Merge inbound to central, a=merge

MozReview-Commit-ID: 96co4Bbby7W
This commit is contained in:
Wes Kocher 2017-03-07 16:40:44 -08:00
commit dac8dc0c7b
284 changed files with 3528 additions and 2599 deletions

View File

@ -11,6 +11,7 @@ module.exports = {
"mozilla/no-import-into-var-and-global": "error",
"mozilla/no-useless-parameters": "error",
"mozilla/no-useless-removeEventListener": "error",
"mozilla/use-default-preference-values": "error",
"mozilla/use-ownerGlobal": "error",
// No (!foo in bar) or (!object instanceof Class)

View File

@ -15,6 +15,10 @@ this.EXPORTED_SYMBOLS = ['AccessFu']; // jshint ignore:line
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/accessibility/Utils.jsm');
if (Utils.MozBuildApp === 'mobile/android') {
Cu.import('resource://gre/modules/Messaging.jsm');
}
const ACCESSFU_DISABLE = 0; // jshint ignore:line
const ACCESSFU_ENABLE = 1;
const ACCESSFU_AUTO = 2;
@ -32,11 +36,9 @@ this.AccessFu = { // jshint ignore:line
attach: function attach(aWindow) {
Utils.init(aWindow);
try {
Services.androidBridge.dispatch('Accessibility:Ready');
Services.obs.addObserver(this, 'Accessibility:Settings', false);
} catch (x) {
// Not on Android
if (Utils.MozBuildApp === 'mobile/android') {
EventDispatcher.instance.dispatch('Accessibility:Ready');
EventDispatcher.instance.registerListener(this, 'Accessibility:Settings');
}
this._activatePref = new PrefCache(
@ -54,7 +56,7 @@ this.AccessFu = { // jshint ignore:line
this._disable();
}
if (Utils.MozBuildApp === 'mobile/android') {
Services.obs.removeObserver(this, 'Accessibility:Settings');
EventDispatcher.instance.unregisterListener(this, 'Accessibility:Settings');
}
delete this._activatePref;
Utils.uninit();
@ -120,16 +122,21 @@ this.AccessFu = { // jshint ignore:line
Output.start();
PointerAdapter.start();
if (Utils.MozBuildApp === 'mobile/android') {
EventDispatcher.instance.registerListener(this, [
'Accessibility:ActivateObject',
'Accessibility:Focus',
'Accessibility:LongPress',
'Accessibility:MoveByGranularity',
'Accessibility:NextObject',
'Accessibility:PreviousObject',
'Accessibility:ScrollBackward',
'Accessibility:ScrollForward',
]);
}
Services.obs.addObserver(this, 'remote-browser-shown', false);
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
Services.obs.addObserver(this, 'Accessibility:NextObject', false);
Services.obs.addObserver(this, 'Accessibility:PreviousObject', false);
Services.obs.addObserver(this, 'Accessibility:Focus', false);
Services.obs.addObserver(this, 'Accessibility:ActivateObject', false);
Services.obs.addObserver(this, 'Accessibility:LongPress', false);
Services.obs.addObserver(this, 'Accessibility:ScrollForward', false);
Services.obs.addObserver(this, 'Accessibility:ScrollBackward', false);
Services.obs.addObserver(this, 'Accessibility:MoveByGranularity', false);
Utils.win.addEventListener('TabOpen', this);
Utils.win.addEventListener('TabClose', this);
Utils.win.addEventListener('TabSelect', this);
@ -169,14 +176,19 @@ this.AccessFu = { // jshint ignore:line
Services.obs.removeObserver(this, 'remote-browser-shown');
Services.obs.removeObserver(this, 'inprocess-browser-shown');
Services.obs.removeObserver(this, 'Accessibility:NextObject');
Services.obs.removeObserver(this, 'Accessibility:PreviousObject');
Services.obs.removeObserver(this, 'Accessibility:Focus');
Services.obs.removeObserver(this, 'Accessibility:ActivateObject');
Services.obs.removeObserver(this, 'Accessibility:LongPress');
Services.obs.removeObserver(this, 'Accessibility:ScrollForward');
Services.obs.removeObserver(this, 'Accessibility:ScrollBackward');
Services.obs.removeObserver(this, 'Accessibility:MoveByGranularity');
if (Utils.MozBuildApp === 'mobile/android') {
EventDispatcher.instance.unregisterListener(this, [
'Accessibility:ActivateObject',
'Accessibility:Focus',
'Accessibility:LongPress',
'Accessibility:MoveByGranularity',
'Accessibility:NextObject',
'Accessibility:PreviousObject',
'Accessibility:ScrollBackward',
'Accessibility:ScrollForward',
]);
}
delete this._quicknavModesPref;
delete this._notifyOutputPref;
@ -288,24 +300,23 @@ this.AccessFu = { // jshint ignore:line
this._loadFrameScript(aMessageManager);
},
observe: function observe(aSubject, aTopic, aData) {
switch (aTopic) {
onEvent: function (event, data, callback) {
switch (event) {
case 'Accessibility:Settings':
this._systemPref = JSON.parse(aData).enabled;
this._systemPref = data.enabled;
this._enableOrDisable();
break;
case 'Accessibility:NextObject':
case 'Accessibility:PreviousObject':
{
let rule = aData ?
aData.substr(0, 1).toUpperCase() + aData.substr(1).toLowerCase() :
case 'Accessibility:PreviousObject': {
let rule = data ?
data.rule.substr(0, 1).toUpperCase() + data.rule.substr(1).toLowerCase() :
'Simple';
let method = aTopic.replace(/Accessibility:(\w+)Object/, 'move$1');
let method = event.replace(/Accessibility:(\w+)Object/, 'move$1');
this.Input.moveCursor(method, rule, 'gesture');
break;
}
case 'Accessibility:ActivateObject':
this.Input.activateCurrent(JSON.parse(aData));
this.Input.activateCurrent(data);
break;
case 'Accessibility:LongPress':
this.Input.sendContextMenuMessage();
@ -317,14 +328,19 @@ this.AccessFu = { // jshint ignore:line
this.Input.androidScroll('backward');
break;
case 'Accessibility:Focus':
this._focused = JSON.parse(aData);
this._focused = data.gainFocus;
if (this._focused) {
this.autoMove({ forcePresent: true, noOpIfOnScreen: true });
}
break;
case 'Accessibility:MoveByGranularity':
this.Input.moveByGranularity(JSON.parse(aData));
this.Input.moveByGranularity(data);
break;
}
},
observe: function observe(aSubject, aTopic, aData) {
switch (aTopic) {
case 'remote-browser-shown':
case 'inprocess-browser-shown':
{

View File

@ -60,6 +60,7 @@ function testObjectOutput(aAccOrElmOrID, aGenerator) {
var context = new PivotContext(accessible);
var output = aGenerator.genForObject(accessible, context);
var outputOrder;
// eslint-disable-next-line mozilla/use-default-preference-values
try {
outputOrder = SpecialPowers.getIntPref(PREF_UTTERANCE_ORDER);
} catch (ex) {

View File

@ -81,31 +81,31 @@ exports['test adding non object or null item'] = function(assert) {
assert.throws(() => {
add(items, 'foo');
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(items, 0);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(items, undefined);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(items, null);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(items, true);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
};
@ -115,31 +115,31 @@ exports['test adding to non object or null item'] = function(assert) {
assert.throws(() => {
add('foo', item);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(0, item);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(undefined, item);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(null, item);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
assert.throws(() => {
add(true, item);
},
/^\w+ is not a non-null object/,
TypeError,
'only non-null object are allowed');
};

View File

@ -46,6 +46,7 @@ var AdbController = {
this.disableAdbTimer.cancel();
} else {
this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
// eslint-disable-next-line mozilla/use-default-preference-values
try {
this.disableAdbTimeoutHours =
Services.prefs.getIntPref("b2g.adb.timeout-hours");

View File

@ -427,12 +427,8 @@ setUpdateTrackingId();
return;
}
// Gaia setting has not been set; set the gaia setting to default.
let prefValue = AppConstants.MOZ_TELEMETRY_ON_BY_DEFAULT;
try {
prefValue = Services.prefs.getBoolPref(geckoPrefName);
} catch (e) {
// Pref not set; use default value.
}
let prefValue = Services.prefs.getBoolPref(geckoPrefName,
AppConstants.MOZ_TELEMETRY_ON_BY_DEFAULT);
let setting = {};
setting[gaiaSettingName] = prefValue;
window.navigator.mozSettings.createLock().set(setting);

View File

@ -256,15 +256,11 @@ var shell = {
// If --start-manifest hasn't been specified, we re-use the latest specified manifest.
// If it's the first launch, we will fallback to b2g.default.start_manifest_url
if (AppConstants.MOZ_GRAPHENE && !startManifestURL) {
try {
startManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url");
} catch(e) {}
startManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url", "");
}
if (!startManifestURL) {
try {
startManifestURL = Services.prefs.getCharPref("b2g.default.start_manifest_url");
} catch(e) {}
startManifestURL = Services.prefs.getCharPref("b2g.default.start_manifest_url", "");
}
if (startManifestURL) {

View File

@ -47,10 +47,7 @@ this.AboutServiceWorkers = {
if (this._enabled) {
return this._enabled;
}
this._enabled = false;
try {
this._enabled = Services.prefs.getBoolPref("dom.serviceWorkers.enabled");
} catch(e) {}
this._enabled = Services.prefs.getBoolPref("dom.serviceWorkers.enabled", false);
return this._enabled;
},

View File

@ -75,6 +75,7 @@ this.Bootstraper = {
return Promise.resolve();
let oldManifestURL;
// eslint-disable-next-line mozilla/use-default-preference-values
try{
oldManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url");
} catch(e) {

View File

@ -113,13 +113,7 @@ DirectoryProvider.prototype = {
// path from the parent, and it is then used to build
// jar:remoteopenfile:// uris.
if (prop == "coreAppsDir") {
let coreAppsDirPref;
try {
coreAppsDirPref = Services.prefs.getCharPref(COREAPPSDIR_PREF);
} catch (e) {
// coreAppsDirPref may not exist if we're on an older version
// of gaia, so just fail silently.
}
let coreAppsDirPref = Services.prefs.getCharPref(COREAPPSDIR_PREF, "");
let appsDir;
// If pref doesn't exist or isn't set, default to old value
if (!coreAppsDirPref || coreAppsDirPref == "") {

View File

@ -94,12 +94,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
// There's no point in setting up an observer to monitor the pref, as b2g prefs
// can only be overwritten when the profie is recreated. So just get the value
// on start-up.
var kPersonaUri = "https://firefoxos.persona.org";
try {
kPersonaUri = Services.prefs.getCharPref("toolkit.identity.uri");
} catch(noSuchPref) {
// stick with the default value
}
var kPersonaUri = Services.prefs.getCharPref("toolkit.identity.uri",
"https://firefoxos.persona.org");
// JS shim that contains the callback functions that
// live within the identity UI provisioning frame.

View File

@ -432,14 +432,9 @@ function migrateToDevEdition(urlParams) {
try {
defaultProfilePath = window.getDefaultProfilePath();
} catch (e) {} // no default profile.
let migrateSyncCreds = false;
if (defaultProfilePath) {
try {
migrateSyncCreds = Services.prefs.getBoolPref("identity.fxaccounts.migrateToDevEdition");
} catch (e) {}
}
if (!migrateSyncCreds) {
if (!defaultProfilePath ||
!Services.prefs.getBoolPref("identity.fxaccounts.migrateToDevEdition", false)) {
return Promise.resolve(false);
}

View File

@ -157,10 +157,7 @@ var gFxAccounts = {
// Note that updateUI() returns a Promise that's only used by tests.
updateUI() {
let profileInfoEnabled = false;
try {
profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled");
} catch (e) { }
let profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled", false);
this.panelUIFooter.hidden = false;

View File

@ -297,10 +297,7 @@ var gSyncUI = {
*/
maybeMoveSyncedTabsButton() {
const prefName = "browser.migrated-sync-button";
let migrated = false;
try {
migrated = Services.prefs.getBoolPref(prefName);
} catch (_) {}
let migrated = Services.prefs.getBoolPref(prefName, false);
if (migrated) {
return;
}

View File

@ -2793,15 +2793,10 @@ var gMenuButtonUpdateBadge = {
cancelObserverRegistered: false,
init() {
try {
this.enabled = Services.prefs.getBoolPref("app.update.badge");
} catch (e) {}
this.enabled = Services.prefs.getBoolPref("app.update.badge", false);
if (this.enabled) {
try {
this.badgeWaitTime = Services.prefs.getIntPref("app.update.badgeWaitTime");
} catch (e) {
this.badgeWaitTime = 345600; // 4 days
}
this.badgeWaitTime = Services.prefs.getIntPref("app.update.badgeWaitTime",
345600); // 4 days
Services.obs.addObserver(this, "update-staged", false);
Services.obs.addObserver(this, "update-downloaded", false);
}

View File

@ -6,7 +6,6 @@
hidden="true"
orient="vertical"
noautofocus="true"
followanchor="false"
role="alert"/>
<popupnotification id="webRTC-shareDevices-notification" hidden="true">

View File

@ -302,12 +302,7 @@ var RemoteTabViewer = {
_refetchTabs(force) {
if (!force) {
// Don't bother refetching tabs if we already did so recently
let lastFetch = 0;
try {
lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch");
} catch (e) {
/* Just use the default value of 0 */
}
let lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch", 0);
let now = Math.floor(Date.now() / 1000);
if (now - lastFetch < 30) {

View File

@ -4470,11 +4470,7 @@
return true;
if (this._logInit)
return this._shouldLog;
let result = false;
try {
result = Services.prefs.getBoolPref("browser.tabs.remote.logSwitchTiming");
} catch (ex) {
}
let result = Services.prefs.getBoolPref("browser.tabs.remote.logSwitchTiming", false);
this._shouldLog = result;
this._logInit = true;
return this._shouldLog;
@ -5647,11 +5643,7 @@
window.addEventListener("resize", this);
window.addEventListener("load", this);
try {
this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled");
} catch (ex) {
this._tabAnimationLoggingEnabled = false;
}
this._tabAnimationLoggingEnabled = Services.prefs.getBoolPref("browser.tabs.animationLogging.enabled", false);
this._browserNewtabpageEnabled = Services.prefs.getBoolPref("browser.newtabpage.enabled");
Services.prefs.addObserver("privacy.userContext", this, false);
this.observe(null, "nsPref:changed", "privacy.userContext.enabled");

View File

@ -2,11 +2,7 @@ var offlineByDefault = {
defaultValue: false,
prefBranch: SpecialPowers.Cc["@mozilla.org/preferences-service;1"].getService(SpecialPowers.Ci.nsIPrefBranch),
set(allow) {
try {
this.defaultValue = this.prefBranch.getBoolPref("offline-apps.allow_by_default");
} catch (e) {
this.defaultValue = false
}
this.defaultValue = this.prefBranch.getBoolPref("offline-apps.allow_by_default", false);
this.prefBranch.setBoolPref("offline-apps.allow_by_default", allow);
},
reset() {

View File

@ -158,10 +158,7 @@ var gUIStateBeforeReset = {
XPCOMUtils.defineLazyGetter(this, "log", () => {
let scope = {};
Cu.import("resource://gre/modules/Console.jsm", scope);
let debug;
try {
debug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
} catch (ex) {}
let debug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false);
let consoleOptions = {
maxLogLevel: debug ? "all" : "log",
prefix: "CustomizableUI",
@ -1926,16 +1923,10 @@ var CustomizableUIInternal = {
// state immediately when a browser window opens, which is important for
// other consumers of this API.
loadSavedState() {
let state = null;
try {
state = Services.prefs.getCharPref(kPrefCustomizationState);
} catch (e) {
log.debug("No saved state found");
// This will fail if nothing has been customized, so silently fall back to
// the defaults.
}
let state = Services.prefs.getCharPref(kPrefCustomizationState, "");
if (!state) {
log.debug("No saved state found");
// Nothing has been customized, so silently fall back to the defaults.
return;
}
try {
@ -2220,10 +2211,7 @@ var CustomizableUIInternal = {
this.notifyListeners("onWidgetAdded", widget.id, widget.currentArea,
widget.currentPosition);
} else if (widgetMightNeedAutoAdding) {
let autoAdd = true;
try {
autoAdd = Services.prefs.getBoolPref(kPrefCustomizationAutoAdd);
} catch (e) {}
let autoAdd = Services.prefs.getBoolPref(kPrefCustomizationAutoAdd, true);
// If the widget doesn't have an existing placement, and it hasn't been
// seen before, then add it to its default area so it can be used.

View File

@ -46,10 +46,7 @@ const kWidePanelItemClass = "panel-wide-item";
XPCOMUtils.defineLazyGetter(this, "log", () => {
let scope = {};
Cu.import("resource://gre/modules/Console.jsm", scope);
let debug;
try {
debug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
} catch (ex) {}
let debug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false);
let consoleOptions = {
maxLogLevel: debug ? "all" : "log",
prefix: "CustomizableWidgets",

View File

@ -42,9 +42,7 @@ let gDebug;
XPCOMUtils.defineLazyGetter(this, "log", () => {
let scope = {};
Cu.import("resource://gre/modules/Console.jsm", scope);
try {
gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
} catch (ex) {}
gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug, false);
let consoleOptions = {
maxLogLevel: gDebug ? "all" : "log",
prefix: "CustomizeMode",
@ -624,11 +622,8 @@ CustomizeMode.prototype = {
},
maybeShowTip(aAnchor) {
let shown = false;
const kShownPref = "browser.customizemode.tip0.shown";
try {
shown = Services.prefs.getBoolPref(kShownPref);
} catch (ex) {}
let shown = Services.prefs.getBoolPref(kShownPref, false);
if (shown)
return;
@ -1502,10 +1497,7 @@ CustomizeMode.prototype = {
if (!AppConstants.CAN_DRAW_IN_TITLEBAR) {
return;
}
let drawInTitlebar = true;
try {
drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref);
} catch (ex) { }
let drawInTitlebar = Services.prefs.getBoolPref(kDrawInTitlebarPref, true);
let button = this.document.getElementById("customization-titlebar-visibility-button");
// Drawing in the titlebar means 'hiding' the titlebar:
if (drawInTitlebar) {

View File

@ -81,10 +81,7 @@ function test() {
continue;
}
let pref = "browser.toolbarbuttons.introduced." + placements[i];
let introduced = false;
try {
introduced = Services.prefs.getBoolPref(pref);
} catch (ex) {}
let introduced = Services.prefs.getBoolPref(pref, false);
if (!introduced) {
i++;
continue;

View File

@ -22,10 +22,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
this.DistributionCustomizer = function DistributionCustomizer() {
// For parallel xpcshell testing purposes allow loading the distribution.ini
// file from the profile folder through an hidden pref.
let loadFromProfile = false;
try {
loadFromProfile = Services.prefs.getBoolPref("distribution.testing.loadFromProfile");
} catch (ex) {}
let loadFromProfile = Services.prefs.getBoolPref("distribution.testing.loadFromProfile", false);
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
try {
@ -60,12 +57,7 @@ DistributionCustomizer.prototype = {
},
get _locale() {
let locale;
try {
locale = this._prefs.getCharPref("general.useragent.locale");
} catch (e) {
locale = "en-US";
}
let locale = this._prefs.getCharPref("general.useragent.locale", "en-US");
this.__defineGetter__("_locale", () => locale);
return this._locale;
},
@ -289,10 +281,7 @@ DistributionCustomizer.prototype = {
this._ini.getString("Global", "id") + ".bookmarksProcessed";
}
let bmProcessed = false;
try {
bmProcessed = this._prefs.getBoolPref(bmProcessedPref);
} catch (e) {}
let bmProcessed = this._prefs.getBoolPref(bmProcessedPref, false);
if (!bmProcessed) {
if (sections["BookmarksMenu"])

View File

@ -19,11 +19,7 @@ function LOG(str) {
let prefB = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
let shouldLog = false;
try {
shouldLog = prefB.getBoolPref("feeds.log");
} catch (ex) {
}
let shouldLog = prefB.getBoolPref("feeds.log", false);
if (shouldLog)
dump("*** Feeds: " + str + "\n");
@ -697,10 +693,7 @@ FeedWriter.prototype = {
_setSelectedHandler(feedType) {
let prefs = Services.prefs;
let handler = "bookmarks";
try {
handler = prefs.getCharPref(getPrefReaderForType(feedType));
} catch (ex) { }
let handler = prefs.getCharPref(getPrefReaderForType(feedType), "bookmarks");
switch (handler) {
case "web": {
@ -835,10 +828,7 @@ FeedWriter.prototype = {
.addEventListener("click", this);
// first-run ui
let showFirstRunUI = true;
try {
showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI);
} catch (ex) { }
let showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI, true);
if (showFirstRunUI) {
let textfeedinfo1, textfeedinfo2;
switch (feedType) {

View File

@ -183,12 +183,9 @@ const Utils = {
// check if it is in the black list
let pb = Services.prefs;
let allowed;
try {
allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
} catch (e) {
allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default");
}
let allowed =
pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol,
pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "-default"));
if (!allowed) {
throw this.getSecurityError(
`Not allowed to register a protocol handler for ${aProtocol}`,

View File

@ -98,20 +98,14 @@ const OVERRIDE_NEW_BUILD_ID = 3;
* OVERRIDE_NONE otherwise.
*/
function needHomepageOverride(prefb) {
var savedmstone = null;
try {
savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone");
} catch (e) {}
var savedmstone = prefb.getCharPref("browser.startup.homepage_override.mstone", "");
if (savedmstone == "ignore")
return OVERRIDE_NONE;
var mstone = Services.appinfo.platformVersion;
var savedBuildID = null;
try {
savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID");
} catch (e) {}
var savedBuildID = prefb.getCharPref("browser.startup.homepage_override.buildID", "");
var buildID = Services.appinfo.platformBuildID;
@ -484,10 +478,7 @@ nsBrowserContentHandler.prototype = {
// URL if we do end up showing an overridePage. This makes it possible
// to have the overridePage's content vary depending on the version we're
// upgrading from.
let old_mstone = "unknown";
try {
old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
} catch (ex) {}
let old_mstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone", "unknown");
override = needHomepageOverride(prefb);
if (override != OVERRIDE_NONE) {
switch (override) {

View File

@ -935,10 +935,7 @@ BrowserGlue.prototype = {
// Offer to reset a user's profile if it hasn't been used for 60 days.
const OFFER_PROFILE_RESET_INTERVAL_MS = 60 * 24 * 60 * 60 * 1000;
let lastUse = Services.appinfo.replacedLockTime;
let disableResetPrompt = false;
try {
disableResetPrompt = Services.prefs.getBoolPref("browser.disableResetPrompt");
} catch (e) {}
let disableResetPrompt = Services.prefs.getBoolPref("browser.disableResetPrompt", false);
if (!disableResetPrompt && lastUse &&
Date.now() - lastUse >= OFFER_PROFILE_RESET_INTERVAL_MS) {
@ -1456,10 +1453,7 @@ BrowserGlue.prototype = {
} catch (ex) {}
// Support legacy bookmarks.html format for apps that depend on that format.
let autoExportHTML = false;
try {
autoExportHTML = Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML");
} catch (ex) {} // Do not export.
let autoExportHTML = Services.prefs.getBoolPref("browser.bookmarks.autoExportHTML", false); // Do not export.
if (autoExportHTML) {
// Sqlite.jsm and Places shutdown happen at profile-before-change, thus,
// to be on the safe side, this should run earlier.
@ -1526,10 +1520,7 @@ BrowserGlue.prototype = {
// An import operation is about to run.
// Don't try to recreate smart bookmarks if autoExportHTML is true or
// smart bookmarks are disabled.
let smartBookmarksVersion = 0;
try {
smartBookmarksVersion = Services.prefs.getIntPref("browser.places.smartBookmarksVersion");
} catch (ex) {}
let smartBookmarksVersion = Services.prefs.getIntPref("browser.places.smartBookmarksVersion", 0);
if (!autoExportHTML && smartBookmarksVersion != -1)
Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0);
@ -1876,10 +1867,7 @@ BrowserGlue.prototype = {
// Refactor urlbar suggestion preferences to make it extendable and
// allow new suggestion types (e.g: search suggestions).
let types = ["history", "bookmark", "openpage"];
let defaultBehavior = 0;
try {
defaultBehavior = Services.prefs.getIntPref("browser.urlbar.default.behavior");
} catch (ex) {}
let defaultBehavior = Services.prefs.getIntPref("browser.urlbar.default.behavior", 0);
try {
let autocompleteEnabled = Services.prefs.getBoolPref("browser.urlbar.autocomplete.enabled");
if (!autocompleteEnabled) {
@ -2018,10 +2006,7 @@ BrowserGlue.prototype = {
}
if (currentUIVersion < 43) {
let currentTheme = null;
try {
currentTheme = Services.prefs.getCharPref("lightweightThemes.selectedThemeID");
} catch (e) {}
let currentTheme = Services.prefs.getCharPref("lightweightThemes.selectedThemeID", "");
if (currentTheme == "firefox-devedition@mozilla.org") {
let newTheme = Services.prefs.getCharPref("devtools.theme") == "dark" ?
"firefox-compact-dark@mozilla.org" : "firefox-compact-light@mozilla.org";
@ -2099,10 +2084,7 @@ BrowserGlue.prototype = {
const MAX_RESULTS = 10;
// Get current smart bookmarks version. If not set, create them.
let smartBookmarksCurrentVersion = 0;
try {
smartBookmarksCurrentVersion = Services.prefs.getIntPref(SMART_BOOKMARKS_PREF);
} catch (ex) {}
let smartBookmarksCurrentVersion = Services.prefs.getIntPref(SMART_BOOKMARKS_PREF, 0);
// If version is current, or smart bookmarks are disabled, bail out.
if (smartBookmarksCurrentVersion == -1 ||

View File

@ -74,22 +74,14 @@ var gSyncPane = {
},
_showLoadPage(xps) {
let username;
try {
username = Services.prefs.getCharPref("services.sync.username");
} catch (e) {}
let username = Services.prefs.getCharPref("services.sync.username", "");
if (!username) {
this.page = FXA_PAGE_LOGGED_OUT;
return;
}
// Use cached values while we wait for the up-to-date values
let cachedComputerName;
try {
cachedComputerName = Services.prefs.getCharPref("services.sync.client.name");
} catch (e) {
cachedComputerName = "";
}
let cachedComputerName = Services.prefs.getCharPref("services.sync.client.name", "");
document.getElementById("fxaEmailAddress1").textContent = username;
this._populateComputerName(cachedComputerName);
this.page = FXA_PAGE_LOGGED_IN;
@ -251,10 +243,7 @@ var gSyncPane = {
fxaEmailAddress1Label.hidden = false;
displayNameLabel.hidden = true;
let profileInfoEnabled;
try {
profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled");
} catch (ex) {}
let profileInfoEnabled = Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled", false);
// determine the fxa status...
this._showLoadPage(service);

View File

@ -26,7 +26,6 @@ tags = trackingprotection
[browser_privatebrowsing_cache.js]
[browser_privatebrowsing_certexceptionsui.js]
[browser_privatebrowsing_concurrent.js]
skip-if = e10s # Bug 1315042
[browser_privatebrowsing_context_and_chromeFlags.js]
[browser_privatebrowsing_crh.js]
[browser_privatebrowsing_downloadLastDir.js]

View File

@ -62,7 +62,7 @@ add_task(function* test() {
private_browser = private_window.getBrowser().selectedBrowser;
private_browser.loadURI(prefix + "?action=get&name=test2");
yield BrowserTestUtils.browserLoaded(private_browser);
yield BrowserTestUtils.browserLoaded(private_browser, false, prefix + "?action=get&name=test2");
elts = yield getElts(private_browser);
isnot(elts[0], "value2", "public window shouldn't see cleared private storage");
is(elts[1], "1", "public window should only see public items");

View File

@ -1795,10 +1795,8 @@ this.UITour = {
// Identifier of the partner repack, as stored in preference "distribution.id"
// and included in Firefox and other update pings. Note this is not the same as
// Services.appinfo.distributionID (value of MOZ_DISTRIBUTION_ID is set at build time).
let distribution = "default";
try {
distribution = Services.prefs.getDefaultBranch("distribution.").getCharPref("id");
} catch (e) {}
let distribution =
Services.prefs.getDefaultBranch("distribution.").getCharPref("id", "default");
appinfo["distribution"] = distribution;
let isDefaultBrowser = null;

View File

@ -600,10 +600,7 @@ this.BrowserUITelemetry = {
getSyncState() {
let result = {};
for (let sub of ["desktop", "mobile"]) {
let count = 0;
try {
count = Services.prefs.getIntPref("services.sync.clients.devices." + sub);
} catch (ex) {}
let count = Services.prefs.getIntPref("services.sync.clients.devices." + sub, 0);
result[sub] = count;
}
return result;

View File

@ -188,10 +188,7 @@ var DirectoryLinksProvider = {
* @return the selected locale or "en-US" if none is selected
*/
get locale() {
let matchOS;
try {
matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE);
} catch (e) {}
let matchOS = Services.prefs.getBoolPref(PREF_MATCH_OS_LOCALE, false);
if (matchOS) {
return Cc["@mozilla.org/intl/ospreferences;1"].

View File

@ -211,16 +211,11 @@ var ActiveProviders = {
};
function migrateSettings() {
let activeProviders, enabled;
try {
activeProviders = Services.prefs.getCharPref("social.activeProviders");
} catch (e) {
// not set, we'll check if we need to migrate older prefs
}
let enabled;
if (Services.prefs.prefHasUserValue("social.enabled")) {
enabled = Services.prefs.getBoolPref("social.enabled");
}
if (activeProviders) {
if (Services.prefs.getCharPref("social.activeProviders", "")) {
// migration from fx21 to fx22 or later
// ensure any *builtin* provider in activeproviders is in user level prefs
for (let origin in ActiveProviders._providers) {
@ -284,10 +279,7 @@ function migrateSettings() {
}
// primary migration from pre-fx21
let active;
try {
active = Services.prefs.getBoolPref("social.active");
} catch (e) {}
let active = Services.prefs.getBoolPref("social.active", false);
if (!active)
return;

View File

@ -193,12 +193,7 @@ DevTools.prototype = {
return tool;
}
let enabled;
try {
enabled = Services.prefs.getBoolPref(tool.visibilityswitch);
} catch (e) {
enabled = true;
}
let enabled = Services.prefs.getBoolPref(tool.visibilityswitch, true);
return enabled ? tool : null;
},

View File

@ -100,17 +100,13 @@ function openToolbox({ form, chrome, isTabActor }) {
};
TargetFactory.forRemoteTab(options).then(target => {
let frame = document.getElementById("toolbox-iframe");
let selectedTool = "jsdebugger";
try {
// Remember the last panel that was used inside of this profile.
selectedTool = Services.prefs.getCharPref("devtools.toolbox.selectedTool");
} catch(e) {}
try {
// But if we are testing, then it should always open the debugger panel.
selectedTool = Services.prefs.getCharPref("devtools.browsertoolbox.panel");
} catch(e) {}
// Remember the last panel that was used inside of this profile.
// But if we are testing, then it should always open the debugger panel.
let selectedTool =
Services.prefs.getCharPref("devtools.browsertoolbox.panel",
Services.prefs.getCharPref("devtools.toolbox.selectedTool",
"jsdebugger"));
let options = { customIframe: frame };
gDevTools.showToolbox(target,

View File

@ -1226,12 +1226,7 @@ Toolbox.prototype = {
visibilityswitch
} = button;
let visible = true;
try {
visible = Services.prefs.getBoolPref(visibilityswitch);
} catch (ex) {
// Do nothing.
}
let visible = Services.prefs.getBoolPref(visibilityswitch, true);
if (isTargetSupported) {
return visible && isTargetSupported(this.target);

View File

@ -71,11 +71,8 @@ function MarkupView(inspector, frame, controllerWindow) {
this.doc = this._frame.contentDocument;
this._elt = this.doc.querySelector("#root");
try {
this.maxChildren = Services.prefs.getIntPref("devtools.markup.pagesize");
} catch (ex) {
this.maxChildren = DEFAULT_MAX_CHILDREN;
}
this.maxChildren = Services.prefs.getIntPref("devtools.markup.pagesize",
DEFAULT_MAX_CHILDREN);
this.collapseAttributes =
Services.prefs.getBoolPref(ATTR_COLLAPSE_ENABLED_PREF);

View File

@ -21,19 +21,8 @@ var systemAppOrigin = (function () {
return systemOrigin;
})();
var threshold = 25;
try {
threshold = Services.prefs.getIntPref("ui.dragThresholdX");
} catch (e) {
// Fall back to default value
}
var delay = 500;
try {
delay = Services.prefs.getIntPref("ui.click_hold_context_menus.delay");
} catch (e) {
// Fall back to default value
}
var threshold = Services.prefs.getIntPref("ui.dragThresholdX", 25);
var delay = Services.prefs.getIntPref("ui.click_hold_context_menus.delay", 500);
function SimulatorCore(simulatorTarget) {
this.simulatorTarget = simulatorTarget;

View File

@ -10385,10 +10385,13 @@ nsDocShell::InternalLoad(nsIURI* aURI,
* call OnNewURI() so that, this traversal will be
* recorded in session and global history.
*/
nsCOMPtr<nsIPrincipal> triggeringPrincipal, principalToInherit;
nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit;
if (mOSHE) {
mOSHE->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
mOSHE->GetPrincipalToInherit(getter_AddRefs(principalToInherit));
mOSHE->GetTriggeringPrincipal(getter_AddRefs(newURITriggeringPrincipal));
mOSHE->GetPrincipalToInherit(getter_AddRefs(newURIPrincipalToInherit));
} else {
newURITriggeringPrincipal = aTriggeringPrincipal;
newURIPrincipalToInherit = doc->NodePrincipal();
}
// Pass true for aCloneSHChildren, since we're not
// changing documents here, so all of our subframes are
@ -10398,7 +10401,7 @@ nsDocShell::InternalLoad(nsIURI* aURI,
// flag on firing onLocationChange(...).
// Anyway, aCloneSHChildren param is simply reflecting
// doShortCircuitedLoad in this scope.
OnNewURI(aURI, nullptr, triggeringPrincipal, principalToInherit,
OnNewURI(aURI, nullptr, newURITriggeringPrincipal, newURIPrincipalToInherit,
mLoadType, true, true, true);
nsCOMPtr<nsIInputStream> postData;

View File

@ -0,0 +1,6 @@
<html>
<head> <meta charset="utf-8"> </head>
<body>
just a dummy html file
</body>
</html>

View File

@ -11,6 +11,7 @@ support-files =
bug668513_redirect.html
bug668513_redirect.html^headers^
bug691547_frame.html
dummy_page.html
file_anchor_scroll_after_document_open.html
file_bug385434_1.html
file_bug385434_2.html
@ -92,3 +93,4 @@ skip-if = toolkit == 'android' # bug 784321
support-files = file_framedhistoryframes.html
[test_pushState_after_document_open.html]
[test_windowedhistoryframes.html]
[test_triggeringprincipal_location_seturi.html]

View File

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
const SAME_ORIGIN_URI = "http://mochi.test:8888/tests/docshell/test/dummy_page.html";
const CROSS_ORIGIN_URI = "http://example.com/tests/docshell/test/dummy_page.html";
const NUMBER_OF_TESTS = 3;
let testCounter = 0;
function checkFinish() {
testCounter++;
if (testCounter < NUMBER_OF_TESTS) {
return;
}
SimpleTest.finish();
}
// ---- test 1 ----
let myFrame1 = document.createElement("iframe");
myFrame1.src = SAME_ORIGIN_URI;
myFrame1.addEventListener("load", checkLoadFrame1);
document.documentElement.appendChild(myFrame1);
function checkLoadFrame1() {
myFrame1.removeEventListener('load', checkLoadFrame1, false);
// window.location.href is no longer cross-origin accessible in gecko.
is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, SAME_ORIGIN_URI,
"initial same origin dummy loaded into frame1");
SpecialPowers.wrap(myFrame1.contentWindow).location.hash = "#bar";
is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, SAME_ORIGIN_URI + "#bar",
"initial same origin dummy#bar loaded into iframe1");
myFrame1.addEventListener("load", checkNavFrame1);
myFrame1.src = CROSS_ORIGIN_URI;
}
function checkNavFrame1() {
myFrame1.removeEventListener('load', checkNavFrame1, false);
is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, CROSS_ORIGIN_URI,
"cross origin dummy loaded into frame1");
myFrame1.addEventListener("load", checkBackNavFrame1);
myFrame1.src = SAME_ORIGIN_URI + "#bar";
}
function checkBackNavFrame1() {
myFrame1.removeEventListener('load', checkBackNavFrame1, false);
is(SpecialPowers.wrap(myFrame1.contentWindow).location.href, SAME_ORIGIN_URI + "#bar",
"navagiating back to same origin dummy for frame1");
checkFinish();
}
// ---- test 2 ----
let myFrame2 = document.createElement("iframe");
myFrame2.src = "about:blank";
myFrame2.addEventListener("load", checkLoadFrame2);
document.documentElement.appendChild(myFrame2);
function checkLoadFrame2() {
myFrame2.removeEventListener('load', checkLoadFrame2, false);
is(SpecialPowers.wrap(myFrame2.contentWindow).location.href, "about:blank",
"initial about:blank frame loaded");
myFrame2.contentWindow.location.hash = "#foo";
is(SpecialPowers.wrap(myFrame2.contentWindow).location.href, "about:blank#foo",
"about:blank#foo frame loaded");
myFrame2.addEventListener('load', checkHistoryFrame2);
myFrame2.src = "about:blank";
}
function checkHistoryFrame2() {
myFrame2.removeEventListener('load', checkHistoryFrame2, false);
is(SpecialPowers.wrap(myFrame2.contentWindow).location.href, "about:blank",
"about:blank frame loaded again");
checkFinish();
}
// ---- test 3 ----
let myFrame3 = document.createElement("frame");
document.documentElement.appendChild(myFrame3);
myFrame3.contentWindow.location.hash = "#foo";
is(myFrame3.contentWindow.location.href, "about:blank#foo",
"created history entry with about:blank#foo");
checkFinish();
</script>
</body>
</html>

View File

@ -12,20 +12,10 @@ const PREF_BRANCH = BASE_PREF + ".";
// Utilities:
function getMaxContentParents(processType) {
let maxContentParents = -1;
try {
maxContentParents = Services.prefs.getIntPref(PREF_BRANCH + processType);
} catch (e) {
// Pref probably didn't exist, get the default number of processes.
try {
maxContentParents = Services.prefs.getIntPref(BASE_PREF);
} catch (e) {
// No prefs? That's odd, use only one process.
maxContentParents = 1;
}
}
return maxContentParents;
// If the pref doesn't exist, get the default number of processes.
// If there's no pref, use only one process.
return Services.prefs.getIntPref(PREF_BRANCH + processType,
Services.prefs.getIntPref(BASE_PREF, 1));
}
// Fills up aProcesses until max and then selects randomly from the available
@ -58,5 +48,36 @@ RandomSelector.prototype = {
},
};
var components = [RandomSelector];
// Fills up aProcesses until max and then selects one from the available
// ones that host the least number of tabs.
function MinTabSelector() {
}
MinTabSelector.prototype = {
classID: Components.ID("{2dc08eaf-6eef-4394-b1df-a3a927c1290b}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentProcessProvider]),
provideProcess(aType, aOpener, aProcesses, aCount) {
let maxContentParents = getMaxContentParents(aType);
if (aCount < maxContentParents) {
return Ci.nsIContentProcessProvider.NEW_PROCESS;
}
let min = Number.MAX_VALUE;
let candidate = Ci.nsIContentProcessProvider.NEW_PROCESS;
for (let i = 0; i < maxContentParents; i++) {
let process = aProcesses[i];
let tabCount = process.tabCount;
if (process.opener === aOpener && tabCount < min) {
min = tabCount;
candidate = i;
}
}
return candidate;
},
};
var components = [RandomSelector, MinTabSelector];
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View File

@ -1,2 +1,3 @@
component {c616fcfd-9737-41f1-aa74-cee72a38f91b} ProcessSelector.js
contract @mozilla.org/ipc/processselector;1 {c616fcfd-9737-41f1-aa74-cee72a38f91b}
component {2dc08eaf-6eef-4394-b1df-a3a927c1290b} ProcessSelector.js
contract @mozilla.org/ipc/processselector;1 {2dc08eaf-6eef-4394-b1df-a3a927c1290b}

View File

@ -2408,8 +2408,13 @@ nsGlobalWindow::WouldReuseInnerWindow(nsIDocument* aNewDocument)
return false;
}
NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
"How'd this happen?");
#ifdef DEBUG
{
nsCOMPtr<nsIURI> uri;
mDoc->GetDocumentURI()->CloneIgnoringRef(getter_AddRefs(uri));
NS_ASSERTION(NS_IsAboutBlank(uri), "How'd this happen?");
}
#endif
// Great, we're the original document, check for one of the other
// conditions.

View File

@ -964,11 +964,7 @@ BrowserElementChild.prototype = {
self._takeScreenshot(maxWidth, maxHeight, mimeType, domRequestID);
};
let maxDelayMS = 2000;
try {
maxDelayMS = Services.prefs.getIntPref('dom.browserElement.maxScreenshotDelayMS');
}
catch(e) {}
let maxDelayMS = Services.prefs.getIntPref('dom.browserElement.maxScreenshotDelayMS', 2000);
// Try to wait for the event loop to go idle before we take the screenshot,
// but once we've waited maxDelayMS milliseconds, go ahead and take it
@ -1649,10 +1645,7 @@ BrowserElementChild.prototype = {
// certerror? If yes, maybe we should add a property to the
// event to to indicate whether there is a custom page. That would
// let the embedder have more control over the desired behavior.
let errorPage = null;
try {
errorPage = Services.prefs.getCharPref(CERTIFICATE_ERROR_PAGE_PREF);
} catch (e) {}
let errorPage = Services.prefs.getCharPref(CERTIFICATE_ERROR_PAGE_PREF, "");
if (errorPage == 'certerror') {
sendAsyncMsg('error', { type: 'certerror' });

View File

@ -31,14 +31,8 @@
Cu.import("resource://gre/modules/Services.jsm");
for (var stage of [ "install", "startup", "shutdown", "uninstall" ]) {
for (var symbol of [ "IDBKeyRange", "indexedDB" ]) {
let pref;
try {
pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage +
"." + symbol);
}
catch(ex) {
pref = false;
}
let pref = Services.prefs.getBoolPref("indexeddbtest.bootstrap." + stage +
"." + symbol, false);
ok(pref, "Symbol '" + symbol + "' present during '" + stage + "'");
}
}

View File

@ -27,6 +27,11 @@ interface nsIContentProcessInfo : nsISupports
*/
readonly attribute nsIContentProcessInfo opener;
/**
* Number of opened tabs living in this content process.
*/
readonly attribute int32_t tabCount;
/**
* The process manager for this ContentParent (so a process message manager
* as opposed to a frame message manager.

View File

@ -603,10 +603,6 @@ ContentChild::Init(MessageLoop* aIOLoop,
SetProcessName(NS_LITERAL_STRING("Web Content"), true);
nsTArray<mozilla::dom::GfxInfoFeatureStatus> featureStatus;
SendGetGfxInfoFeatureStatus(&featureStatus);
GfxInfoBase::SetFeatureStatus(featureStatus);
return true;
}
@ -1033,6 +1029,8 @@ ContentChild::InitXPCOM(const XPCOMInitData& aXPCOMInit,
// This will register cross-process observer.
mozilla::dom::time::InitializeDateCacheCleaner();
GfxInfoBase::SetFeatureStatus(aXPCOMInit.gfxFeatureStatus());
}
mozilla::ipc::IPCResult

View File

@ -505,6 +505,19 @@ ScriptableCPInfo::GetOpener(nsIContentProcessInfo** aInfo)
return NS_OK;
}
NS_IMETHODIMP
ScriptableCPInfo::GetTabCount(int32_t* aTabCount)
{
if (!mContentParent) {
return NS_ERROR_NOT_INITIALIZED;
}
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
*aTabCount = cpm->GetTabParentCountByProcessId(mContentParent->ChildID());
return NS_OK;
}
NS_IMETHODIMP
ScriptableCPInfo::GetMessageManager(nsIMessageSender** aMessenger)
{
@ -757,23 +770,28 @@ ContentParent::ReleaseCachedProcesses()
}
/*static*/ already_AddRefed<ContentParent>
ContentParent::RandomSelect(const nsTArray<ContentParent*>& aContentParents,
ContentParent::MinTabSelect(const nsTArray<ContentParent*>& aContentParents,
ContentParent* aOpener, int32_t aMaxContentParents)
{
uint32_t maxSelectable = std::min(static_cast<uint32_t>(aContentParents.Length()),
static_cast<uint32_t>(aMaxContentParents));
uint32_t startIdx = rand() % maxSelectable;
uint32_t currIdx = startIdx;
do {
RefPtr<ContentParent> p = aContentParents[currIdx];
uint32_t min = INT_MAX;
RefPtr<ContentParent> candidate;
ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
for (uint32_t i = 0; i < maxSelectable; i++) {
ContentParent* p = aContentParents[i];
NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in sBrowserContentParents?");
if (p->mOpener == aOpener) {
return p.forget();
uint32_t tabCount = cpm->GetTabParentCountByProcessId(p->ChildID());
if (tabCount < min) {
candidate = p;
min = tabCount;
}
}
currIdx = (currIdx + 1) % maxSelectable;
} while (currIdx != startIdx);
}
return nullptr;
return candidate.forget();
}
/*static*/ already_AddRefed<ContentParent>
@ -816,7 +834,7 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
NS_WARNING("nsIContentProcessProvider failed to return a process");
RefPtr<ContentParent> random;
if (contentParents.Length() >= maxContentParents &&
(random = RandomSelect(contentParents, aOpener, maxContentParents))) {
(random = MinTabSelect(contentParents, aOpener, maxContentParents))) {
return random.forget();
}
}
@ -2174,6 +2192,20 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
SerializeURI(nullptr, xpcomInit.userContentSheetURL());
}
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
if (gfxInfo) {
for (int32_t i = 1; i <= nsIGfxInfo::FEATURE_MAX_VALUE; ++i) {
int32_t status = 0;
nsAutoCString failureId;
gfxInfo->GetFeatureStatus(i, failureId, &status);
dom::GfxInfoFeatureStatus gfxFeatureStatus;
gfxFeatureStatus.feature() = i;
gfxFeatureStatus.status() = status;
gfxFeatureStatus.failureId() = failureId;
xpcomInit.gfxFeatureStatus().AppendElement(gfxFeatureStatus);
}
}
Unused << SendSetXPCOMProcessAttributes(xpcomInit, initialData, lnfCache);
if (aSendRegisteredChrome) {
@ -4017,25 +4049,6 @@ ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvGetGfxInfoFeatureStatus(nsTArray<mozilla::dom::GfxInfoFeatureStatus>* aFS)
{
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
if (!gfxInfo) {
return IPC_OK();
}
for (int32_t i = 1; i <= nsIGfxInfo::FEATURE_MAX_VALUE; ++i) {
int32_t status = 0;
nsAutoCString failureId;
gfxInfo->GetFeatureStatus(i, failureId, &status);
mozilla::dom::GfxInfoFeatureStatus fs(i, status, failureId);
aFS->AppendElement(Move(fs));
}
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvAddIdleObserver(const uint64_t& aObserver,
const uint32_t& aIdleTimeInS)

View File

@ -159,7 +159,7 @@ public:
* Returns null if non available.
*/
static already_AddRefed<ContentParent>
RandomSelect(const nsTArray<ContentParent*>& aContentParents,
MinTabSelect(const nsTArray<ContentParent*>& aContentParents,
ContentParent* aOpener,
int32_t maxContentParents);
@ -469,8 +469,6 @@ public:
const bool& aIsAudio,
const bool& aIsVideo) override;
virtual mozilla::ipc::IPCResult RecvGetGfxInfoFeatureStatus(nsTArray<mozilla::dom::GfxInfoFeatureStatus>* aFS) override;
bool CycleCollectWithLogs(bool aDumpAllTraces,
nsICycleCollectorLogSink* aSink,
nsIDumpGCAndCCLogsCallback* aCallback);

View File

@ -354,5 +354,18 @@ ContentProcessManager::GetTabParentsByProcessId(const ContentParentId& aChildCpI
return Move(tabIdList);
}
uint32_t
ContentProcessManager::GetTabParentCountByProcessId(const ContentParentId& aChildCpId)
{
MOZ_ASSERT(NS_IsMainThread());
auto iter = mContentParentMap.find(aChildCpId);
if (NS_WARN_IF(iter == mContentParentMap.end())) {
return 0;
}
return iter->second.mRemoteFrames.size();
}
} // namespace dom
} // namespace mozilla

View File

@ -117,6 +117,13 @@ public:
nsTArray<TabId>
GetTabParentsByProcessId(const ContentParentId& aChildCpId);
/**
* Get the number of TabParents managed by the givent content process.
* Return 0 when TabParent couldn't be found via aChildCpId.
*/
uint32_t
GetTabParentCountByProcessId(const ContentParentId& aChildCpId);
/**
* Get the TabParent by the given content process and tab id.
* Return nullptr when TabParent couldn't be found via aChildCpId

View File

@ -350,6 +350,13 @@ struct GMPCapabilityData
GMPAPITags[] capabilities;
};
struct GfxInfoFeatureStatus
{
int32_t feature;
int32_t status;
nsCString failureId;
};
struct XPCOMInitData
{
bool isOffline;
@ -364,13 +371,7 @@ struct XPCOMInitData
FontFamilyListEntry[] fontFamilies;
OptionalURIParams userContentSheetURL;
PrefSetting[] prefs;
};
struct GfxInfoFeatureStatus
{
int32_t feature;
int32_t status;
nsCString failureId;
GfxInfoFeatureStatus[] gfxFeatureStatus;
};
/**
@ -964,8 +965,6 @@ parent:
bool isAudio,
bool isVideo);
sync GetGfxInfoFeatureStatus() returns (GfxInfoFeatureStatus[] features);
// Graphics errors
async GraphicsError(nsCString aError);

View File

@ -48,12 +48,10 @@ function tryToCreateNodeOnClosedContext(ctx) {
}
function loadFile(url, callback) {
todo(false, "loadFile: " + url);
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer";
xhr.onload = function() {
todo(false, "loadFile: " + url + " calling callback...");
callback(xhr.response);
};
xhr.send();
@ -393,13 +391,18 @@ function finish() {
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var tests = [
testAudioContext,
testOfflineAudioContext,
testScriptProcessNodeSuspended,
testMultiContextOutput,
testMultiContextInput,
testSuspendResumeEventLoop
];
// See Bug 1305136, many intermittent failures on Linux
if (!navigator.platform.startsWith("Linux")) {
tests.push(testAudioContext);
}
remaining = tests.length;
tests.forEach(function(f) { f() });
});

View File

@ -109,13 +109,7 @@ PresentationTransportBuilder.prototype = {
// TODO bug 1228235 we should have a way to let device providers customize
// the time-out duration.
let timeout;
try {
timeout = Services.prefs.getIntPref("presentation.receiver.loading.timeout");
} catch (e) {
// This happens if the pref doesn't exist, so we have a default value.
timeout = 10000;
}
let timeout = Services.prefs.getIntPref("presentation.receiver.loading.timeout", 10000);
// The timer is to check if the negotiation finishes on time.
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);

View File

@ -358,12 +358,11 @@ ChromecastRemoteDisplayDevice.prototype = {
};
function AndroidCastDeviceProvider() {
this._listener = null;
this._deviceList = new Map();
}
AndroidCastDeviceProvider.prototype = {
_listener: null,
_deviceList: new Map(),
onSessionRequest: function APDP_onSessionRequest(aDeviceId,
aUrl,
aPresentationId,
@ -403,18 +402,23 @@ AndroidCastDeviceProvider.prototype = {
// When unload this provider.
if (!this._listener) {
// remove observer
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED);
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_CHANGED);
Services.obs.removeObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED);
EventDispatcher.instance.unregisterListener(this, [
TOPIC_ANDROID_CAST_DEVICE_ADDED,
TOPIC_ANDROID_CAST_DEVICE_CHANGED,
TOPIC_ANDROID_CAST_DEVICE_REMOVED,
]);
return;
}
// Observer registration
EventDispatcher.instance.registerListener(this, [
TOPIC_ANDROID_CAST_DEVICE_ADDED,
TOPIC_ANDROID_CAST_DEVICE_CHANGED,
TOPIC_ANDROID_CAST_DEVICE_REMOVED,
]);
// Sync all device already found by Android.
EventDispatcher.instance.sendRequest({ type: TOPIC_ANDROID_CAST_DEVICE_SYNCDEVICE });
// Observer registration
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_ADDED, false);
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_CHANGED, false);
Services.obs.addObserver(this, TOPIC_ANDROID_CAST_DEVICE_REMOVED, false);
},
get listener() {
@ -425,13 +429,11 @@ AndroidCastDeviceProvider.prototype = {
// There is no API to do force discovery in Android SDK.
},
// nsIObserver
observe: function APDP_observe(aSubject, aTopic, aData) {
log('observe ' + aTopic + ': ' + aData);
switch (aTopic) {
onEvent: function APDP_onEvent(event, data, callback) {
switch (event) {
case TOPIC_ANDROID_CAST_DEVICE_ADDED:
case TOPIC_ANDROID_CAST_DEVICE_CHANGED: {
let deviceInfo = JSON.parse(aData);
let deviceInfo = data;
let deviceId = deviceInfo.uuid;
if (!this._deviceList.has(deviceId)) {
@ -449,7 +451,7 @@ AndroidCastDeviceProvider.prototype = {
break;
}
case TOPIC_ANDROID_CAST_DEVICE_REMOVED: {
let deviceId = aData;
let deviceId = data.id;
if (!this._deviceList.has(deviceId)) {
break;
}

View File

@ -39,12 +39,7 @@ var DEBUG = RIL.DEBUG_RIL;
function updateDebugFlag() {
// Read debug setting from pref
let debugPref;
try {
debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED);
} catch (e) {
debugPref = false;
}
let debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED, false);
DEBUG = debugPref || RIL.DEBUG_RIL;
}
updateDebugFlag();

View File

@ -85,12 +85,7 @@ var DEBUG = RIL.DEBUG_RIL;
function updateDebugFlag() {
// Read debug setting from pref
let debugPref;
try {
debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED);
} catch (e) {
debugPref = false;
}
let debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED, false);
DEBUG = debugPref || RIL.DEBUG_RIL;
}
updateDebugFlag();

View File

@ -68,12 +68,7 @@ var DEBUG = RIL.DEBUG_RIL;
function updateDebugFlag() {
// Read debug setting from pref
let debugPref;
try {
debugPref = Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
} catch (e) {
debugPref = false;
}
let debugPref = Services.prefs.getBoolPref(kPrefRilDebuggingEnabled, false);
DEBUG = RIL.DEBUG_RIL || debugPref;
}
updateDebugFlag();

View File

@ -14,13 +14,7 @@ const Ci = Components.interfaces;
const CONTENT_PAGE = "http://mochi.test:8888/chrome/dom/tests/mochitest/localstorage/page_blank.html";
const slavePath = "/chrome/dom/tests/mochitest/localstorage/";
var currentTest = 1;
var quota;
try {
quota = Services.prefs.getIntPref("dom.storage.default_quota");
} catch (ex) {
quota = 5 * 1024;
}
var quota = Services.prefs.getIntPref("dom.storage.default_quota", 5 * 1024);
Services.prefs.setIntPref("browser.startup.page", 0);
Services.prefs.setIntPref("dom.storage.default_quota", 1);

View File

@ -86,6 +86,7 @@ class JS_PUBLIC_API(JSTracer)
bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; }
bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; }
inline JS::CallbackTracer* asCallbackTracer();
bool traceWeakEdges() const { return traceWeakEdges_; }
#ifdef DEBUG
bool checkEdges() { return checkEdges_; }
#endif
@ -99,6 +100,7 @@ class JS_PUBLIC_API(JSTracer)
, checkEdges_(true)
#endif
, tag_(tag)
, traceWeakEdges_(true)
{}
#ifdef DEBUG
@ -117,6 +119,7 @@ class JS_PUBLIC_API(JSTracer)
protected:
TracerKindTag tag_;
bool traceWeakEdges_;
};
namespace JS {
@ -232,6 +235,11 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); }
protected:
void setTraceWeakEdges(bool value) {
traceWeakEdges_ = value;
}
private:
friend class AutoTracingName;
const char* contextName_;

View File

@ -26,7 +26,8 @@ Reflect_defineProperty(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
RootedObject obj(cx, NonNullObjectArg(cx, "`target`", "Reflect.defineProperty",
args.get(0)));
if (!obj)
return false;
@ -56,7 +57,8 @@ Reflect_deleteProperty(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
RootedObject target(cx, NonNullObjectArg(cx, "`target`", "Reflect.deleteProperty",
args.get(0)));
if (!target)
return false;
@ -81,7 +83,7 @@ Reflect_get(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
RootedObject obj(cx, NonNullObjectArg(cx, "`target`", "Reflect.get", args.get(0)));
if (!obj)
return false;
@ -104,7 +106,7 @@ Reflect_getOwnPropertyDescriptor(JSContext* cx, unsigned argc, Value* vp)
{
// Step 1.
CallArgs args = CallArgsFromVp(argc, vp);
if (!NonNullObject(cx, args.get(0)))
if (!NonNullObjectArg(cx, "`target`", "Reflect.getOwnPropertyDescriptor", args.get(0)))
return false;
// The other steps are identical to ES6 draft rev 32 (2015 Feb 2) 19.1.2.6
@ -119,7 +121,8 @@ js::Reflect_getPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
RootedObject target(cx, NonNullObjectArg(cx, "`target`", "Reflect.getPrototypeOf",
args.get(0)));
if (!target)
return false;
@ -138,7 +141,7 @@ js::Reflect_isExtensible(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
RootedObject target(cx, NonNullObjectArg(cx, "`target`", "Reflect.isExtensible", args.get(0)));
if (!target)
return false;
@ -157,7 +160,7 @@ Reflect_ownKeys(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (!NonNullObject(cx, args.get(0)))
if (!NonNullObjectArg(cx, "`target`", "Reflect.ownKeys", args.get(0)))
return false;
// Steps 2-4.
@ -171,7 +174,8 @@ Reflect_preventExtensions(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
RootedObject target(cx, NonNullObjectArg(cx, "`target`", "Reflect.preventExtensions",
args.get(0)));
if (!target)
return false;
@ -190,7 +194,7 @@ Reflect_set(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject target(cx, NonNullObject(cx, args.get(0)));
RootedObject target(cx, NonNullObjectArg(cx, "`target`", "Reflect.set", args.get(0)));
if (!target)
return false;
@ -224,7 +228,7 @@ Reflect_setPrototypeOf(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
RootedObject obj(cx, NonNullObject(cx, args.get(0)));
RootedObject obj(cx, NonNullObjectArg(cx, "`target`", "Reflect.setPrototypeOf", args.get(0)));
if (!obj)
return false;

View File

@ -34,8 +34,10 @@ function Reflect_apply(target, thisArgument, argumentsList) {
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, target));
// Step 2.
if (!IsObject(argumentsList))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(2, argumentsList));
if (!IsObject(argumentsList)) {
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT_ARG, "`argumentsList`", "Reflect.apply",
ToSource(argumentsList));
}
// Steps 2-4.
return callFunction(std_Function_apply, target, thisArgument, argumentsList);
@ -59,8 +61,10 @@ function Reflect_construct(target, argumentsList/*, newTarget*/) {
}
// Step 4.
if (!IsObject(argumentsList))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(1, argumentsList));
if (!IsObject(argumentsList)) {
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT_ARG, "`argumentsList`", "Reflect.construct",
ToSource(argumentsList));
}
// Fast path when we can avoid calling CreateListFromArrayLikeForArgs().
var args = (IsPackedArray(argumentsList) && argumentsList.length <= MAX_ARGS_LENGTH)
@ -105,7 +109,8 @@ function Reflect_construct(target, argumentsList/*, newTarget*/) {
function Reflect_has(target, propertyKey) {
// Step 1.
if (!IsObject(target))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, target));
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT_ARG, "`target`", "Reflect.has",
ToSource(target));
// Steps 2-3 are identical to the runtime semantics of the "in" operator.
return propertyKey in target;

View File

@ -169,11 +169,7 @@ WeakMap_set_impl(JSContext* cx, const CallArgs& args)
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!args.get(0).isObject()) {
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
if (!bytes)
return false;
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
bytes.get());
ReportNotObjectWithName(cx, "WeakMap key", args.get(0));
return false;
}

View File

@ -33,7 +33,7 @@ function WeakSet_add(value) {
// Step 5.
if (!IsObject(value))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value));
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT_NAME, "WeakSet value", ToSource(value));
// Steps 7-8.
callFunction(std_WeakMap_set, entries, value, true);

View File

@ -118,12 +118,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
if (keyVal.isPrimitive()) {
UniqueChars bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
if (!bytes)
return false;
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
JSMSG_NOT_NONNULL_OBJECT, bytes.get());
ReportNotObjectWithName(cx, "WeakSet value", keyVal);
return false;
}

View File

@ -64,29 +64,32 @@ using UsedNamePtr = UsedNameTracker::UsedNameMap::Ptr;
// Read a token. Report an error and return null() if that token doesn't match
// to the condition. Do not use MUST_MATCH_TOKEN_INTERNAL directly.
#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorNumber) \
#define MUST_MATCH_TOKEN_INTERNAL(cond, modifier, errorReport) \
JS_BEGIN_MACRO \
TokenKind token; \
if (!tokenStream.getToken(&token, modifier)) \
return null(); \
if (!(cond)) { \
error(errorNumber); \
errorReport; \
return null(); \
} \
JS_END_MACRO
#define MUST_MATCH_TOKEN_MOD(tt, modifier, errorNumber) \
MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorNumber)
MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, error(errorNumber))
#define MUST_MATCH_TOKEN(tt, errorNumber) \
MUST_MATCH_TOKEN_MOD(tt, TokenStream::None, errorNumber)
#define MUST_MATCH_TOKEN_FUNC_MOD(func, modifier, errorNumber) \
MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, errorNumber)
MUST_MATCH_TOKEN_INTERNAL((func)(token), modifier, error(errorNumber))
#define MUST_MATCH_TOKEN_FUNC(func, errorNumber) \
MUST_MATCH_TOKEN_FUNC_MOD(func, TokenStream::None, errorNumber)
#define MUST_MATCH_TOKEN_MOD_WITH_REPORT(tt, modifier, errorReport) \
MUST_MATCH_TOKEN_INTERNAL(token == tt, modifier, errorReport)
template <class T, class U>
static inline void
PropagateTransitiveParseFlags(const T* inner, U* outer)
@ -1001,6 +1004,35 @@ Parser<ParseHandler>::hasValidSimpleStrictParameterNames()
return true;
}
template <typename ParseHandler>
void
Parser<ParseHandler>::reportMissingClosing(unsigned errorNumber, unsigned noteNumber,
uint32_t openedPos)
{
auto notes = MakeUnique<JSErrorNotes>();
if (!notes)
return;
uint32_t line, column;
tokenStream.srcCoords.lineNumAndColumnIndex(openedPos, &line, &column);
const size_t MaxWidth = sizeof("4294967295");
char columnNumber[MaxWidth];
SprintfLiteral(columnNumber, "%" PRIu32, column);
char lineNumber[MaxWidth];
SprintfLiteral(lineNumber, "%" PRIu32, line);
if (!notes->addNoteASCII(pc->sc()->context,
getFilename(), line, column,
GetErrorMessage, nullptr,
noteNumber, lineNumber, columnNumber))
{
return;
}
errorWithNotes(Move(notes), errorNumber);
}
template <typename ParseHandler>
void
Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind,
@ -1028,11 +1060,11 @@ Parser<ParseHandler>::reportRedeclaration(HandlePropertyName name, DeclarationKi
char lineNumber[MaxWidth];
SprintfLiteral(lineNumber, "%" PRIu32, line);
if (!notes->addNoteLatin1(pc->sc()->context,
getFilename(), line, column,
GetErrorMessage, nullptr,
JSMSG_REDECLARED_PREV,
lineNumber, columnNumber))
if (!notes->addNoteASCII(pc->sc()->context,
getFilename(), line, column,
GetErrorMessage, nullptr,
JSMSG_REDECLARED_PREV,
lineNumber, columnNumber))
{
return;
}
@ -3607,6 +3639,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return false;
uint32_t openedPos = 0;
if (tt != TOK_LC) {
if (funbox->isStarGenerator() || kind == Method ||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
@ -3629,6 +3662,8 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
tokenStream.ungetToken();
bodyType = ExpressionBody;
funbox->setIsExprBody();
} else {
openedPos = pos().begin;
}
// Arrow function parameters inherit yieldHandling from the enclosing
@ -3666,13 +3701,9 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
}
if (bodyType == StatementListBody) {
bool matched;
if (!tokenStream.matchToken(&matched, TOK_RC, TokenStream::Operand))
return false;
if (!matched) {
error(JSMSG_CURLY_AFTER_BODY);
return false;
}
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
JSMSG_CURLY_OPENED, openedPos));
funbox->bufEnd = pos().end;
} else {
#if !JS_HAS_EXPR_CLOSURES
@ -4446,6 +4477,7 @@ typename ParseHandler::Node
Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned errorNumber)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc, StatementKind::Block);
ParseContext::Scope scope(this);
@ -4456,7 +4488,9 @@ Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned error
if (!list)
return null();
MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, errorNumber);
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED,
openedPos));
return finishLexicalScope(scope, list);
}
@ -6705,6 +6739,8 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
{
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc, StatementKind::Try);
ParseContext::Scope scope(this);
if (!scope.init(pc))
@ -6718,7 +6754,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!innerBlock)
return null();
MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_TRY);
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
JSMSG_CURLY_OPENED, openedPos));
}
bool hasUnconditionalCatch = false;
@ -6834,6 +6872,8 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (tt == TOK_FINALLY) {
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc, StatementKind::Finally);
ParseContext::Scope scope(this);
if (!scope.init(pc))
@ -6847,7 +6887,9 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!finallyBlock)
return null();
MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_FINALLY);
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
JSMSG_CURLY_OPENED, openedPos));
} else {
tokenStream.ungetToken();
}
@ -6864,6 +6906,8 @@ typename ParseHandler::Node
Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
ParseContext::Scope& catchParamScope)
{
uint32_t openedPos = pos().begin;
ParseContext::Statement stmt(pc, StatementKind::Block);
// ES 13.15.7 CatchClauseEvaluation
@ -6883,7 +6927,9 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
if (!list)
return null();
MUST_MATCH_TOKEN_MOD(TOK_RC, TokenStream::Operand, JSMSG_CURLY_AFTER_CATCH);
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::Operand,
reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
JSMSG_CURLY_OPENED, openedPos));
// The catch parameter names are not bound in the body scope, so remove
// them before generating bindings.
@ -9219,7 +9265,9 @@ Parser<ParseHandler>::arrayInitializer(YieldHandling yieldHandling, PossibleErro
}
}
MUST_MATCH_TOKEN_MOD(TOK_RB, modifier, JSMSG_BRACKET_AFTER_LIST);
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RB, modifier,
reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
JSMSG_BRACKET_OPENED, begin));
}
handler.setEndPosition(literal, pos().end);
return literal;
@ -9440,6 +9488,8 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
uint32_t openedPos = pos().begin;
Node literal = handler.newObjectLiteral(pos().begin);
if (!literal)
return null();
@ -9602,7 +9652,7 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
if (tt == TOK_RC)
break;
if (tt != TOK_COMMA) {
error(JSMSG_CURLY_AFTER_LIST);
reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, openedPos);
return null();
}
}

View File

@ -1448,6 +1448,8 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool hasValidSimpleStrictParameterNames();
void reportMissingClosing(unsigned errorNumber, unsigned noteNumber, uint32_t openedPos);
void reportRedeclaration(HandlePropertyName name, DeclarationKind prevKind, TokenPos pos,
uint32_t prevPos);
bool notePositionalFormalParameter(Node fn, HandlePropertyName name, uint32_t beginPos,

View File

@ -979,7 +979,7 @@ class GCRuntime
void beginSweepPhase(bool lastGC, AutoLockForExclusiveAccess& lock);
void findZoneGroups(AutoLockForExclusiveAccess& lock);
MOZ_MUST_USE bool findZoneEdgesForWeakMaps();
MOZ_MUST_USE bool findInterZoneEdges();
void getNextZoneGroup();
void endMarkingZoneGroup();
void beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock);

View File

@ -479,9 +479,12 @@ template <typename T>
void
js::TraceWeakEdge(JSTracer* trc, WeakRef<T>* thingp, const char* name)
{
// Non-marking tracers treat the edge strongly.
if (!trc->isMarkingTracer())
return DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
if (!trc->isMarkingTracer()) {
// Non-marking tracers can select whether or not they see weak edges.
if (trc->traceWeakEdges())
DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
return;
}
NoteWeakEdge(GCMarker::fromTracer(trc),
ConvertToBase(thingp->unsafeUnbarrieredForTracing()));

View File

@ -449,14 +449,24 @@ js::gc::GCRuntime::finishVerifier()
#endif /* JS_GC_ZEAL */
#ifdef JSGC_HASH_TABLE_CHECKS
#if defined(JSGC_HASH_TABLE_CHECKS) || defined(DEBUG)
class CheckHeapTracer : public JS::CallbackTracer
class HeapCheckTracerBase : public JS::CallbackTracer
{
public:
explicit CheckHeapTracer(JSRuntime* rt);
explicit HeapCheckTracerBase(JSRuntime* rt, WeakMapTraceKind weakTraceKind);
bool init();
void check(AutoLockForExclusiveAccess& lock);
bool traceHeap(AutoLockForExclusiveAccess& lock);
virtual void checkCell(Cell* cell) = 0;
protected:
void dumpCellPath();
Cell* parentCell() {
return parentIndex == -1 ? nullptr : stack[parentIndex].thing.asCell();
}
size_t failures;
private:
void onChild(const JS::GCCellPtr& thing) override;
@ -474,17 +484,16 @@ class CheckHeapTracer : public JS::CallbackTracer
JSRuntime* rt;
bool oom;
size_t failures;
HashSet<Cell*, DefaultHasher<Cell*>, SystemAllocPolicy> visited;
Vector<WorkItem, 0, SystemAllocPolicy> stack;
int parentIndex;
};
CheckHeapTracer::CheckHeapTracer(JSRuntime* rt)
: CallbackTracer(rt, TraceWeakMapKeysValues),
HeapCheckTracerBase::HeapCheckTracerBase(JSRuntime* rt, WeakMapTraceKind weakTraceKind)
: CallbackTracer(rt, weakTraceKind),
failures(0),
rt(rt),
oom(false),
failures(0),
parentIndex(-1)
{
#ifdef DEBUG
@ -493,21 +502,17 @@ CheckHeapTracer::CheckHeapTracer(JSRuntime* rt)
}
bool
CheckHeapTracer::init()
HeapCheckTracerBase::init()
{
return visited.init();
}
inline static bool
IsValidGCThingPointer(Cell* cell)
{
return (uintptr_t(cell) & CellMask) == 0;
}
void
CheckHeapTracer::onChild(const JS::GCCellPtr& thing)
HeapCheckTracerBase::onChild(const JS::GCCellPtr& thing)
{
Cell* cell = thing.asCell();
checkCell(cell);
if (visited.lookup(cell))
return;
@ -516,57 +521,98 @@ CheckHeapTracer::onChild(const JS::GCCellPtr& thing)
return;
}
if (!IsValidGCThingPointer(cell) || !IsGCThingValidAfterMovingGC(cell))
{
failures++;
fprintf(stderr, "Bad pointer %p\n", cell);
const char* name = contextName();
for (int index = parentIndex; index != -1; index = stack[index].parentIndex) {
const WorkItem& parent = stack[index];
cell = parent.thing.asCell();
fprintf(stderr, " from %s %p %s edge\n",
GCTraceKindToAscii(cell->getTraceKind()), cell, name);
name = parent.name;
}
fprintf(stderr, " from root %s\n", name);
return;
}
// Don't trace into GC things owned by another runtime.
if (cell->runtimeFromAnyThread() != rt)
return;
// Don't trace into GC in zones being used by helper threads.
Zone* zone = thing.is<JSObject>() ? thing.as<JSObject>().zone() : cell->asTenured().zone();
if (zone->group() && zone->group()->usedByHelperThread)
return;
WorkItem item(thing, contextName(), parentIndex);
if (!stack.append(item))
oom = true;
}
void
CheckHeapTracer::check(AutoLockForExclusiveAccess& lock)
bool
HeapCheckTracerBase::traceHeap(AutoLockForExclusiveAccess& lock)
{
// The analysis thinks that traceRuntime might GC by calling a GC callback.
JS::AutoSuppressGCAnalysis nogc;
if (!rt->isBeingDestroyed())
rt->gc.traceRuntime(this, lock);
while (!stack.empty()) {
while (!stack.empty() && !oom) {
WorkItem item = stack.back();
if (item.processed) {
stack.popBack();
} else {
parentIndex = stack.length() - 1;
TraceChildren(this, item.thing);
stack.back().processed = true;
TraceChildren(this, item.thing);
}
}
if (oom)
return !oom;
}
void
HeapCheckTracerBase::dumpCellPath()
{
const char* name = contextName();
for (int index = parentIndex; index != -1; index = stack[index].parentIndex) {
const WorkItem& parent = stack[index];
Cell* cell = parent.thing.asCell();
fprintf(stderr, " from %s %p %s edge\n",
GCTraceKindToAscii(cell->getTraceKind()), cell, name);
name = parent.name;
}
fprintf(stderr, " from root %s\n", name);
}
#endif // defined(JSGC_HASH_TABLE_CHECKS) || defined(DEBUG)
#ifdef JSGC_HASH_TABLE_CHECKS
class CheckHeapTracer final : public HeapCheckTracerBase
{
public:
explicit CheckHeapTracer(JSRuntime* rt);
void check(AutoLockForExclusiveAccess& lock);
private:
void checkCell(Cell* cell) override;
};
CheckHeapTracer::CheckHeapTracer(JSRuntime* rt)
: HeapCheckTracerBase(rt, TraceWeakMapKeysValues)
{}
inline static bool
IsValidGCThingPointer(Cell* cell)
{
return (uintptr_t(cell) & CellMask) == 0;
}
void
CheckHeapTracer::checkCell(Cell* cell)
{
if (!IsValidGCThingPointer(cell) || !IsGCThingValidAfterMovingGC(cell)) {
failures++;
fprintf(stderr, "Bad pointer %p\n", cell);
dumpCellPath();
}
}
void
CheckHeapTracer::check(AutoLockForExclusiveAccess& lock)
{
if (!traceHeap(lock))
return;
if (failures) {
fprintf(stderr, "Heap check: %" PRIuSIZE " failure(s) out of %" PRIu32 " pointers checked\n",
failures, visited.count());
}
if (failures)
fprintf(stderr, "Heap check: %" PRIuSIZE " failure(s)\n", failures);
MOZ_RELEASE_ASSERT(failures == 0);
}
@ -580,3 +626,69 @@ js::gc::CheckHeapAfterGC(JSRuntime* rt)
}
#endif /* JSGC_HASH_TABLE_CHECKS */
#ifdef DEBUG
class CheckGrayMarkingTracer final : public HeapCheckTracerBase
{
public:
explicit CheckGrayMarkingTracer(JSRuntime* rt);
bool check(AutoLockForExclusiveAccess& lock);
private:
void checkCell(Cell* cell) override;
};
CheckGrayMarkingTracer::CheckGrayMarkingTracer(JSRuntime* rt)
: HeapCheckTracerBase(rt, DoNotTraceWeakMaps)
{
// Weak gray->black edges are allowed.
setTraceWeakEdges(false);
}
void
CheckGrayMarkingTracer::checkCell(Cell* cell)
{
Cell* parent = parentCell();
if (!cell->isTenured() || !parent || !parent->isTenured())
return;
TenuredCell* tenuredCell = &cell->asTenured();
TenuredCell* tenuredParent = &parent->asTenured();
if (tenuredParent->isMarked(BLACK) && !tenuredParent->isMarked(GRAY) &&
tenuredCell->isMarked(GRAY))
{
failures++;
fprintf(stderr, "Found black to gray edge %p\n", cell);
dumpCellPath();
}
}
bool
CheckGrayMarkingTracer::check(AutoLockForExclusiveAccess& lock)
{
if (!traceHeap(lock))
return true; // Ignore failure.
return failures == 0;
}
JS_FRIEND_API(bool)
js::CheckGrayMarkingState(JSContext* cx)
{
JSRuntime* rt = cx->runtime();
MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
MOZ_ASSERT(!rt->gc.isIncrementalGCInProgress());
if (!rt->gc.areGrayBitsValid())
return true;
gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PHASE_TRACE_HEAP);
AutoTraceSession session(rt, JS::HeapState::Tracing);
CheckGrayMarkingTracer tracer(rt);
if (!tracer.init())
return true; // Ignore failure
return tracer.check(session.lock);
}
#endif // DEBUG

View File

@ -38,6 +38,7 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
weakCaches_(group),
gcWeakKeys_(group, SystemAllocPolicy(), rt->randomHashCodeScrambler()),
gcZoneGroupEdges_(group),
hasDeadProxies_(group),
typeDescrObjects_(group, this, SystemAllocPolicy()),
markedAtoms_(group),
usage(&rt->gc.usage),

View File

@ -371,9 +371,17 @@ struct Zone : public JS::shadow::Zone,
// This is used during GC while calculating zone groups to record edges that
// can't be determined by examining this zone by itself.
js::ZoneGroupData<ZoneSet> gcZoneGroupEdges_;
// Zones with dead proxies require an extra scan through the wrapper map,
// so track whether any dead proxies are known to exist.
js::ZoneGroupData<bool> hasDeadProxies_;
public:
ZoneSet& gcZoneGroupEdges() { return gcZoneGroupEdges_.ref(); }
bool hasDeadProxies() { return hasDeadProxies_; }
void setHasDeadProxies(bool b) { hasDeadProxies_ = b; }
// Keep track of all TypeDescr and related objects in this compartment.
// This is used by the GC to trace them all first when compacting, since the
// TypedObject trace hook may access these objects.

View File

@ -0,0 +1,14 @@
if (!('oomTest' in this))
quit();
function f(s) {
s + "x";
s.indexOf("y") === 0;
oomTest(new Function(s));
}
var s = `
class TestClass { constructor() {} }
for (var fun of hasPrototype) {}
`;
if (s.length)
f(s);

View File

@ -1,6 +1,6 @@
var wrapper = evaluate("({a: 15, b: {c: 42}})", {global: newGlobal({sameZoneAs: this})});
function testNuke() {
var wrapper = evaluate("({a: 15, b: {c: 42}})", {global: newGlobal({sameZoneAs: this})});
function test() {
var i, error;
try {
for (i = 0; i < 150; i++) {
@ -20,4 +20,19 @@ function test() {
assertEq(i, 143);
}
test();
function testSweep() {
var wrapper = evaluate("({a: 15, b: {c: 42}})", {global: newGlobal({})});
var error;
nukeCCW(wrapper);
gczeal(8, 1); // Sweep zones separately
try {
// Next access to wrapper.b should throw.
wrapper.x = 4;
} catch (e) {
error = e;
}
assertEq(error.message.includes("dead object"), true);
}
testNuke();
testSweep();

View File

@ -0,0 +1,90 @@
function test(source, [lineNumber, columnNumber], openType = "{", closeType = "}") {
let caught = false;
try {
Reflect.parse(source, { source: "foo.js" });
} catch (e) {
assertEq(e.message.includes("missing " + closeType + " "), true);
let notes = getErrorNotes(e);
assertEq(notes.length, 1);
let note = notes[0];
assertEq(note.message, openType + " opened at line " + lineNumber + ", column " + columnNumber);
assertEq(note.fileName, "foo.js");
assertEq(note.lineNumber, lineNumber);
assertEq(note.columnNumber, columnNumber);
caught = true;
}
assertEq(caught, true);
}
// Function
test(`
function test1() {
}
function test2() {
if (true) {
//}
}
function test3() {
}
`, [4, 17]);
// Block statement.
test(`
{
if (true) {
}
`, [2, 0]);
test(`
if (true) {
if (true) {
}
`, [2, 10]);
test(`
for (;;) {
if (true) {
}
`, [2, 9]);
test(`
while (true) {
if (true) {
}
`, [2, 13]);
test(`
do {
do {
} while(true);
`, [2, 3]);
// try-catch-finally.
test(`
try {
if (true) {
}
`, [2, 4]);
test(`
try {
} catch (e) {
if (true) {
}
`, [3, 12]);
test(`
try {
} finally {
if (true) {
}
`, [3, 10]);
// Object literal.
test(`
var x = {
foo: {
};
`, [2, 8]);
// Array literal.
test(`
var x = [
[
];
`, [2, 8], "[", "]");

View File

@ -141,6 +141,7 @@ GetObject(const MDefinition* ins)
case MDefinition::Op_AtomicTypedArrayElementBinop:
case MDefinition::Op_AsmJSLoadHeap:
case MDefinition::Op_AsmJSStoreHeap:
case MDefinition::Op_WasmLoadTls:
case MDefinition::Op_WasmLoad:
case MDefinition::Op_WasmStore:
case MDefinition::Op_AsmJSCompareExchangeHeap:

View File

@ -329,7 +329,14 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H
MOZ_CRASH("Invalid stub");
}
return stub->addUpdateStubForValue(cx, script /* = outerScript */, obj, id, value);
if (!stub->addUpdateStubForValue(cx, script /* = outerScript */, obj, id, value)) {
// The calling JIT code assumes this function is infallible (for
// instance we may reallocate dynamic slots before calling this),
// so ignore OOMs if we failed to attach a stub.
cx->recoverFromOutOfMemory();
}
return true;
}
typedef bool (*DoTypeUpdateFallbackFn)(JSContext*, BaselineFrame*, ICUpdatedStub*, HandleValue,

View File

@ -12005,9 +12005,32 @@ CodeGenerator::visitWasmTrap(LWasmTrap* lir)
void
CodeGenerator::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
{
#ifdef WASM_HUGE_MEMORY
MOZ_CRASH("No wasm bounds check for huge memory");
#else
const MWasmBoundsCheck* mir = ins->mir();
Register ptr = ToRegister(ins->ptr());
masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr, trap(mir, wasm::Trap::OutOfBounds));
Register boundsCheckLimit = ToRegister(ins->boundsCheckLimit());
masm.wasmBoundsCheck(Assembler::AboveOrEqual, ptr, boundsCheckLimit,
trap(mir, wasm::Trap::OutOfBounds));
#endif
}
void
CodeGenerator::visitWasmLoadTls(LWasmLoadTls* ins)
{
switch (ins->mir()->type()) {
case MIRType::Pointer:
masm.loadPtr(Address(ToRegister(ins->tlsPtr()), ins->mir()->offset()),
ToRegister(ins->output()));
break;
case MIRType::Int32:
masm.load32(Address(ToRegister(ins->tlsPtr()), ins->mir()->offset()),
ToRegister(ins->output()));
break;
default:
MOZ_CRASH("MIRType not supported in WasmLoadTls");
}
}
typedef bool (*RecompileFn)(JSContext*);

View File

@ -437,6 +437,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitInterruptCheck(LInterruptCheck* lir);
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
void visitWasmTrap(LWasmTrap* lir);
void visitWasmLoadTls(LWasmLoadTls* ins);
void visitWasmBoundsCheck(LWasmBoundsCheck* ins);
void visitRecompileCheck(LRecompileCheck* ins);
void visitRotate(LRotate* ins);

View File

@ -937,7 +937,7 @@ ControlFlowGenerator::processWhileOrForInLoop(jssrcnote* sn)
size_t stackPhiCount;
if (SN_TYPE(sn) == SRC_FOR_OF)
stackPhiCount = 2;
stackPhiCount = 3;
else if (SN_TYPE(sn) == SRC_FOR_IN)
stackPhiCount = 1;
else

View File

@ -874,6 +874,14 @@ enum class BarrierKind : uint32_t {
enum ReprotectCode { Reprotect = true, DontReprotect = false };
// Rounding modes for round instructions.
enum class RoundingMode {
Down,
Up,
NearestTiesToEven,
TowardsZero
};
} // namespace jit
} // namespace js

View File

@ -1432,6 +1432,22 @@ LIRGenerator::visitRound(MRound* ins)
define(lir, ins);
}
void
LIRGenerator::visitNearbyInt(MNearbyInt* ins)
{
MIRType inputType = ins->input()->type();
MOZ_ASSERT(IsFloatingPointType(inputType));
MOZ_ASSERT(ins->type() == inputType);
LInstructionHelper<1, 1, 0>* lir;
if (inputType == MIRType::Double)
lir = new(alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
else
lir = new(alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
define(lir, ins);
}
void
LIRGenerator::visitMinMax(MMinMax* ins)
{
@ -4254,19 +4270,39 @@ LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins)
define(new(alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
}
void
LIRGenerator::visitWasmLoadTls(MWasmLoadTls* ins)
{
#ifdef WASM_HUGE_MEMORY
// This will disappear once we remove HeapReg and replace it with a load
// from Tls, but in the mean time it keeps us sane.
MOZ_CRASH("No WasmLoadTls here at the moment");
#endif
auto* lir = new(alloc()) LWasmLoadTls(useRegisterAtStart(ins->tlsPtr()));
define(lir, ins);
}
void
LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins)
{
#ifdef WASM_HUGE_MEMORY
MOZ_CRASH("No bounds checking on huge memory");
#else
if (ins->isRedundant()) {
if (MOZ_LIKELY(!JitOptions.wasmAlwaysCheckBounds))
return;
}
MDefinition* input = ins->input();
MOZ_ASSERT(input->type() == MIRType::Int32);
MDefinition* index = ins->index();
MOZ_ASSERT(index->type() == MIRType::Int32);
auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(input));
MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
MOZ_ASSERT(boundsCheckLimit->type() == MIRType::Int32);
auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
useRegisterAtStart(boundsCheckLimit));
add(lir, ins);
#endif
}
void

View File

@ -135,6 +135,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitFloor(MFloor* ins);
void visitCeil(MCeil* ins);
void visitRound(MRound* ins);
void visitNearbyInt(MNearbyInt* ins);
void visitMinMax(MMinMax* ins);
void visitAbs(MAbs* ins);
void visitClz(MClz* ins);
@ -292,6 +293,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitIsObject(MIsObject* ins);
void visitHasClass(MHasClass* ins);
void visitWasmAddOffset(MWasmAddOffset* ins);
void visitWasmLoadTls(MWasmLoadTls* ins);
void visitWasmBoundsCheck(MWasmBoundsCheck* ins);
void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins);
void visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins);

View File

@ -986,20 +986,30 @@ IonBuilder::inlineMathFloor(CallInfo& callInfo)
return InliningStatus_Inlined;
}
if (IsFloatingPointType(argType) && returnType == MIRType::Int32) {
callInfo.setImplicitlyUsedUnchecked();
MFloor* ins = MFloor::New(alloc(), callInfo.getArg(0));
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
if (IsFloatingPointType(argType)) {
if (returnType == MIRType::Int32) {
callInfo.setImplicitlyUsedUnchecked();
MFloor* ins = MFloor::New(alloc(), callInfo.getArg(0));
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
if (IsFloatingPointType(argType) && returnType == MIRType::Double) {
callInfo.setImplicitlyUsedUnchecked();
MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor, nullptr);
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
if (returnType == MIRType::Double) {
callInfo.setImplicitlyUsedUnchecked();
MInstruction* ins = nullptr;
if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down)) {
ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, RoundingMode::Down);
} else {
ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Floor,
/* cache */ nullptr);
}
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
}
return InliningStatus_NotInlined;
@ -1030,20 +1040,30 @@ IonBuilder::inlineMathCeil(CallInfo& callInfo)
return InliningStatus_Inlined;
}
if (IsFloatingPointType(argType) && returnType == MIRType::Int32) {
callInfo.setImplicitlyUsedUnchecked();
MCeil* ins = MCeil::New(alloc(), callInfo.getArg(0));
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
if (IsFloatingPointType(argType)) {
if (returnType == MIRType::Int32) {
callInfo.setImplicitlyUsedUnchecked();
MCeil* ins = MCeil::New(alloc(), callInfo.getArg(0));
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
if (IsFloatingPointType(argType) && returnType == MIRType::Double) {
callInfo.setImplicitlyUsedUnchecked();
MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil, nullptr);
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
if (returnType == MIRType::Double) {
callInfo.setImplicitlyUsedUnchecked();
MInstruction* ins = nullptr;
if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up)) {
ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, RoundingMode::Up);
} else {
ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Ceil,
/* cache */ nullptr);
}
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
}
return InliningStatus_NotInlined;
@ -1108,7 +1128,8 @@ IonBuilder::inlineMathRound(CallInfo& callInfo)
if (IsFloatingPointType(argType) && returnType == MIRType::Double) {
callInfo.setImplicitlyUsedUnchecked();
MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round, nullptr);
MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), MMathFunction::Round,
/* cache */ nullptr);
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;

View File

@ -1778,6 +1778,19 @@ MAssertRange::printOpcode(GenericPrinter& out) const
assertedRange()->dump(out);
}
void MNearbyInt::printOpcode(GenericPrinter& out) const
{
MDefinition::printOpcode(out);
const char* roundingModeStr = nullptr;
switch (roundingMode_) {
case RoundingMode::Up: roundingModeStr = "(up)"; break;
case RoundingMode::Down: roundingModeStr = "(down)"; break;
case RoundingMode::NearestTiesToEven: roundingModeStr = "(nearest ties even)"; break;
case RoundingMode::TowardsZero: roundingModeStr = "(towards zero)"; break;
}
out.printf(" %s", roundingModeStr);
}
const char*
MMathFunction::FunctionName(Function function)
{
@ -2153,6 +2166,13 @@ MRound::trySpecializeFloat32(TempAllocator& alloc)
specialization_ = MIRType::Float32;
}
void
MNearbyInt::trySpecializeFloat32(TempAllocator& alloc)
{
if (EnsureFloatInputOrConvert(this, alloc))
specialization_ = MIRType::Float32;
}
MTableSwitch*
MTableSwitch::New(TempAllocator& alloc, MDefinition* ins, int32_t low, int32_t high)
{

View File

@ -385,11 +385,13 @@ class AliasSet {
FrameArgument = 1 << 6, // An argument kept on the stack frame
WasmGlobalVar = 1 << 7, // An asm.js/wasm global var
WasmHeap = 1 << 8, // An asm.js/wasm heap load
TypedArrayLength = 1 << 9,// A typed array's length
WasmHeapMeta = 1 << 9, // The asm.js/wasm heap base pointer and
// bounds check limit, in Tls.
TypedArrayLength = 1 << 10,// A typed array's length
Last = TypedArrayLength,
Any = Last | (Last - 1),
NumCategories = 10,
NumCategories = 11,
// Indicates load or store.
Store_ = 1 << 31
@ -12190,7 +12192,7 @@ class MStringLength
ALLOW_CLONE(MStringLength)
};
// Inlined version of Math.floor().
// Inlined assembly for Math.floor(double | float32) -> int32.
class MFloor
: public MUnaryInstruction,
public FloatingPointPolicy<0>::Data
@ -12231,7 +12233,7 @@ class MFloor
ALLOW_CLONE(MFloor)
};
// Inlined version of Math.ceil().
// Inlined assembly version for Math.ceil(double | float32) -> int32.
class MCeil
: public MUnaryInstruction,
public FloatingPointPolicy<0>::Data
@ -12272,7 +12274,7 @@ class MCeil
ALLOW_CLONE(MCeil)
};
// Inlined version of Math.round().
// Inlined version of Math.round(double | float32) -> int32.
class MRound
: public MUnaryInstruction,
public FloatingPointPolicy<0>::Data
@ -12314,6 +12316,61 @@ class MRound
ALLOW_CLONE(MRound)
};
// NearbyInt rounds the floating-point input to the nearest integer, according
// to the RoundingMode.
class MNearbyInt
: public MUnaryInstruction,
public FloatingPointPolicy<0>::Data
{
RoundingMode roundingMode_;
explicit MNearbyInt(MDefinition* num, MIRType resultType, RoundingMode roundingMode)
: MUnaryInstruction(num),
roundingMode_(roundingMode)
{
MOZ_ASSERT(HasAssemblerSupport(roundingMode));
MOZ_ASSERT(IsFloatingPointType(resultType));
setResultType(resultType);
specialization_ = resultType;
setMovable();
}
public:
INSTRUCTION_HEADER(NearbyInt)
TRIVIAL_NEW_WRAPPERS
static bool HasAssemblerSupport(RoundingMode mode) {
return Assembler::HasRoundInstruction(mode);
}
RoundingMode roundingMode() const { return roundingMode_; }
AliasSet getAliasSet() const override {
return AliasSet::None();
}
bool isFloat32Commutative() const override {
return true;
}
void trySpecializeFloat32(TempAllocator& alloc) override;
#ifdef DEBUG
bool isConsistentFloat32Use(MUse* use) const override {
return true;
}
#endif
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins) &&
ins->toNearbyInt()->roundingMode() == roundingMode_;
}
void printOpcode(GenericPrinter& out) const override;
ALLOW_CLONE(MNearbyInt)
};
class MIteratorStart
: public MUnaryInstruction,
public BoxExceptPolicy<0, MIRType::Object>::Data
@ -13617,15 +13674,62 @@ class MAsmJSNeg
TRIVIAL_NEW_WRAPPERS
};
class MWasmBoundsCheck
class MWasmLoadTls
: public MUnaryInstruction,
public NoTypePolicy::Data
{
uint32_t offset_;
AliasSet aliases_;
explicit MWasmLoadTls(MDefinition* tlsPointer, uint32_t offset, MIRType type, AliasSet aliases)
: MUnaryInstruction(tlsPointer),
offset_(offset),
aliases_(aliases)
{
// Different Tls data have different alias classes and only those classes are allowed.
MOZ_ASSERT(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||
aliases_.flags() == AliasSet::None().flags());
// The only types supported at the moment.
MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32);
setMovable();
setResultType(type);
}
public:
INSTRUCTION_HEADER(WasmLoadTls)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, tlsPtr))
uint32_t offset() const {
return offset_;
}
bool congruentTo(const MDefinition* ins) const override {
return op() == ins->op() &&
offset() == ins->toWasmLoadTls()->offset() &&
type() == ins->type();
}
HashNumber valueHash() const override {
return op() + offset();
}
AliasSet getAliasSet() const override {
return aliases_;
}
};
class MWasmBoundsCheck
: public MBinaryInstruction,
public NoTypePolicy::Data
{
bool redundant_;
wasm::TrapOffset trapOffset_;
explicit MWasmBoundsCheck(MDefinition* index, wasm::TrapOffset trapOffset)
: MUnaryInstruction(index),
explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit, wasm::TrapOffset trapOffset)
: MBinaryInstruction(index, boundsCheckLimit),
redundant_(false),
trapOffset_(trapOffset)
{
@ -13635,6 +13739,7 @@ class MWasmBoundsCheck
public:
INSTRUCTION_HEADER(WasmBoundsCheck)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, index), (1, boundsCheckLimit))
AliasSet getAliasSet() const override {
return AliasSet::None();
@ -13689,14 +13794,13 @@ class MWasmAddOffset
};
class MWasmLoad
: public MUnaryInstruction,
: public MVariadicInstruction, // memoryBase is nullptr on some platforms
public NoTypePolicy::Data
{
wasm::MemoryAccessDesc access_;
MWasmLoad(MDefinition* base, const wasm::MemoryAccessDesc& access, MIRType resultType)
: MUnaryInstruction(base),
access_(access)
explicit MWasmLoad(const wasm::MemoryAccessDesc& access, MIRType resultType)
: access_(access)
{
setGuard();
setResultType(resultType);
@ -13704,8 +13808,24 @@ class MWasmLoad
public:
INSTRUCTION_HEADER(WasmLoad)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, base))
NAMED_OPERANDS((0, base), (1, memoryBase));
static MWasmLoad* New(TempAllocator& alloc,
MDefinition* memoryBase,
MDefinition* base,
const wasm::MemoryAccessDesc& access,
MIRType resultType)
{
MWasmLoad* load = new(alloc) MWasmLoad(access, resultType);
if (!load->init(alloc, 1 + !!memoryBase))
return nullptr;
load->initOperand(0, base);
if (memoryBase)
load->initOperand(1, memoryBase);
return load;
}
const wasm::MemoryAccessDesc& access() const {
return access_;
@ -13721,22 +13841,38 @@ class MWasmLoad
};
class MWasmStore
: public MBinaryInstruction,
: public MVariadicInstruction,
public NoTypePolicy::Data
{
wasm::MemoryAccessDesc access_;
MWasmStore(MDefinition* base, const wasm::MemoryAccessDesc& access, MDefinition* value)
: MBinaryInstruction(base, value),
access_(access)
explicit MWasmStore(const wasm::MemoryAccessDesc& access)
: access_(access)
{
setGuard();
}
public:
INSTRUCTION_HEADER(WasmStore)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, base), (1, value))
NAMED_OPERANDS((0, base), (1, value), (2, memoryBase))
static MWasmStore* New(TempAllocator& alloc,
MDefinition* memoryBase,
MDefinition* base,
const wasm::MemoryAccessDesc& access,
MDefinition* value)
{
MWasmStore* store = new(alloc) MWasmStore(access);
if (!store->init(alloc, 2 + !!memoryBase))
return nullptr;
store->initOperand(0, base);
store->initOperand(1, value);
if (memoryBase)
store->initOperand(2, memoryBase);
return store;
}
const wasm::MemoryAccessDesc& access() const {
return access_;
@ -13779,23 +13915,53 @@ class MAsmJSMemoryAccess
};
class MAsmJSLoadHeap
: public MUnaryInstruction,
: public MVariadicInstruction, // 1 plus optional memoryBase and boundsCheckLimit
public MAsmJSMemoryAccess,
public NoTypePolicy::Data
{
MAsmJSLoadHeap(MDefinition* base, Scalar::Type accessType)
: MUnaryInstruction(base),
MAsmJSMemoryAccess(accessType)
uint32_t memoryBaseIndex_;
uint32_t boundsCheckIndex_;
explicit MAsmJSLoadHeap(uint32_t memoryBaseIndex, uint32_t boundsCheckIndex,
Scalar::Type accessType)
: MAsmJSMemoryAccess(accessType),
memoryBaseIndex_(memoryBaseIndex),
boundsCheckIndex_(boundsCheckIndex)
{
setResultType(ScalarTypeToMIRType(accessType));
}
public:
INSTRUCTION_HEADER(AsmJSLoadHeap)
TRIVIAL_NEW_WRAPPERS
static MAsmJSLoadHeap* New(TempAllocator& alloc,
MDefinition* memoryBase,
MDefinition* base,
MDefinition* boundsCheckLimit,
Scalar::Type accessType)
{
uint32_t nextIndex = 1;
uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX;
uint32_t boundsCheckIndex = boundsCheckLimit ? nextIndex++ : UINT32_MAX;
MAsmJSLoadHeap* load = new(alloc) MAsmJSLoadHeap(memoryBaseIndex, boundsCheckIndex,
accessType);
if (!load->init(alloc, nextIndex))
return nullptr;
load->initOperand(0, base);
if (memoryBase)
load->initOperand(memoryBaseIndex, memoryBase);
if (boundsCheckLimit)
load->initOperand(boundsCheckIndex, boundsCheckLimit);
return load;
}
MDefinition* base() const { return getOperand(0); }
void replaceBase(MDefinition* newBase) { replaceOperand(0, newBase); }
MDefinition* memoryBase() const { return getOperand(memoryBaseIndex_); }
MDefinition* boundsCheckLimit() const { return getOperand(boundsCheckIndex_); }
bool congruentTo(const MDefinition* ins) const override;
AliasSet getAliasSet() const override {
@ -13805,22 +13971,55 @@ class MAsmJSLoadHeap
};
class MAsmJSStoreHeap
: public MBinaryInstruction,
: public MVariadicInstruction, // 2 plus optional memoryBase and boundsCheckLimit
public MAsmJSMemoryAccess,
public NoTypePolicy::Data
{
MAsmJSStoreHeap(MDefinition* base, Scalar::Type accessType, MDefinition* v)
: MBinaryInstruction(base, v),
MAsmJSMemoryAccess(accessType)
{}
uint32_t memoryBaseIndex_;
uint32_t boundsCheckIndex_;
explicit MAsmJSStoreHeap(uint32_t memoryBaseIndex, uint32_t boundsCheckIndex,
Scalar::Type accessType)
: MAsmJSMemoryAccess(accessType),
memoryBaseIndex_(memoryBaseIndex),
boundsCheckIndex_(boundsCheckIndex)
{
}
public:
INSTRUCTION_HEADER(AsmJSStoreHeap)
TRIVIAL_NEW_WRAPPERS
static MAsmJSStoreHeap* New(TempAllocator& alloc,
MDefinition* memoryBase,
MDefinition* base,
MDefinition* boundsCheckLimit,
Scalar::Type accessType,
MDefinition* v)
{
uint32_t nextIndex = 2;
uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX;
uint32_t boundsCheckIndex = boundsCheckLimit ? nextIndex++ : UINT32_MAX;
MAsmJSStoreHeap* store = new(alloc) MAsmJSStoreHeap(memoryBaseIndex, boundsCheckIndex,
accessType);
if (!store->init(alloc, nextIndex))
return nullptr;
store->initOperand(0, base);
store->initOperand(1, v);
if (memoryBase)
store->initOperand(memoryBaseIndex, memoryBase);
if (boundsCheckLimit)
store->initOperand(boundsCheckIndex, boundsCheckLimit);
return store;
}
MDefinition* base() const { return getOperand(0); }
void replaceBase(MDefinition* newBase) { replaceOperand(0, newBase); }
MDefinition* value() const { return getOperand(1); }
MDefinition* memoryBase() const { return getOperand(memoryBaseIndex_); }
MDefinition* boundsCheckLimit() const { return getOperand(boundsCheckIndex_); }
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::WasmHeap);
@ -13828,15 +14027,13 @@ class MAsmJSStoreHeap
};
class MAsmJSCompareExchangeHeap
: public MQuaternaryInstruction,
: public MVariadicInstruction,
public NoTypePolicy::Data
{
wasm::MemoryAccessDesc access_;
MAsmJSCompareExchangeHeap(MDefinition* base, const wasm::MemoryAccessDesc& access,
MDefinition* oldv, MDefinition* newv, MDefinition* tls)
: MQuaternaryInstruction(base, oldv, newv, tls),
access_(access)
explicit MAsmJSCompareExchangeHeap(const wasm::MemoryAccessDesc& access)
: access_(access)
{
setGuard(); // Not removable
setResultType(MIRType::Int32);
@ -13844,7 +14041,28 @@ class MAsmJSCompareExchangeHeap
public:
INSTRUCTION_HEADER(AsmJSCompareExchangeHeap)
TRIVIAL_NEW_WRAPPERS
static MAsmJSCompareExchangeHeap* New(TempAllocator& alloc,
MDefinition* memoryBase,
MDefinition* base,
const wasm::MemoryAccessDesc& access,
MDefinition* oldv,
MDefinition* newv,
MDefinition* tls)
{
MAsmJSCompareExchangeHeap* cas = new(alloc) MAsmJSCompareExchangeHeap(access);
if (!cas->init(alloc, 4 + !!memoryBase))
return nullptr;
cas->initOperand(0, base);
cas->initOperand(1, oldv);
cas->initOperand(2, newv);
cas->initOperand(3, tls);
if (memoryBase)
cas->initOperand(4, memoryBase);
return cas;
}
const wasm::MemoryAccessDesc& access() const { return access_; }
@ -13852,6 +14070,7 @@ class MAsmJSCompareExchangeHeap
MDefinition* oldValue() const { return getOperand(1); }
MDefinition* newValue() const { return getOperand(2); }
MDefinition* tls() const { return getOperand(3); }
MDefinition* memoryBase() const { return getOperand(4); }
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::WasmHeap);
@ -13859,15 +14078,13 @@ class MAsmJSCompareExchangeHeap
};
class MAsmJSAtomicExchangeHeap
: public MTernaryInstruction,
: public MVariadicInstruction,
public NoTypePolicy::Data
{
wasm::MemoryAccessDesc access_;
MAsmJSAtomicExchangeHeap(MDefinition* base, const wasm::MemoryAccessDesc& access,
MDefinition* value, MDefinition* tls)
: MTernaryInstruction(base, value, tls),
access_(access)
explicit MAsmJSAtomicExchangeHeap(const wasm::MemoryAccessDesc& access)
: access_(access)
{
setGuard(); // Not removable
setResultType(MIRType::Int32);
@ -13875,13 +14092,33 @@ class MAsmJSAtomicExchangeHeap
public:
INSTRUCTION_HEADER(AsmJSAtomicExchangeHeap)
TRIVIAL_NEW_WRAPPERS
static MAsmJSAtomicExchangeHeap* New(TempAllocator& alloc,
MDefinition* memoryBase,
MDefinition* base,
const wasm::MemoryAccessDesc& access,
MDefinition* value,
MDefinition* tls)
{
MAsmJSAtomicExchangeHeap* xchg = new(alloc) MAsmJSAtomicExchangeHeap(access);
if (!xchg->init(alloc, 3 + !!memoryBase))
return nullptr;
xchg->initOperand(0, base);
xchg->initOperand(1, value);
xchg->initOperand(2, tls);
if (memoryBase)
xchg->initOperand(3, memoryBase);
return xchg;
}
const wasm::MemoryAccessDesc& access() const { return access_; }
MDefinition* base() const { return getOperand(0); }
MDefinition* value() const { return getOperand(1); }
MDefinition* tls() const { return getOperand(2); }
MDefinition* memoryBase() const { return getOperand(3); }
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::WasmHeap);
@ -13889,16 +14126,14 @@ class MAsmJSAtomicExchangeHeap
};
class MAsmJSAtomicBinopHeap
: public MTernaryInstruction,
: public MVariadicInstruction,
public NoTypePolicy::Data
{
AtomicOp op_;
wasm::MemoryAccessDesc access_;
MAsmJSAtomicBinopHeap(AtomicOp op, MDefinition* base, const wasm::MemoryAccessDesc& access,
MDefinition* v, MDefinition* tls)
: MTernaryInstruction(base, v, tls),
op_(op),
explicit MAsmJSAtomicBinopHeap(AtomicOp op, const wasm::MemoryAccessDesc& access)
: op_(op),
access_(access)
{
setGuard(); // Not removable
@ -13907,7 +14142,27 @@ class MAsmJSAtomicBinopHeap
public:
INSTRUCTION_HEADER(AsmJSAtomicBinopHeap)
TRIVIAL_NEW_WRAPPERS
static MAsmJSAtomicBinopHeap* New(TempAllocator& alloc,
AtomicOp op,
MDefinition* memoryBase,
MDefinition* base,
const wasm::MemoryAccessDesc& access,
MDefinition* v,
MDefinition* tls)
{
MAsmJSAtomicBinopHeap* binop = new(alloc) MAsmJSAtomicBinopHeap(op, access);
if (!binop->init(alloc, 3 + !!memoryBase))
return nullptr;
binop->initOperand(0, base);
binop->initOperand(1, v);
binop->initOperand(2, tls);
if (memoryBase)
binop->initOperand(3, memoryBase);
return binop;
}
AtomicOp operation() const { return op_; }
const wasm::MemoryAccessDesc& access() const { return access_; }
@ -13915,6 +14170,7 @@ class MAsmJSAtomicBinopHeap
MDefinition* base() const { return getOperand(0); }
MDefinition* value() const { return getOperand(1); }
MDefinition* tls() const { return getOperand(2); }
MDefinition* memoryBase() const { return getOperand(3); }
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::WasmHeap);

View File

@ -263,6 +263,7 @@ namespace jit {
_(Floor) \
_(Ceil) \
_(Round) \
_(NearbyInt) \
_(In) \
_(InstanceOf) \
_(CallInstanceOf) \
@ -297,6 +298,7 @@ namespace jit {
_(AsmJSAtomicExchangeHeap) \
_(AsmJSAtomicBinopHeap) \
_(WasmBoundsCheck) \
_(WasmLoadTls) \
_(WasmAddOffset) \
_(WasmLoad) \
_(WasmStore) \

View File

@ -1360,14 +1360,15 @@ class MacroAssembler : public MacroAssemblerSpecific
// ========================================================================
// wasm support
// Emit a bounds check against the (dynamically-patched) wasm bounds check
// limit, jumping to 'label' if 'cond' holds.
// Emit a bounds check against the wasm heap limit, jumping to 'label' if 'cond' holds.
// Required when WASM_HUGE_MEMORY is not defined.
template <class L>
inline void wasmBoundsCheck(Condition cond, Register index, L label) PER_ARCH;
inline void wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
DEFINED_ON(arm, arm64, mips32, mips64, x86);
// Called after compilation completes to patch the given limit into the
// given instruction's immediate.
static inline void wasmPatchBoundsCheck(uint8_t* patchAt, uint32_t limit) PER_ARCH;
template <class L>
inline void wasmBoundsCheck(Condition cond, Register index, Address boundsCheckLimit, L label)
DEFINED_ON(arm, arm64, mips32, mips64, x86);
// On x86, each instruction adds its own wasm::MemoryAccess's to the
// wasm::MemoryAccessVector (there can be multiple when i64 is involved).

View File

@ -1747,6 +1747,8 @@ class Assembler : public AssemblerShared
return js::jit::SupportsSimd;
}
static bool HasRoundInstruction(RoundingMode mode) { return false; }
protected:
void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) {
enoughMemory_ &= jumps_.append(RelativePatch(target.value, kind));

View File

@ -2292,6 +2292,7 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
MOZ_ASSERT(mir->offset() == 0);
const LAllocation* ptr = ins->ptr();
const LAllocation* boundsCheckLimit = ins->boundsCheckLimit();
bool isSigned;
int size;
@ -2325,7 +2326,6 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
ToRegister(ins->output()), scratch, Offset, Assembler::Always);
}
} else {
ScratchRegisterScope scratch(masm);
Register ptrReg = ToRegister(ptr);
if (isFloat) {
FloatRegister output = ToFloatRegister(ins->output());
@ -2334,8 +2334,8 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
Assembler::Condition cond = Assembler::Always;
if (mir->needsBoundsCheck()) {
BufferOffset cmp = masm.as_cmp(ptrReg, Imm8(0));
masm.append(wasm::BoundsCheck(cmp.getOffset()));
Register boundsCheckLimitReg = ToRegister(boundsCheckLimit);
masm.as_cmp(ptrReg, O2Reg(boundsCheckLimitReg));
if (size == 32)
masm.ma_vimm_f32(GenericNaN(), output, Assembler::AboveOrEqual);
else
@ -2343,19 +2343,20 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
cond = Assembler::Below;
}
ScratchRegisterScope scratch(masm);
masm.ma_vldr(output, HeapReg, ptrReg, scratch, 0, cond);
} else {
Register output = ToRegister(ins->output());
Assembler::Condition cond = Assembler::Always;
if (mir->needsBoundsCheck()) {
uint32_t cmpOffset = masm.as_cmp(ptrReg, Imm8(0)).getOffset();
masm.append(wasm::BoundsCheck(cmpOffset));
Register boundsCheckLimitReg = ToRegister(boundsCheckLimit);
masm.as_cmp(ptrReg, O2Reg(boundsCheckLimitReg));
masm.ma_mov(Imm32(0), output, Assembler::AboveOrEqual);
cond = Assembler::Below;
}
ScratchRegisterScope scratch(masm);
masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, ptrReg, output, scratch, Offset, cond);
}
}
@ -2517,6 +2518,7 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
MOZ_ASSERT(mir->offset() == 0);
const LAllocation* ptr = ins->ptr();
const LAllocation* boundsCheckLimit = ins->boundsCheckLimit();
bool isSigned;
int size;
@ -2554,9 +2556,8 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
Assembler::Condition cond = Assembler::Always;
if (mir->needsBoundsCheck()) {
BufferOffset cmp = masm.as_cmp(ptrReg, Imm8(0));
masm.append(wasm::BoundsCheck(cmp.getOffset()));
Register boundsCheckLimitReg = ToRegister(boundsCheckLimit);
masm.as_cmp(ptrReg, O2Reg(boundsCheckLimitReg));
cond = Assembler::Below;
}

View File

@ -612,7 +612,7 @@ class LWasmUnalignedLoadBase : public details::LWasmLoadBase<NumDefs, 4>
explicit LWasmUnalignedLoadBase(const LAllocation& ptr, const LDefinition& ptrCopy,
const LDefinition& temp1, const LDefinition& temp2,
const LDefinition& temp3)
: Base(ptr)
: Base(ptr, LAllocation())
{
Base::setTemp(0, ptrCopy);
Base::setTemp(1, temp1);

View File

@ -712,15 +712,22 @@ LIRGeneratorARM::visitAsmJSLoadHeap(MAsmJSLoadHeap* ins)
// For the ARM it is best to keep the 'base' in a register if a bounds check is needed.
LAllocation baseAlloc;
LAllocation limitAlloc;
if (base->isConstant() && !ins->needsBoundsCheck()) {
// A bounds check is only skipped for a positive index.
MOZ_ASSERT(base->toConstant()->toInt32() >= 0);
baseAlloc = LAllocation(base->toConstant());
} else {
baseAlloc = useRegisterAtStart(base);
if (ins->needsBoundsCheck()) {
MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
MOZ_ASSERT(boundsCheckLimit->type() == MIRType::Int32);
limitAlloc = useRegisterAtStart(boundsCheckLimit);
}
}
define(new(alloc()) LAsmJSLoadHeap(baseAlloc), ins);
define(new(alloc()) LAsmJSLoadHeap(baseAlloc, limitAlloc), ins);
}
void
@ -730,16 +737,24 @@ LIRGeneratorARM::visitAsmJSStoreHeap(MAsmJSStoreHeap* ins)
MDefinition* base = ins->base();
MOZ_ASSERT(base->type() == MIRType::Int32);
LAllocation baseAlloc;
LAllocation limitAlloc;
if (base->isConstant() && !ins->needsBoundsCheck()) {
MOZ_ASSERT(base->toConstant()->toInt32() >= 0);
baseAlloc = LAllocation(base->toConstant());
} else {
baseAlloc = useRegisterAtStart(base);
if (ins->needsBoundsCheck()) {
MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
MOZ_ASSERT(boundsCheckLimit->type() == MIRType::Int32);
limitAlloc = useRegisterAtStart(boundsCheckLimit);
}
}
add(new(alloc()) LAsmJSStoreHeap(baseAlloc, useRegisterAtStart(ins->value())), ins);
add(new(alloc()) LAsmJSStoreHeap(baseAlloc, useRegisterAtStart(ins->value()), limitAlloc),
ins);
}
void

View File

@ -2127,31 +2127,21 @@ MacroAssembler::clampIntToUint8(Register reg)
template <class L>
void
MacroAssembler::wasmBoundsCheck(Condition cond, Register index, L label)
MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
{
BufferOffset bo = as_cmp(index, Imm8(0));
append(wasm::BoundsCheck(bo.getOffset()));
as_cmp(index, O2Reg(boundsCheckLimit));
as_b(label, cond);
}
template <class L>
void
MacroAssembler::wasmPatchBoundsCheck(uint8_t* patchAt, uint32_t limit)
MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCheckLimit, L label)
{
Instruction* inst = (Instruction*) patchAt;
MOZ_ASSERT(inst->is<InstCMP>());
InstCMP* cmp = inst->as<InstCMP>();
Register index;
cmp->extractOp1(&index);
MOZ_ASSERT(cmp->extractOp2().isImm8());
Imm8 imm8 = Imm8(limit);
MOZ_RELEASE_ASSERT(!imm8.invalid());
*inst = InstALU(InvalidReg, index, imm8, OpCmp, SetCC, Always);
// Don't call Auto Flush Cache; the wasm caller has done this for us.
ScratchRegisterScope scratch(*this);
MOZ_ASSERT(boundsCheckLimit.offset == offsetof(wasm::TlsData, boundsCheckLimit));
ma_ldr(DTRAddr(boundsCheckLimit.base, DtrOffImm(boundsCheckLimit.offset)), scratch);
as_cmp(index, O2Reg(scratch));
as_b(label, cond);
}
//}}} check_macroassembler_style

View File

@ -297,6 +297,8 @@ class Assembler : public vixl::Assembler
static bool SupportsUnalignedAccesses() { return true; }
static bool SupportsSimd() { return js::jit::SupportsSimd; }
static bool HasRoundInstruction(RoundingMode mode) { return false; }
// Tracks a jump that is patchable after finalization.
void addJumpRelocation(BufferOffset src, Relocation::Kind reloc);

View File

@ -1708,13 +1708,14 @@ MacroAssembler::clampIntToUint8(Register reg)
template <class L>
void
MacroAssembler::wasmBoundsCheck(Condition cond, Register index, L label)
MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
{
MOZ_CRASH("NYI");
}
template <class L>
void
MacroAssembler::wasmPatchBoundsCheck(uint8_t* patchAt, uint32_t limit)
MacroAssembler::wasmBoundsCheck(Condition cond, Register index, Address boundsCheckLimit, L label)
{
MOZ_CRASH("NYI");
}

View File

@ -1238,6 +1238,10 @@ class AssemblerMIPSShared : public AssemblerShared
return js::jit::SupportsSimd;
}
static bool HasRoundInstruction(RoundingMode mode) {
return false;
}
protected:
InstImm invertBranch(InstImm branch, BOffImm16 skipOffset);
void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) {

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