Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2017-02-20 14:12:30 +01:00
Родитель fdb5c9d7cb 9857d2af8e
Коммит 85079555b0
281 изменённых файлов: 6980 добавлений и 3357 удалений

Просмотреть файл

@ -26,7 +26,6 @@ const {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {})
// use to select our configuration. // use to select our configuration.
if (gTestPath.includes("test-oop-extensions")) { if (gTestPath.includes("test-oop-extensions")) {
SpecialPowers.pushPrefEnv({set: [ SpecialPowers.pushPrefEnv({set: [
["dom.ipc.processCount.extension", 1],
["extensions.webextensions.remote", true], ["extensions.webextensions.remote", true],
]}); ]});
// We don't want to reset this at the end of the test, so that we don't have // We don't want to reset this at the end of the test, so that we don't have

Просмотреть файл

@ -3,6 +3,7 @@ import shutil
import time import time
from marionette_harness import MarionetteTestCase from marionette_harness import MarionetteTestCase
from marionette_driver.errors import NoAlertPresentException
class TestFirefoxRefresh(MarionetteTestCase): class TestFirefoxRefresh(MarionetteTestCase):
@ -269,11 +270,17 @@ class TestFirefoxRefresh(MarionetteTestCase):
""") """)
self.assertSequenceEqual(tabURIs, ["about:welcomeback"]) self.assertSequenceEqual(tabURIs, ["about:welcomeback"])
# Dismiss modal dialog if any. This is mainly to dismiss the check for
# default browser dialog if it shows up.
try:
alert = self.marionette.switch_to_alert()
alert.dismiss()
except NoAlertPresentException:
pass
tabURIs = self.runAsyncCode(""" tabURIs = self.runAsyncCode("""
let mm = gBrowser.selectedBrowser.messageManager; let mm = gBrowser.selectedBrowser.messageManager;
let fs = function() {
content.document.getElementById("errorTryAgain").click();
};
let {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {}); let {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
window.addEventListener("SSWindowStateReady", function testSSPostReset() { window.addEventListener("SSWindowStateReady", function testSSPostReset() {
window.removeEventListener("SSWindowStateReady", testSSPostReset, false); window.removeEventListener("SSWindowStateReady", testSSPostReset, false);
@ -281,6 +288,17 @@ class TestFirefoxRefresh(MarionetteTestCase):
marionetteScriptFinished([... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec)); marionetteScriptFinished([... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec));
}); });
}, false); }, false);
let fs = function() {
if (content.document.readyState === "complete") {
content.document.getElementById("errorTryAgain").click();
} else {
content.window.addEventListener("load", function(event) {
content.document.getElementById("errorTryAgain").click();
}, { once: true });
}
};
mm.loadFrameScript("data:application/javascript,(" + fs.toString() + ")()", true); mm.loadFrameScript("data:application/javascript,(" + fs.toString() + ")()", true);
""") """)
self.assertSequenceEqual(tabURIs, self._expectedURLs) self.assertSequenceEqual(tabURIs, self._expectedURLs)

112
browser/extensions/aushelper/bootstrap.js поставляемый
Просмотреть файл

@ -8,8 +8,33 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const APP_UPDATE_URL_PREF = "app.update.url"; const APP_UPDATE_URL_PREF = "app.update.url";
const REPLACE_KEY = "%OS_VERSION%"; const REPLACE_KEY = "%OS_VERSION%";
const AUSHELPER_CPU_RESULT_CODE_HISTOGRAM_ID = "AUSHELPER_CPU_RESULT_CODE";
// The system is not vulnerable to Bug 1296630.
const CPU_NO_BUG1296630 = 1;
// The system is vulnerable to Bug 1296630.
const CPU_YES_BUG1296630 = 2;
// An error occured when checking if the system is vulnerable to Bug 1296630.
const CPU_ERR_BUG1296630 = 3;
// It is unknown whether the system is vulnerable to Bug 1296630 (should never happen).
const CPU_UNKNOWN_BUG1296630 = 4;
const AUSHELPER_CPU_ERROR_CODE_HISTOGRAM_ID = "AUSHELPER_CPU_ERROR_CODE";
const CPU_SUCCESS = 0;
const CPU_REG_OPEN_ERROR = 1;
const CPU_VENDOR_ID_ERROR = 2;
const CPU_ID_ERROR = 4;
const CPU_REV_ERROR = 8;
const AUSHELPER_WEBSENSE_REG_VERSION_SCALAR_NAME = "aushelper.websense_reg_version";
const AUSHELPER_WEBSENSE_REG_EXISTS_HISTOGRAM_ID = "AUSHELPER_WEBSENSE_REG_EXISTS";
const AUSHELPER_WEBSENSE_ERROR_CODE_HISTOGRAM_ID = "AUSHELPER_WEBSENSE_ERROR_CODE";
const WEBSENSE_SUCCESS = 0;
const WEBSENSE_REG_OPEN_ERROR = 1;
const WEBSENSE_REG_READ_ERROR = 2;
const WEBSENSE_ALREADY_MODIFIED = 4;
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/TelemetryLog.jsm");
function startup() { function startup() {
if (Services.appinfo.OS != "WINNT") { if (Services.appinfo.OS != "WINNT") {
@ -18,12 +43,13 @@ function startup() {
const regCPUPath = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; const regCPUPath = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
let wrk; let wrk;
let cpuErrorCode = CPU_SUCCESS;
try { try {
wrk = Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey); wrk = Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, regCPUPath, wrk.ACCESS_READ); wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, regCPUPath, wrk.ACCESS_READ);
} catch (e) { } catch (e) {
Cu.reportError("Unable to open registry. Exception: " + e); Cu.reportError("AUSHelper - unable to open registry. Exception: " + e);
TelemetryLog.log("AUSHELPER_FATAL_ERROR", [e]); cpuErrorCode |= CPU_REG_OPEN_ERROR;
} }
// If any of the following values are successfully retrieved and they don't // If any of the following values are successfully retrieved and they don't
@ -41,9 +67,9 @@ function startup() {
cpuVendorIDMatch = true; cpuVendorIDMatch = true;
} }
} catch (e) { } catch (e) {
Cu.reportError("AUSHelper - error getting CPU vendor indentifier. Exception: " + e);
cpuVendorIDMatch = null; cpuVendorIDMatch = null;
Cu.reportError("Error getting CPU vendor indentifier. Exception: " + e); cpuErrorCode |= CPU_VENDOR_ID_ERROR;
TelemetryLog.log("AUSHELPER_CPU_VENDOR_ID_ERROR", [e]);
} }
let cpuIDMatch = false; let cpuIDMatch = false;
@ -53,9 +79,9 @@ function startup() {
cpuIDMatch = true; cpuIDMatch = true;
} }
} catch (e) { } catch (e) {
Cu.reportError("AUSHelper - error getting CPU indentifier. Exception: " + e);
cpuIDMatch = null; cpuIDMatch = null;
Cu.reportError("Error getting CPU indentifier. Exception: " + e); cpuErrorCode |= CPU_ID_ERROR;
TelemetryLog.log("AUSHELPER_CPU_ID_ERROR", [e]);
} }
let microCodeVersions = [0xe, 0x11, 0x12, 0x13, 0x16, 0x18, 0x19]; let microCodeVersions = [0xe, 0x11, 0x12, 0x13, 0x16, 0x18, 0x19];
@ -67,8 +93,8 @@ function startup() {
let regVal = wrk.readBinaryValue(keyNames[i]); let regVal = wrk.readBinaryValue(keyNames[i]);
if (regVal.length == 8) { if (regVal.length == 8) {
let hexVal = []; let hexVal = [];
// We are only inyterested in the highest byte and return the little // We are only inyterested in the upper 4 bytes and the little endian
// endian value for it. // value for it.
for (let j = 4; j < 8; j++) { for (let j = 4; j < 8; j++) {
let c = regVal.charCodeAt(j).toString(16); let c = regVal.charCodeAt(j).toString(16);
if (c.length == 1) { if (c.length == 1) {
@ -86,44 +112,78 @@ function startup() {
if (i == keyNames.length - 1) { if (i == keyNames.length - 1) {
// The registry key name's value was not successfully queried. // The registry key name's value was not successfully queried.
cpuRevMatch = null; cpuRevMatch = null;
TelemetryLog.log("AUSHELPER_CPU_REV_ERROR", [e]); cpuErrorCode |= CPU_REV_ERROR;
} }
} }
} }
wrk.close();
} catch (ex) { } catch (ex) {
Cu.reportError("AUSHelper - error getting CPU revision. Exception: " + ex);
cpuRevMatch = null; cpuRevMatch = null;
Cu.reportError("Error getting CPU revision. Exception: " + ex); cpuErrorCode |= CPU_REV_ERROR;
TelemetryLog.log("AUSHELPER_CPU_REV_ERROR", [ex]);
} }
let resultCode = 3; let cpuResult = CPU_UNKNOWN_BUG1296630;
let newValue = "(unkBug1296630v1)"; let cpuValue = "(unkBug1296630v1)";
// The following uses strict equality checks since the values can be true, // The following uses strict equality checks since the values can be true,
// false, or null. // false, or null.
if (cpuVendorIDMatch === false || cpuIDMatch === false || cpuRevMatch === false) { if (cpuVendorIDMatch === false || cpuIDMatch === false || cpuRevMatch === false) {
// Since one of the values is false then the system won't be affected by // Since one of the values is false then the system won't be affected by
// bug 1296630 according to the conditions set out in bug 1311515. // bug 1296630 according to the conditions set out in bug 1311515.
newValue = "(noBug1296630v1)"; cpuValue = "(noBug1296630v1)";
resultCode = 0; cpuResult = CPU_NO_BUG1296630;
} else if (cpuVendorIDMatch === null || cpuIDMatch === null || cpuRevMatch === null) { } else if (cpuVendorIDMatch === null || cpuIDMatch === null || cpuRevMatch === null) {
// Since one of the values is null we can't say for sure if the system will // Since one of the values is null we can't say for sure if the system will
// be affected by bug 1296630. // be affected by bug 1296630.
newValue = "(errBug1296630v1)"; cpuValue = "(errBug1296630v1)";
resultCode = 2; cpuResult = CPU_ERR_BUG1296630;
} else if (cpuVendorIDMatch === true && cpuIDMatch === true && cpuRevMatch === true) { } else if (cpuVendorIDMatch === true && cpuIDMatch === true && cpuRevMatch === true) {
// Since all of the values are true we can say that the system will be // Since all of the values are true we can say that the system will be
// affected by bug 1296630. // affected by bug 1296630.
newValue = "(yesBug1296630v1)"; cpuValue = "(yesBug1296630v1)";
resultCode = 1; cpuResult = CPU_YES_BUG1296630;
} }
let defaultBranch = Services.prefs.getDefaultBranch(""); Services.telemetry.getHistogramById(AUSHELPER_CPU_RESULT_CODE_HISTOGRAM_ID).add(cpuResult);
let curPrefValue = defaultBranch.getCharPref(APP_UPDATE_URL_PREF); Services.telemetry.getHistogramById(AUSHELPER_CPU_ERROR_CODE_HISTOGRAM_ID).add(cpuErrorCode);
let newPrefValue = curPrefValue.replace(REPLACE_KEY + "/", REPLACE_KEY + newValue + "/");
defaultBranch.setCharPref(APP_UPDATE_URL_PREF, newPrefValue);
TelemetryLog.log("AUSHELPER_RESULT", [resultCode]);
}
const regWebsensePath = "Websense\\Agent";
let websenseErrorCode = WEBSENSE_SUCCESS;
let websenseVersion = "";
try {
let regModes = [wrk.ACCESS_READ, wrk.ACCESS_READ | wrk.WOW64_64];
for (let i = 0; i < regModes.length; ++i) {
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, "SOFTWARE", regModes[i]);
try {
if (wrk.hasChild(regWebsensePath)) {
let childKey = wrk.openChild(regWebsensePath, wrk.ACCESS_READ);
websenseVersion = childKey.readStringValue("InstallVersion");
Services.telemetry.scalarSet(AUSHELPER_WEBSENSE_REG_VERSION_SCALAR_NAME, websenseVersion);
}
wrk.close();
} catch (e) {
Cu.reportError("AUSHelper - unable to read registry. Exception: " + e);
websenseErrorCode |= WEBSENSE_REG_READ_ERROR;
}
}
} catch (ex) {
Cu.reportError("AUSHelper - unable to open registry. Exception: " + ex);
websenseErrorCode |= WEBSENSE_REG_OPEN_ERROR;
}
Services.telemetry.getHistogramById(AUSHELPER_WEBSENSE_REG_EXISTS_HISTOGRAM_ID).add(!!websenseVersion);
let websenseValue = "(" + (websenseVersion ? "websense-" + websenseVersion : "nowebsense") + ")";
let branch = Services.prefs.getDefaultBranch("");
let curValue = branch.getCharPref(APP_UPDATE_URL_PREF);
if (curValue.indexOf(REPLACE_KEY + "/") > -1) {
let newValue = curValue.replace(REPLACE_KEY + "/", REPLACE_KEY + cpuValue + websenseValue + "/");
branch.setCharPref(APP_UPDATE_URL_PREF, newValue);
} else {
websenseErrorCode |= WEBSENSE_ALREADY_MODIFIED;
}
Services.telemetry.getHistogramById(AUSHELPER_WEBSENSE_ERROR_CODE_HISTOGRAM_ID).add(websenseErrorCode);
}
function shutdown() {} function shutdown() {}
function install() {} function install() {}
function uninstall() {} function uninstall() {}

Просмотреть файл

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest"> <Description about="urn:mozilla:install-manifest">
<em:id>aushelper@mozilla.org</em:id> <em:id>aushelper@mozilla.org</em:id>
<em:version>1.0</em:version> <em:version>2.0</em:version>
<em:type>2</em:type> <em:type>2</em:type>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible> <em:multiprocessCompatible>true</em:multiprocessCompatible>

Просмотреть файл

@ -1,3 +1,3 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 1.7.290 Current extension version is: 1.7.297

Просмотреть файл

@ -3632,8 +3632,8 @@ var _UnsupportedManager = function UnsupportedManagerClosure() {
} }
}; };
}(); }();
exports.version = '1.7.290'; exports.version = '1.7.297';
exports.build = 'b509a3f8'; exports.build = '425ad309';
exports.getDocument = getDocument; exports.getDocument = getDocument;
exports.PDFDataRangeTransport = PDFDataRangeTransport; exports.PDFDataRangeTransport = PDFDataRangeTransport;
exports.PDFWorker = PDFWorker; exports.PDFWorker = PDFWorker;
@ -4650,8 +4650,8 @@ if (!globalScope.PDFJS) {
globalScope.PDFJS = {}; globalScope.PDFJS = {};
} }
var PDFJS = globalScope.PDFJS; var PDFJS = globalScope.PDFJS;
PDFJS.version = '1.7.290'; PDFJS.version = '1.7.297';
PDFJS.build = 'b509a3f8'; PDFJS.build = '425ad309';
PDFJS.pdfBug = false; PDFJS.pdfBug = false;
if (PDFJS.verbosity !== undefined) { if (PDFJS.verbosity !== undefined) {
sharedUtil.setVerbosityLevel(PDFJS.verbosity); sharedUtil.setVerbosityLevel(PDFJS.verbosity);
@ -7143,8 +7143,8 @@ exports.TilingPattern = TilingPattern;
"use strict"; "use strict";
var pdfjsVersion = '1.7.290'; var pdfjsVersion = '1.7.297';
var pdfjsBuild = 'b509a3f8'; var pdfjsBuild = '425ad309';
var pdfjsSharedUtil = __w_pdfjs_require__(0); var pdfjsSharedUtil = __w_pdfjs_require__(0);
var pdfjsDisplayGlobal = __w_pdfjs_require__(8); var pdfjsDisplayGlobal = __w_pdfjs_require__(8);
var pdfjsDisplayAPI = __w_pdfjs_require__(3); var pdfjsDisplayAPI = __w_pdfjs_require__(3);

Просмотреть файл

@ -88,7 +88,7 @@ return /******/ (function(modules) { // webpackBootstrap
/******/ __w_pdfjs_require__.p = ""; /******/ __w_pdfjs_require__.p = "";
/******/ // Load entry module and return exports /******/ // Load entry module and return exports
/******/ return __w_pdfjs_require__(__w_pdfjs_require__.s = 36); /******/ return __w_pdfjs_require__(__w_pdfjs_require__.s = 35);
/******/ }) /******/ })
/************************************************************************/ /************************************************************************/
/******/ ([ /******/ ([
@ -1732,8 +1732,8 @@ exports.isStream = isStream;
var sharedUtil = __w_pdfjs_require__(0); var sharedUtil = __w_pdfjs_require__(0);
var corePrimitives = __w_pdfjs_require__(1); var corePrimitives = __w_pdfjs_require__(1);
var coreJbig2 = __w_pdfjs_require__(28); var coreJbig2 = __w_pdfjs_require__(27);
var coreJpg = __w_pdfjs_require__(29); var coreJpg = __w_pdfjs_require__(28);
var coreJpx = __w_pdfjs_require__(13); var coreJpx = __w_pdfjs_require__(13);
var Util = sharedUtil.Util; var Util = sharedUtil.Util;
var error = sharedUtil.error; var error = sharedUtil.error;
@ -12357,7 +12357,7 @@ exports.Parser = Parser;
var sharedUtil = __w_pdfjs_require__(0); var sharedUtil = __w_pdfjs_require__(0);
var corePrimitives = __w_pdfjs_require__(1); var corePrimitives = __w_pdfjs_require__(1);
var corePsParser = __w_pdfjs_require__(34); var corePsParser = __w_pdfjs_require__(33);
var error = sharedUtil.error; var error = sharedUtil.error;
var info = sharedUtil.info; var info = sharedUtil.info;
var isArray = sharedUtil.isArray; var isArray = sharedUtil.isArray;
@ -18279,7 +18279,7 @@ exports.ArithmeticDecoder = ArithmeticDecoder;
"use strict"; "use strict";
var sharedUtil = __w_pdfjs_require__(0); var sharedUtil = __w_pdfjs_require__(0);
var coreCharsets = __w_pdfjs_require__(22); var coreCharsets = __w_pdfjs_require__(21);
var coreEncodings = __w_pdfjs_require__(4); var coreEncodings = __w_pdfjs_require__(4);
var error = sharedUtil.error; var error = sharedUtil.error;
var info = sharedUtil.info; var info = sharedUtil.info;
@ -24768,15 +24768,15 @@ var sharedUtil = __w_pdfjs_require__(0);
var corePrimitives = __w_pdfjs_require__(1); var corePrimitives = __w_pdfjs_require__(1);
var coreStream = __w_pdfjs_require__(2); var coreStream = __w_pdfjs_require__(2);
var coreParser = __w_pdfjs_require__(5); var coreParser = __w_pdfjs_require__(5);
var coreImage = __w_pdfjs_require__(27); var coreImage = __w_pdfjs_require__(26);
var coreColorSpace = __w_pdfjs_require__(3); var coreColorSpace = __w_pdfjs_require__(3);
var coreMurmurHash3 = __w_pdfjs_require__(31); var coreMurmurHash3 = __w_pdfjs_require__(30);
var coreFonts = __w_pdfjs_require__(26); var coreFonts = __w_pdfjs_require__(25);
var coreFunction = __w_pdfjs_require__(6); var coreFunction = __w_pdfjs_require__(6);
var corePattern = __w_pdfjs_require__(32); var corePattern = __w_pdfjs_require__(31);
var coreCMap = __w_pdfjs_require__(23); var coreCMap = __w_pdfjs_require__(22);
var coreMetrics = __w_pdfjs_require__(30); var coreMetrics = __w_pdfjs_require__(29);
var coreBidi = __w_pdfjs_require__(21); var coreBidi = __w_pdfjs_require__(20);
var coreEncodings = __w_pdfjs_require__(4); var coreEncodings = __w_pdfjs_require__(4);
var coreStandardFonts = __w_pdfjs_require__(15); var coreStandardFonts = __w_pdfjs_require__(15);
var coreUnicode = __w_pdfjs_require__(16); var coreUnicode = __w_pdfjs_require__(16);
@ -33906,10 +33906,10 @@ exports.getUnicodeForGlyph = getUnicodeForGlyph;
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
/* WEBPACK VAR INJECTION */(function(module) {
var sharedUtil = __w_pdfjs_require__(0); var sharedUtil = __w_pdfjs_require__(0);
var corePrimitives = __w_pdfjs_require__(1); var corePrimitives = __w_pdfjs_require__(1);
var corePdfManager = __w_pdfjs_require__(33); var corePdfManager = __w_pdfjs_require__(32);
var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES; var UNSUPPORTED_FEATURES = sharedUtil.UNSUPPORTED_FEATURES;
var InvalidPDFException = sharedUtil.InvalidPDFException; var InvalidPDFException = sharedUtil.InvalidPDFException;
var MessageHandler = sharedUtil.MessageHandler; var MessageHandler = sharedUtil.MessageHandler;
@ -34588,13 +34588,18 @@ function initializeWorker() {
WorkerMessageHandler.setup(handler, self); WorkerMessageHandler.setup(handler, self);
handler.send('ready', null); handler.send('ready', null);
} }
if (typeof window === 'undefined' && !(typeof module !== 'undefined' && module.require)) { function isNodeJS() {
if (typeof __pdfjsdev_webpack__ === 'undefined') {
return typeof process === 'object' && process + '' === '[object process]';
}
return false;
}
if (typeof window === 'undefined' && !isNodeJS()) {
initializeWorker(); initializeWorker();
} }
exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass; exports.setPDFNetworkStreamClass = setPDFNetworkStreamClass;
exports.WorkerTask = WorkerTask; exports.WorkerTask = WorkerTask;
exports.WorkerMessageHandler = WorkerMessageHandler; exports.WorkerMessageHandler = WorkerMessageHandler;
/* WEBPACK VAR INJECTION */}.call(exports, __w_pdfjs_require__(19)(module)))
/***/ }), /***/ }),
/* 18 */ /* 18 */
@ -34614,34 +34619,6 @@ module.exports = g;
/***/ }), /***/ }),
/* 19 */ /* 19 */
/***/ (function(module, exports) {
module.exports = function (module) {
if (!module.webpackPolyfill) {
module.deprecate = function () {
};
module.paths = [];
if (!module.children)
module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function () {
return module.l;
}
});
Object.defineProperty(module, "id", {
enumerable: true,
get: function () {
return module.i;
}
});
module.webpackPolyfill = 1;
}
return module;
};
/***/ }),
/* 20 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -34667,6 +34644,7 @@ var Dict = corePrimitives.Dict;
var isDict = corePrimitives.isDict; var isDict = corePrimitives.isDict;
var isName = corePrimitives.isName; var isName = corePrimitives.isName;
var isRef = corePrimitives.isRef; var isRef = corePrimitives.isRef;
var isStream = corePrimitives.isStream;
var Stream = coreStream.Stream; var Stream = coreStream.Stream;
var ColorSpace = coreColorSpace.ColorSpace; var ColorSpace = coreColorSpace.ColorSpace;
var Catalog = coreObj.Catalog; var Catalog = coreObj.Catalog;
@ -34760,30 +34738,13 @@ var Annotation = function AnnotationClosure() {
rect[1] - minY * yRatio rect[1] - minY * yRatio
]; ];
} }
function getDefaultAppearance(dict) {
var appearanceState = dict.get('AP');
if (!isDict(appearanceState)) {
return;
}
var appearance;
var appearances = appearanceState.get('N');
if (isDict(appearances)) {
var as = dict.get('AS');
if (as && appearances.has(as.name)) {
appearance = appearances.get(as.name);
}
} else {
appearance = appearances;
}
return appearance;
}
function Annotation(params) { function Annotation(params) {
var dict = params.dict; var dict = params.dict;
this.setFlags(dict.get('F')); this.setFlags(dict.get('F'));
this.setRectangle(dict.getArray('Rect')); this.setRectangle(dict.getArray('Rect'));
this.setColor(dict.getArray('C')); this.setColor(dict.getArray('C'));
this.setBorderStyle(dict); this.setBorderStyle(dict);
this.appearance = getDefaultAppearance(dict); this.setAppearance(dict);
this.data = {}; this.data = {};
this.data.id = params.id; this.data.id = params.id;
this.data.subtype = params.subtype; this.data.subtype = params.subtype;
@ -34887,6 +34848,26 @@ var Annotation = function AnnotationClosure() {
this.borderStyle.setWidth(0); this.borderStyle.setWidth(0);
} }
}, },
setAppearance: function Annotation_setAppearance(dict) {
this.appearance = null;
var appearanceStates = dict.get('AP');
if (!isDict(appearanceStates)) {
return;
}
var normalAppearanceState = appearanceStates.get('N');
if (isStream(normalAppearanceState)) {
this.appearance = normalAppearanceState;
return;
}
if (!isDict(normalAppearanceState)) {
return;
}
var as = dict.get('AS');
if (!isName(as) || !normalAppearanceState.has(as.name)) {
return;
}
this.appearance = normalAppearanceState.get(as.name);
},
_preparePopup: function Annotation_preparePopup(dict) { _preparePopup: function Annotation_preparePopup(dict) {
if (!dict.has('C')) { if (!dict.has('C')) {
this.data.color = null; this.data.color = null;
@ -35332,7 +35313,7 @@ exports.AnnotationBorderStyle = AnnotationBorderStyle;
exports.AnnotationFactory = AnnotationFactory; exports.AnnotationFactory = AnnotationFactory;
/***/ }), /***/ }),
/* 21 */ /* 20 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -36085,7 +36066,7 @@ function bidi(str, startLevel, vertical) {
exports.bidi = bidi; exports.bidi = bidi;
/***/ }), /***/ }),
/* 22 */ /* 21 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -36583,7 +36564,7 @@ exports.ExpertCharset = ExpertCharset;
exports.ExpertSubsetCharset = ExpertSubsetCharset; exports.ExpertSubsetCharset = ExpertSubsetCharset;
/***/ }), /***/ }),
/* 23 */ /* 22 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -37488,7 +37469,7 @@ exports.CMapFactory = CMapFactory;
exports.IdentityCMap = IdentityCMap; exports.IdentityCMap = IdentityCMap;
/***/ }), /***/ }),
/* 24 */ /* 23 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -37500,7 +37481,7 @@ var coreObj = __w_pdfjs_require__(14);
var coreParser = __w_pdfjs_require__(5); var coreParser = __w_pdfjs_require__(5);
var coreCrypto = __w_pdfjs_require__(11); var coreCrypto = __w_pdfjs_require__(11);
var coreEvaluator = __w_pdfjs_require__(12); var coreEvaluator = __w_pdfjs_require__(12);
var coreAnnotation = __w_pdfjs_require__(20); var coreAnnotation = __w_pdfjs_require__(19);
var MissingDataException = sharedUtil.MissingDataException; var MissingDataException = sharedUtil.MissingDataException;
var Util = sharedUtil.Util; var Util = sharedUtil.Util;
var assert = sharedUtil.assert; var assert = sharedUtil.assert;
@ -37988,7 +37969,7 @@ exports.Page = Page;
exports.PDFDocument = PDFDocument; exports.PDFDocument = PDFDocument;
/***/ }), /***/ }),
/* 25 */ /* 24 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -38774,7 +38755,7 @@ var FontRendererFactory = function FontRendererFactoryClosure() {
exports.FontRendererFactory = FontRendererFactory; exports.FontRendererFactory = FontRendererFactory;
/***/ }), /***/ }),
/* 26 */ /* 25 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -38783,11 +38764,11 @@ var sharedUtil = __w_pdfjs_require__(0);
var corePrimitives = __w_pdfjs_require__(1); var corePrimitives = __w_pdfjs_require__(1);
var coreStream = __w_pdfjs_require__(2); var coreStream = __w_pdfjs_require__(2);
var coreGlyphList = __w_pdfjs_require__(7); var coreGlyphList = __w_pdfjs_require__(7);
var coreFontRenderer = __w_pdfjs_require__(25); var coreFontRenderer = __w_pdfjs_require__(24);
var coreEncodings = __w_pdfjs_require__(4); var coreEncodings = __w_pdfjs_require__(4);
var coreStandardFonts = __w_pdfjs_require__(15); var coreStandardFonts = __w_pdfjs_require__(15);
var coreUnicode = __w_pdfjs_require__(16); var coreUnicode = __w_pdfjs_require__(16);
var coreType1Parser = __w_pdfjs_require__(35); var coreType1Parser = __w_pdfjs_require__(34);
var coreCFFParser = __w_pdfjs_require__(9); var coreCFFParser = __w_pdfjs_require__(9);
var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX; var FONT_IDENTITY_MATRIX = sharedUtil.FONT_IDENTITY_MATRIX;
var FontType = sharedUtil.FontType; var FontType = sharedUtil.FontType;
@ -40003,7 +39984,7 @@ var Font = function FontClosure() {
useTable = true; useTable = true;
} else if (platformId === 1 && encodingId === 0) { } else if (platformId === 1 && encodingId === 0) {
useTable = true; useTable = true;
} else if (platformId === 3 && encodingId === 1 && (!isSymbolicFont && hasEncoding || !potentialTable)) { } else if (platformId === 3 && encodingId === 1 && (hasEncoding || !potentialTable)) {
useTable = true; useTable = true;
if (!isSymbolicFont) { if (!isSymbolicFont) {
canBreak = true; canBreak = true;
@ -41740,7 +41721,7 @@ exports.ToUnicodeMap = ToUnicodeMap;
exports.getFontType = getFontType; exports.getFontType = getFontType;
/***/ }), /***/ }),
/* 27 */ /* 26 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -42231,7 +42212,7 @@ var PDFImage = function PDFImageClosure() {
exports.PDFImage = PDFImage; exports.PDFImage = PDFImage;
/***/ }), /***/ }),
/* 28 */ /* 27 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -43432,7 +43413,7 @@ var Jbig2Image = function Jbig2ImageClosure() {
exports.Jbig2Image = Jbig2Image; exports.Jbig2Image = Jbig2Image;
/***/ }), /***/ }),
/* 29 */ /* 28 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -44349,7 +44330,7 @@ var JpegImage = function JpegImageClosure() {
exports.JpegImage = JpegImage; exports.JpegImage = JpegImage;
/***/ }), /***/ }),
/* 30 */ /* 29 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -47297,7 +47278,7 @@ var getMetrics = getLookupTableFactory(function (t) {
exports.getMetrics = getMetrics; exports.getMetrics = getMetrics;
/***/ }), /***/ }),
/* 31 */ /* 30 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -47418,7 +47399,7 @@ var MurmurHash3_64 = function MurmurHash3_64Closure(seed) {
exports.MurmurHash3_64 = MurmurHash3_64; exports.MurmurHash3_64 = MurmurHash3_64;
/***/ }), /***/ }),
/* 32 */ /* 31 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -48257,7 +48238,7 @@ exports.Pattern = Pattern;
exports.getTilingPatternIR = getTilingPatternIR; exports.getTilingPatternIR = getTilingPatternIR;
/***/ }), /***/ }),
/* 33 */ /* 32 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -48265,7 +48246,7 @@ exports.getTilingPatternIR = getTilingPatternIR;
var sharedUtil = __w_pdfjs_require__(0); var sharedUtil = __w_pdfjs_require__(0);
var coreStream = __w_pdfjs_require__(2); var coreStream = __w_pdfjs_require__(2);
var coreChunkedStream = __w_pdfjs_require__(10); var coreChunkedStream = __w_pdfjs_require__(10);
var coreDocument = __w_pdfjs_require__(24); var coreDocument = __w_pdfjs_require__(23);
var warn = sharedUtil.warn; var warn = sharedUtil.warn;
var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl;
var shadow = sharedUtil.shadow; var shadow = sharedUtil.shadow;
@ -48443,7 +48424,7 @@ exports.LocalPdfManager = LocalPdfManager;
exports.NetworkPdfManager = NetworkPdfManager; exports.NetworkPdfManager = NetworkPdfManager;
/***/ }), /***/ }),
/* 34 */ /* 33 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -48642,7 +48623,7 @@ exports.PostScriptLexer = PostScriptLexer;
exports.PostScriptParser = PostScriptParser; exports.PostScriptParser = PostScriptParser;
/***/ }), /***/ }),
/* 35 */ /* 34 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
@ -49188,13 +49169,13 @@ var Type1Parser = function Type1ParserClosure() {
exports.Type1Parser = Type1Parser; exports.Type1Parser = Type1Parser;
/***/ }), /***/ }),
/* 36 */ /* 35 */
/***/ (function(module, exports, __w_pdfjs_require__) { /***/ (function(module, exports, __w_pdfjs_require__) {
"use strict"; "use strict";
var pdfjsVersion = '1.7.290'; var pdfjsVersion = '1.7.297';
var pdfjsBuild = 'b509a3f8'; var pdfjsBuild = '425ad309';
var pdfjsCoreWorker = __w_pdfjs_require__(17); var pdfjsCoreWorker = __w_pdfjs_require__(17);
; ;
exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler; exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;

Просмотреть файл

@ -1,5 +1,5 @@
{ {
"llvm_revision": "292415", "llvm_revision": "295482",
"stages": "1", "stages": "1",
"build_libcxx": true, "build_libcxx": true,
"build_type": "Release", "build_type": "Release",

Просмотреть файл

@ -1,5 +1,5 @@
{ {
"llvm_revision": "292415", "llvm_revision": "295482",
"stages": "1", "stages": "1",
"build_libcxx": true, "build_libcxx": true,
"build_type": "Release", "build_type": "Release",

Просмотреть файл

@ -1,5 +1,5 @@
{ {
"llvm_revision": "292415", "llvm_revision": "295482",
"stages": "1", "stages": "1",
"build_libcxx": false, "build_libcxx": false,
"build_type": "Release", "build_type": "Release",

Просмотреть файл

@ -1,5 +1,5 @@
{ {
"llvm_revision": "292415", "llvm_revision": "295482",
"stages": "1", "stages": "1",
"build_libcxx": false, "build_libcxx": false,
"build_type": "Release", "build_type": "Release",

Просмотреть файл

@ -7,7 +7,7 @@
// Tests the various highlight command parameters and options // Tests the various highlight command parameters and options
requestLongerTimeout(3); requestLongerTimeout(4);
// Creating a test page with many elements to test the --showall option // Creating a test page with many elements to test the --showall option
var TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>"; var TEST_PAGE = "data:text/html;charset=utf-8,<body><ul>";

Просмотреть файл

@ -1094,50 +1094,9 @@ Inspector.prototype = {
type: "separator", type: "separator",
})); }));
let copySubmenu = new Menu();
copySubmenu.append(new MenuItem({
id: "node-menu-copyinner",
label: INSPECTOR_L10N.getStr("inspectorCopyInnerHTML.label"),
accesskey: INSPECTOR_L10N.getStr("inspectorCopyInnerHTML.accesskey"),
disabled: !isSelectionElement,
click: () => this.copyInnerHTML(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copyouter",
label: INSPECTOR_L10N.getStr("inspectorCopyOuterHTML.label"),
accesskey: INSPECTOR_L10N.getStr("inspectorCopyOuterHTML.accesskey"),
disabled: !isSelectionElement,
click: () => this.copyOuterHTML(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copyuniqueselector",
label: INSPECTOR_L10N.getStr("inspectorCopyCSSSelector.label"),
accesskey:
INSPECTOR_L10N.getStr("inspectorCopyCSSSelector.accesskey"),
disabled: !isSelectionElement,
hidden: !this.canGetUniqueSelector,
click: () => this.copyUniqueSelector(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copycsspath",
label: INSPECTOR_L10N.getStr("inspectorCopyCSSPath.label"),
accesskey:
INSPECTOR_L10N.getStr("inspectorCopyCSSPath.accesskey"),
disabled: !isSelectionElement,
hidden: !this.canGetCssPath,
click: () => this.copyCssPath(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copyimagedatauri",
label: INSPECTOR_L10N.getStr("inspectorImageDataUri.label"),
disabled: !isSelectionElement || !markupContainer ||
!markupContainer.isPreviewable(),
click: () => this.copyImageDataUri(),
}));
menu.append(new MenuItem({ menu.append(new MenuItem({
label: INSPECTOR_L10N.getStr("inspectorCopyHTMLSubmenu.label"), label: INSPECTOR_L10N.getStr("inspectorCopyHTMLSubmenu.label"),
submenu: copySubmenu, submenu: this._getCopySubmenu(markupContainer, isSelectionElement),
})); }));
menu.append(new MenuItem({ menu.append(new MenuItem({
@ -1210,6 +1169,51 @@ Inspector.prototype = {
return menu; return menu;
}, },
_getCopySubmenu: function (markupContainer, isSelectionElement) {
let copySubmenu = new Menu();
copySubmenu.append(new MenuItem({
id: "node-menu-copyinner",
label: INSPECTOR_L10N.getStr("inspectorCopyInnerHTML.label"),
accesskey: INSPECTOR_L10N.getStr("inspectorCopyInnerHTML.accesskey"),
disabled: !isSelectionElement,
click: () => this.copyInnerHTML(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copyouter",
label: INSPECTOR_L10N.getStr("inspectorCopyOuterHTML.label"),
accesskey: INSPECTOR_L10N.getStr("inspectorCopyOuterHTML.accesskey"),
disabled: !isSelectionElement,
click: () => this.copyOuterHTML(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copyuniqueselector",
label: INSPECTOR_L10N.getStr("inspectorCopyCSSSelector.label"),
accesskey:
INSPECTOR_L10N.getStr("inspectorCopyCSSSelector.accesskey"),
disabled: !isSelectionElement,
hidden: !this.canGetUniqueSelector,
click: () => this.copyUniqueSelector(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copycsspath",
label: INSPECTOR_L10N.getStr("inspectorCopyCSSPath.label"),
accesskey:
INSPECTOR_L10N.getStr("inspectorCopyCSSPath.accesskey"),
disabled: !isSelectionElement,
hidden: !this.canGetCssPath,
click: () => this.copyCssPath(),
}));
copySubmenu.append(new MenuItem({
id: "node-menu-copyimagedatauri",
label: INSPECTOR_L10N.getStr("inspectorImageDataUri.label"),
disabled: !isSelectionElement || !markupContainer ||
!markupContainer.isPreviewable(),
click: () => this.copyImageDataUri(),
}));
return copySubmenu;
},
_getPasteSubmenu: function (isEditableElement) { _getPasteSubmenu: function (isEditableElement) {
let isPasteable = isEditableElement && this._getClipboardContentForPaste(); let isPasteable = isEditableElement && this._getClipboardContentForPaste();
let disableAdjacentPaste = !isPasteable || let disableAdjacentPaste = !isPasteable ||
@ -1283,6 +1287,14 @@ Inspector.prototype = {
disabled: !isEditableElement, disabled: !isEditableElement,
click: () => this.onAddAttribute(), click: () => this.onAddAttribute(),
})); }));
attributesSubmenu.append(new MenuItem({
id: "node-menu-copy-attribute",
label: INSPECTOR_L10N.getFormatStr("inspectorCopyAttributeValue.label",
isAttributeClicked ? `"${nodeInfo.value}"` : ""),
accesskey: INSPECTOR_L10N.getStr("inspectorCopyAttributeValue.accesskey"),
disabled: !isAttributeClicked,
click: () => this.onCopyAttributeValue(),
}));
attributesSubmenu.append(new MenuItem({ attributesSubmenu.append(new MenuItem({
id: "node-menu-edit-attribute", id: "node-menu-edit-attribute",
label: INSPECTOR_L10N.getFormatStr("inspectorEditAttribute.label", label: INSPECTOR_L10N.getFormatStr("inspectorEditAttribute.label",
@ -1291,13 +1303,11 @@ Inspector.prototype = {
disabled: !isAttributeClicked, disabled: !isAttributeClicked,
click: () => this.onEditAttribute(), click: () => this.onEditAttribute(),
})); }));
attributesSubmenu.append(new MenuItem({ attributesSubmenu.append(new MenuItem({
id: "node-menu-remove-attribute", id: "node-menu-remove-attribute",
label: INSPECTOR_L10N.getFormatStr("inspectorRemoveAttribute.label", label: INSPECTOR_L10N.getFormatStr("inspectorRemoveAttribute.label",
isAttributeClicked ? `"${nodeInfo.name}"` : ""), isAttributeClicked ? `"${nodeInfo.name}"` : ""),
accesskey: accesskey: INSPECTOR_L10N.getStr("inspectorRemoveAttribute.accesskey"),
INSPECTOR_L10N.getStr("inspectorRemoveAttribute.accesskey"),
disabled: !isAttributeClicked, disabled: !isAttributeClicked,
click: () => this.onRemoveAttribute(), click: () => this.onRemoveAttribute(),
})); }));
@ -1817,6 +1827,14 @@ Inspector.prototype = {
container.addAttribute(); container.addAttribute();
}, },
/**
* Copy attribute value for node.
* Used for node context menu and shouldn't be called directly.
*/
onCopyAttributeValue: function () {
clipboardHelper.copyString(this.nodeMenuTriggerInfo.value);
},
/** /**
* Edit attribute for node. * Edit attribute for node.
* Used for node context menu and shouldn't be called directly. * Used for node context menu and shouldn't be called directly.

Просмотреть файл

@ -215,6 +215,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_rules_selector-highlighter_04.js] [browser_rules_selector-highlighter_04.js]
[browser_rules_selector-highlighter_05.js] [browser_rules_selector-highlighter_05.js]
[browser_rules_selector_highlight.js] [browser_rules_selector_highlight.js]
[browser_rules_shorthand-overridden-lists.js]
[browser_rules_strict-search-filter-computed-list_01.js] [browser_rules_strict-search-filter-computed-list_01.js]
[browser_rules_strict-search-filter_01.js] [browser_rules_strict-search-filter_01.js]
[browser_rules_strict-search-filter_02.js] [browser_rules_strict-search-filter_02.js]

Просмотреть файл

@ -0,0 +1,70 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the rule view shorthand overridden list works correctly,
// can be shown and hidden correctly, and contain the right subproperties.
var TEST_URI = `
<style type="text/css">
div {
margin: 0px 1px 2px 3px;
top: 0px;
}
#testid {
margin-left: 10px;
margin-right: 10px;
}
</style>
<div id="testid">Styled Node</div>
`;
add_task(function* () {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("#testid", inspector);
yield testComputedList(inspector, view);
});
function* testComputedList(inspector, view) {
let rule = getRuleViewRuleEditor(view, 2).rule;
let propEditor = rule.textProps[0].editor;
let expander = propEditor.expander;
let overriddenItems = propEditor.shorthandOverridden.children;
let propNames = [
"margin-right",
"margin-left"
];
ok(!expander.hasAttribute("open"), "margin computed list is closed.");
ok(!propEditor.shorthandOverridden.hasAttribute("hidden"),
"The shorthandOverridden list should be open.");
is(overriddenItems.length, propNames.length,
"There should be 2 overridden shorthand value.");
for (let i = 0; i < propNames.length; i++) {
let overriddenItem = overriddenItems[i].querySelector(".ruleview-propertyname");
is(overriddenItem.textContent, propNames[i],
"The overridden item #" + i + " should be " + propNames[i]);
}
info("Opening the computed list of margin property.");
expander.click();
ok(expander.hasAttribute("open"), "margin computed list is open.");
ok(propEditor.shorthandOverridden.hasAttribute("hidden"),
"The shorthandOverridden list should be hidden.");
info("Closing the computed list of margin property.");
expander.click();
ok(!expander.hasAttribute("open"), "margin computed list is closed.");
ok(!propEditor.shorthandOverridden.hasAttribute("hidden"),
"The shorthandOverridden list should be open.");
for (let i = 0; i < propNames.length; i++) {
let overriddenItem = overriddenItems[i].querySelector(".ruleview-propertyname");
is(overriddenItem.textContent, propNames[i],
"The overridden item #" + i + " should still be " + propNames[i]);
}
}

Просмотреть файл

@ -197,6 +197,12 @@ TextPropertyEditor.prototype = {
class: "ruleview-computedlist", class: "ruleview-computedlist",
}); });
// Holds the viewers for the overridden shorthand properties.
// will be populated in |_updateShorthandOverridden|.
this.shorthandOverridden = createChild(this.element, "ul", {
class: "ruleview-overridden-items",
});
// Only bind event handlers if the rule is editable. // Only bind event handlers if the rule is editable.
if (this.ruleEditor.isEditable) { if (this.ruleEditor.isEditable) {
this.enable.addEventListener("click", this._onEnableClicked, true); this.enable.addEventListener("click", this._onEnableClicked, true);
@ -454,8 +460,9 @@ TextPropertyEditor.prototype = {
elToClick.click(); elToClick.click();
} }
// Populate the computed styles. // Populate the computed styles and shorthand overridden styles.
this._updateComputed(); this._updateComputed();
this._updateShorthandOverridden();
// Update the rule property highlight. // Update the rule property highlight.
this.ruleView._updatePropertyHighlight(this); this.ruleView._updatePropertyHighlight(this);
@ -469,7 +476,7 @@ TextPropertyEditor.prototype = {
/** /**
* Update the visibility of the enable checkbox, the warning indicator and * Update the visibility of the enable checkbox, the warning indicator and
* the filter property, as well as the overriden state of the property. * the filter property, as well as the overridden state of the property.
*/ */
updatePropertyState: function () { updatePropertyState: function () {
if (this.prop.enabled) { if (this.prop.enabled) {
@ -527,8 +534,52 @@ TextPropertyEditor.prototype = {
continue; continue;
} }
let li = createChild(this.computed, "li", { // Store the computed style element for easy access when highlighting
class: "ruleview-computed" // styles
computed.element = this._createComputedListItem(this.computed, computed,
"ruleview-computed");
}
},
/**
* Update the indicator for overridden shorthand styles. The shorthand
* overridden styles themselves are populated on demand, when they
* become visible.
*/
_updateShorthandOverridden: function () {
this.shorthandOverridden.innerHTML = "";
this._populatedShorthandOverridden = false;
this._populateShorthandOverridden();
},
/**
* Populate the list of overridden shorthand styles.
*/
_populateShorthandOverridden: function () {
if (this._populatedShorthandOverridden || this.prop.overridden) {
return;
}
this._populatedShorthandOverridden = true;
for (let computed of this.prop.computed) {
// Don't display duplicate information or show properties
// that are completely overridden.
if (computed.name === this.prop.name || !computed.overridden) {
continue;
}
this._createComputedListItem(this.shorthandOverridden, computed,
"ruleview-overridden-item");
}
},
/**
* Creates and populates a list item with the computed CSS property.
*/
_createComputedListItem: function (parentEl, computed, className) {
let li = createChild(parentEl, "li", {
class: className
}); });
if (computed.overridden) { if (computed.overridden) {
@ -560,10 +611,7 @@ TextPropertyEditor.prototype = {
appendText(li, ";"); appendText(li, ";");
// Store the computed style element for easy access when highlighting return li;
// styles
computed.element = li;
}
}, },
/** /**
@ -593,9 +641,12 @@ TextPropertyEditor.prototype = {
this.expander.removeAttribute("open"); this.expander.removeAttribute("open");
this.computed.removeAttribute("filter-open"); this.computed.removeAttribute("filter-open");
this.computed.removeAttribute("user-open"); this.computed.removeAttribute("user-open");
this.shorthandOverridden.removeAttribute("hidden");
this._populateShorthandOverridden();
} else { } else {
this.expander.setAttribute("open", "true"); this.expander.setAttribute("open", "true");
this.computed.setAttribute("user-open", ""); this.computed.setAttribute("user-open", "");
this.shorthandOverridden.setAttribute("hidden", "true");
this._populateComputed(); this._populateComputed();
} }

Просмотреть файл

@ -35,6 +35,7 @@ const ALL_MENU_ITEMS = [
"node-menu-scrollnodeintoview", "node-menu-scrollnodeintoview",
"node-menu-screenshotnode", "node-menu-screenshotnode",
"node-menu-add-attribute", "node-menu-add-attribute",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
].concat(PASTE_MENU_ITEMS, ACTIVE_ON_DOCTYPE_ITEMS); ].concat(PASTE_MENU_ITEMS, ACTIVE_ON_DOCTYPE_ITEMS);
@ -70,6 +71,7 @@ const TEST_CASES = [
clipboardDataType: "html", clipboardDataType: "html",
disabled: [ disabled: [
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
], ],
@ -86,6 +88,7 @@ const TEST_CASES = [
"node-menu-pasteafter", "node-menu-pasteafter",
"node-menu-pastefirstchild", "node-menu-pastefirstchild",
"node-menu-pastelastchild", "node-menu-pastelastchild",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
], ],
@ -99,6 +102,7 @@ const TEST_CASES = [
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-pastebefore", "node-menu-pastebefore",
"node-menu-pasteafter", "node-menu-pasteafter",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
] ]
@ -109,6 +113,7 @@ const TEST_CASES = [
clipboardDataType: "html", clipboardDataType: "html",
selector: "img", selector: "img",
disabled: [ disabled: [
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
] ]
@ -123,6 +128,7 @@ const TEST_CASES = [
"node-menu-pastebefore", "node-menu-pastebefore",
"node-menu-pasteafter", "node-menu-pasteafter",
"node-menu-screenshotnode", "node-menu-screenshotnode",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
], ],
@ -133,6 +139,7 @@ const TEST_CASES = [
disabled: PASTE_MENU_ITEMS.concat([ disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-screenshotnode", "node-menu-screenshotnode",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
]), ]),
@ -144,6 +151,7 @@ const TEST_CASES = [
selector: "#paste-area", selector: "#paste-area",
disabled: [ disabled: [
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
] ]
@ -157,6 +165,7 @@ const TEST_CASES = [
selector: "#paste-area", selector: "#paste-area",
disabled: PASTE_MENU_ITEMS.concat([ disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
]), ]),
@ -168,6 +177,7 @@ const TEST_CASES = [
selector: "#paste-area", selector: "#paste-area",
disabled: PASTE_MENU_ITEMS.concat([ disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
]), ]),
@ -179,6 +189,7 @@ const TEST_CASES = [
selector: "#paste-area", selector: "#paste-area",
disabled: PASTE_MENU_ITEMS.concat([ disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
]), ]),
@ -189,6 +200,7 @@ const TEST_CASES = [
disabled: PASTE_MENU_ITEMS.concat([ disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-screenshotnode", "node-menu-screenshotnode",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
]), ]),
@ -199,6 +211,7 @@ const TEST_CASES = [
disabled: PASTE_MENU_ITEMS.concat([ disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri", "node-menu-copyimagedatauri",
"node-menu-screenshotnode", "node-menu-screenshotnode",
"node-menu-copy-attribute",
"node-menu-edit-attribute", "node-menu-edit-attribute",
"node-menu-remove-attribute" "node-menu-remove-attribute"
]), ]),

Просмотреть файл

@ -12,6 +12,7 @@ add_task(function* () {
yield selectNode("#attributes", inspector); yield selectNode("#attributes", inspector);
yield testAddAttribute(); yield testAddAttribute();
yield testCopyAttributeValue();
yield testEditAttribute(); yield testEditAttribute();
yield testRemoveAttribute(); yield testRemoveAttribute();
@ -29,6 +30,20 @@ add_task(function* () {
ok(hasAttribute, "attribute was successfully added"); ok(hasAttribute, "attribute was successfully added");
} }
function* testCopyAttributeValue() {
info("Testing 'Copy Attribute Value' and waiting for clipboard promise to resolve");
let copyAttributeValue = getMenuItem("node-menu-copy-attribute");
info("Triggering 'Copy Attribute Value' and waiting for clipboard to copy the value");
inspector.nodeMenuTriggerInfo = {
type: "attribute",
name: "data-edit",
value: "the"
};
yield waitForClipboardPromise(() => copyAttributeValue.click(), "the");
}
function* testEditAttribute() { function* testEditAttribute() {
info("Testing 'Edit Attribute' menu item"); info("Testing 'Edit Attribute' menu item");
let editAttribute = getMenuItem("node-menu-edit-attribute"); let editAttribute = getMenuItem("node-menu-edit-attribute");

Просмотреть файл

@ -23,7 +23,7 @@
</div> </div>
<p id="console-var">Paragraph for testing console variables</p> <p id="console-var">Paragraph for testing console variables</p>
<p id="console-var-multi">Paragraph for testing multiple console variables</p> <p id="console-var-multi">Paragraph for testing multiple console variables</p>
<p id="attributes" data-edit="original" data-remove="thing">Attributes are going to be changed here</p> <p id="attributes" data-copy="the" data-edit="original" data-remove="thing">Attributes are going to be changed here</p>
</div> </div>
</body> </body>
</html> </html>

Просмотреть файл

@ -117,6 +117,13 @@ inspectorEditAttribute.accesskey=E
inspectorRemoveAttribute.label=Remove Attribute %S inspectorRemoveAttribute.label=Remove Attribute %S
inspectorRemoveAttribute.accesskey=R inspectorRemoveAttribute.accesskey=R
# LOCALIZATION NOTE (inspectorCopyAttributeValue.label): This is the label of a
# sub-menu "Attribute" in the inspector contextual-menu that appears
# when the user right-clicks on the attribute of a node in the inspector,
# and that allows to copy the attribute value to clipboard.
inspectorCopyAttributeValue.label=Copy Attribute Value %S
inspectorCopyAttributeValue.accesskey=V
# LOCALIZATION NOTE (inspector.nodePreview.selectNodeLabel): # LOCALIZATION NOTE (inspector.nodePreview.selectNodeLabel):
# This string is displayed in a tooltip that is shown when hovering over a DOM # This string is displayed in a tooltip that is shown when hovering over a DOM
# node preview (e.g. something like "div#foo.bar"). # node preview (e.g. something like "div#foo.bar").

Просмотреть файл

@ -123,13 +123,15 @@
} }
.ruleview-computedlist, .ruleview-computedlist,
.ruleview-overridden-items[hidden],
.ruleview-overridden-rule-filter[hidden], .ruleview-overridden-rule-filter[hidden],
.ruleview-warning[hidden] { .ruleview-warning[hidden] {
display: none; display: none;
} }
.ruleview-computedlist[user-open], .ruleview-computedlist[user-open],
.ruleview-computedlist[filter-open] { .ruleview-computedlist[filter-open],
.ruleview-overridden-items {
display: block; display: block;
} }
@ -362,6 +364,42 @@
margin-inline-start: 35px; margin-inline-start: 35px;
} }
.ruleview-overridden-items {
margin: 0px 0px 0px 5px;
list-style: none;
line-height: 1.5em;
}
.ruleview-overridden-item {
position: relative;
}
.ruleview-overridden-item::before {
position: absolute;
left: -15px;
top: 0px;
content: '';
display: block;
border-left: 1px solid var(--theme-highlight-gray);
height: 0.7em;
border-bottom: 1px solid var(--theme-highlight-gray);
width: 10px;
}
.ruleview-overridden-item::after {
position: absolute;
left: -15px;
bottom: -7px;
content: '';
display: block;
border-left: 1px solid var(--theme-highlight-gray);
height: 100%;
}
.ruleview-overridden-item:last-child:after {
display: none;
}
.ruleview-grid, .ruleview-grid,
.ruleview-swatch { .ruleview-swatch {
cursor: pointer; cursor: pointer;

Просмотреть файл

@ -353,7 +353,7 @@ DragDataProducer::GetNodeString(nsIContent* inNode,
// use a range to get the text-equivalent of the node // use a range to get the text-equivalent of the node
nsCOMPtr<nsIDocument> doc = node->OwnerDoc(); nsCOMPtr<nsIDocument> doc = node->OwnerDoc();
mozilla::ErrorResult rv; mozilla::IgnoredErrorResult rv;
RefPtr<nsRange> range = doc->CreateRange(rv); RefPtr<nsRange> range = doc->CreateRange(rv);
if (range) { if (range) {
range->SelectNode(*node, rv); range->SelectNode(*node, rv);

Просмотреть файл

@ -7967,13 +7967,8 @@ nsDocument::FlushPendingNotifications(FlushType aType)
mParentDocument->FlushPendingNotifications(parentType); mParentDocument->FlushPendingNotifications(parentType);
} }
// Call nsIPresShell::NeedFlush (inline, non-virtual) to check whether we
// really need to flush the shell (virtual, and needs a strong reference).
if (nsIPresShell* shell = GetShell()) { if (nsIPresShell* shell = GetShell()) {
if (shell->NeedFlush(aType)) { shell->FlushPendingNotifications(aType);
nsCOMPtr<nsIPresShell> presShell = shell;
presShell->FlushPendingNotifications(aType);
}
} }
} }

Просмотреть файл

@ -2179,7 +2179,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
for (IdleRequest* request : tmp->mIdleRequestCallbacks) { for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
@ -2260,7 +2259,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService) NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock) NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers) NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads) NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
@ -3240,7 +3238,11 @@ nsGlobalWindow::PreloadLocalStorage()
// private browsing windows do not persist local storage to disk so we should // private browsing windows do not persist local storage to disk so we should
// only try to precache storage when we're not a private browsing window. // only try to precache storage when we're not a private browsing window.
if (principal->GetPrivateBrowsingId() == 0) { if (principal->GetPrivateBrowsingId() == 0) {
storageManager->PrecacheStorage(principal); nsCOMPtr<nsIDOMStorage> storage;
rv = storageManager->PrecacheStorage(principal, getter_AddRefs(storage));
if (NS_SUCCEEDED(rv)) {
mLocalStorage = static_cast<Storage*>(storage.get());
}
} }
} }
@ -11906,49 +11908,66 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK; return NS_OK;
} }
// We need these for our private-browsing check below; so save them off.
// (And we can't do the private-browsing enforcement check as part of our
// outer conditional because otherwise we'll trigger an NS_WARNING if control
// flow reaches the bottom of this method.)
bool isNonPrivateLocalStorageChange =
!nsCRT::strcmp(aTopic, "dom-storage2-changed");
bool isPrivateLocalStorageChange =
!nsCRT::strcmp(aTopic, "dom-private-storage2-changed");
if (isNonPrivateLocalStorageChange || isPrivateLocalStorageChange) {
// Enforce that the source storage area's private browsing state matches
// this window's state. These flag checks and their maintenance independent
// from the principal's OriginAttributes matter because chrome docshells
// that are part of private browsing windows can be private browsing without
// having their OriginAttributes set (because they have the system
// principal).
bool isPrivateBrowsing = IsPrivateBrowsing(); bool isPrivateBrowsing = IsPrivateBrowsing();
if ((!nsCRT::strcmp(aTopic, "dom-storage2-changed") && !isPrivateBrowsing) || if ((isNonPrivateLocalStorageChange && isPrivateBrowsing) ||
(!nsCRT::strcmp(aTopic, "dom-private-storage2-changed") && isPrivateBrowsing)) { (isPrivateLocalStorageChange && !isPrivateBrowsing)) {
if (!IsInnerWindow() || !AsInner()->IsCurrentInnerWindow()) {
return NS_OK; return NS_OK;
} }
nsIPrincipal *principal; // We require that aData be either u"SessionStorage" or u"localStorage".
nsresult rv; // Assert under debug, but ignore the bogus event under non-debug.
MOZ_ASSERT(aData);
if (!aData) {
return NS_ERROR_INVALID_ARG;
}
// LocalStorage can only exist on an inner window, and we don't want to
// generate events on frozen or otherwise-navigated-away from windows.
// (Actually, this code used to try and buffer events for frozen windows,
// but it never worked, so we've removed it. See bug 1285898.)
if (!IsInnerWindow() || !AsInner()->IsCurrentInnerWindow() || IsFrozen()) {
return NS_OK;
}
nsIPrincipal *principal = GetPrincipal();
if (!principal) {
return NS_OK;
}
RefPtr<StorageEvent> event = static_cast<StorageEvent*>(aSubject); RefPtr<StorageEvent> event = static_cast<StorageEvent*>(aSubject);
if (!event) { if (!event) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
RefPtr<Storage> changingStorage = event->GetStorageArea();
if (!changingStorage) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMStorage> istorage = changingStorage.get();
bool fireMozStorageChanged = false; bool fireMozStorageChanged = false;
nsAutoString eventType; nsAutoString eventType;
eventType.AssignLiteral("storage"); eventType.AssignLiteral("storage");
principal = GetPrincipal();
if (!principal) {
return NS_OK;
}
if (changingStorage->IsPrivate() != IsPrivateBrowsing()) { if (!NS_strcmp(aData, u"sessionStorage")) {
return NS_OK; nsCOMPtr<nsIDOMStorage> changingStorage = event->GetStorageArea();
} MOZ_ASSERT(changingStorage);
switch (changingStorage->GetType())
{
case Storage::SessionStorage:
{
bool check = false; bool check = false;
nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell()); nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
if (storageManager) { if (storageManager) {
rv = storageManager->CheckStorage(principal, istorage, &check); nsresult rv = storageManager->CheckStorage(principal, changingStorage,
&check);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
@ -11969,58 +11988,48 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
if (fireMozStorageChanged) { if (fireMozStorageChanged) {
eventType.AssignLiteral("MozSessionStorageChanged"); eventType.AssignLiteral("MozSessionStorageChanged");
} }
break;
} }
case Storage::LocalStorage: else {
{ MOZ_ASSERT(!NS_strcmp(aData, u"localStorage"));
// Allow event fire only for the same principal storages nsIPrincipal* storagePrincipal = event->GetPrincipal();
// XXX We have to use EqualsIgnoreDomain after bug 495337 lands if (!storagePrincipal) {
nsIPrincipal* storagePrincipal = changingStorage->GetPrincipal(); return NS_OK;
}
bool equals = false; bool equals = false;
rv = storagePrincipal->Equals(principal, &equals); nsresult rv = storagePrincipal->Equals(principal, &equals);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (!equals) if (!equals) {
return NS_OK; return NS_OK;
}
fireMozStorageChanged = mLocalStorage == event->GetStorageArea();
fireMozStorageChanged = mLocalStorage == changingStorage;
if (fireMozStorageChanged) { if (fireMozStorageChanged) {
eventType.AssignLiteral("MozLocalStorageChanged"); eventType.AssignLiteral("MozLocalStorageChanged");
} }
break;
}
default:
return NS_OK;
} }
// Clone the storage event included in the observer notification. We want // Clone the storage event included in the observer notification. We want
// to dispatch clones rather than the original event. // to dispatch clones rather than the original event.
ErrorResult error; ErrorResult error;
RefPtr<StorageEvent> newEvent = CloneStorageEvent(eventType, event, error); RefPtr<StorageEvent> clonedEvent =
CloneStorageEvent(eventType, event, error);
if (error.Failed()) { if (error.Failed()) {
return error.StealNSResult(); return error.StealNSResult();
} }
newEvent->SetTrusted(true); clonedEvent->SetTrusted(true);
if (fireMozStorageChanged) { if (fireMozStorageChanged) {
WidgetEvent* internalEvent = newEvent->WidgetEventPtr(); WidgetEvent* internalEvent = clonedEvent->WidgetEventPtr();
internalEvent->mFlags.mOnlyChromeDispatch = true; internalEvent->mFlags.mOnlyChromeDispatch = true;
} }
if (IsFrozen()) {
// This window is frozen, rather than firing the events here,
// store the domain in which the change happened and fire the
// events if we're ever thawed.
mPendingStorageEvents.AppendElement(newEvent);
return NS_OK;
}
bool defaultActionEnabled; bool defaultActionEnabled;
DispatchEvent(newEvent, &defaultActionEnabled); DispatchEvent(clonedEvent, &defaultActionEnabled);
return NS_OK; return NS_OK;
} }
@ -12111,10 +12120,19 @@ nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
aEvent->GetUrl(dict.mUrl); aEvent->GetUrl(dict.mUrl);
RefPtr<Storage> storageArea = aEvent->GetStorageArea(); RefPtr<Storage> storageArea = aEvent->GetStorageArea();
MOZ_ASSERT(storageArea);
RefPtr<Storage> storage; RefPtr<Storage> storage;
if (storageArea->GetType() == Storage::LocalStorage) {
// If null, this is a localStorage event received by IPC.
if (!storageArea) {
storage = GetLocalStorage(aRv);
if (aRv.Failed() || !storage) {
return nullptr;
}
// We must apply the current change to the 'local' localStorage.
storage->ApplyEvent(aEvent);
} else if (storageArea->GetType() == Storage::LocalStorage) {
storage = GetLocalStorage(aRv); storage = GetLocalStorage(aRv);
} else { } else {
MOZ_ASSERT(storageArea->GetType() == Storage::SessionStorage); MOZ_ASSERT(storageArea->GetType() == Storage::SessionStorage);
@ -12126,7 +12144,7 @@ nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
} }
MOZ_ASSERT(storage); MOZ_ASSERT(storage);
MOZ_ASSERT(storage->IsForkOf(storageArea)); MOZ_ASSERT_IF(storageArea, storage->IsForkOf(storageArea));
dict.mStorageArea = storage; dict.mStorageArea = storage;
@ -12419,11 +12437,6 @@ nsGlobalWindow::FireDelayedDOMEvents()
{ {
FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED); FORWARD_TO_INNER(FireDelayedDOMEvents, (), NS_ERROR_UNEXPECTED);
for (uint32_t i = 0, len = mPendingStorageEvents.Length(); i < len; ++i) {
Observe(mPendingStorageEvents[i], "dom-storage2-changed", nullptr);
Observe(mPendingStorageEvents[i], "dom-private-storage2-changed", nullptr);
}
if (mApplicationCache) { if (mApplicationCache) {
static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents(); static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
} }
@ -13293,6 +13306,13 @@ nsGlobalWindow::EventListenerAdded(nsIAtom* aType)
aType == nsGkAtoms::onvrdisplaypresentchange) { aType == nsGkAtoms::onvrdisplaypresentchange) {
NotifyVREventListenerAdded(); NotifyVREventListenerAdded();
} }
// We need to initialize localStorage in order to receive notifications.
if (aType == nsGkAtoms::onstorage) {
ErrorResult rv;
GetLocalStorage(rv);
rv.SuppressException();
}
} }
void void

Просмотреть файл

@ -1946,9 +1946,6 @@ protected:
// These member variables are used on both inner and the outer windows. // These member variables are used on both inner and the outer windows.
nsCOMPtr<nsIPrincipal> mDocumentPrincipal; nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
typedef nsTArray<RefPtr<mozilla::dom::StorageEvent>> nsStorageEventArray;
nsStorageEventArray mPendingStorageEvents;
uint32_t mSuspendDepth; uint32_t mSuspendDepth;
uint32_t mFreezeDepth; uint32_t mFreezeDepth;

Просмотреть файл

@ -1,8 +1,7 @@
[DEFAULT] [DEFAULT]
skip-if = os == 'android'
support-files = nonchrome_webgl_debug_renderer_info.html
[test_webgl_debug_renderer_info.html] [test_webgl_debug_renderer_info.html]
subsuite = gpu subsuite = gpu
[test_drawWindow_widget_layers.html] [test_drawWindow_widget_layers.html]
skip-if = os == 'android'
support-files = ../file_drawWindow_source.html ../file_drawWindow_common.js support-files = ../file_drawWindow_source.html ../file_drawWindow_common.js

Просмотреть файл

@ -1,83 +0,0 @@
<!DOCTYPE HTML>
<html>
<script>
// This file has the portion of the test_webgl_renderer_info chrome mochitest
// that has to run as non-chrome to check that this WebGL extension is not exposed to content
// we can't call the chrome Mochitest ok() function ourselves from non-chrome code.
// So we remote it to the chrome test.
function ok(res, msg) {
// Note we post to ourselves as posting to the chrome code doesn't seem to work here.
// This works by having the chrome code put an event handler on our own window.
window.postMessage({ subTestFinished: true, result: res, message: msg }, "*");
}
function messageListener(e) {
// This is how the chrome test tells us to start running -- we have to wait for this
// message to avoid running before it's set up its event handler.
if (e.data.run) {
var canBeUnprivileged = e.data.canBeUnprivileged;
run(canBeUnprivileged);
}
}
window.addEventListener("message", messageListener, true);
function run(canBeUnprivileged) {
const UNMASKED_VENDOR_WEBGL = 0x9245;
const UNMASKED_RENDERER_WEBGL = 0x9246;
var canvas = document.createElement("canvas");
var gl = canvas.getContext("experimental-webgl");
ok(!gl.getError(), "getError on newly created WebGL context should return NO_ERROR");
ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
"Should not be able to query UNMASKED_VENDOR_WEBGL without having enabled the"
+ " WEBGL_debug_renderer_info extension");
ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM,
"Should not be able to query UNMASKED_RENDERER_WEBGL without having enabled the"
+ " WEBGL_debug_renderer_info extension");
var exts = gl.getSupportedExtensions();
if (canBeUnprivileged) {
ok(exts.indexOf("WEBGL_debug_renderer_info") != -1,
"WEBGL_debug_renderer_info should be listed by getSupportedExtensions in"
+ " non-chrome contexts on non-RELEASE_OR_BETAs");
var ext = gl.getExtension("WEBGL_debug_renderer_info");
ok(!!ext,
"WEBGL_debug_renderer_info should be available through getExtension in non-chrome"
+ " contexts on non-RELEASE_OR_BETAs");
ok(gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.NO_ERROR,
"Should be able to query UNMASKED_VENDOR_WEBGL if enabling"
+ " WEBGL_debug_renderer_info succeeded");
ok(gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.NO_ERROR,
"Should be able to query UNMASKED_RENDERER_WEBGL if enabling"
+ " WEBGL_debug_renderer_info succeeded");
} else {
ok(exts.indexOf("WEBGL_debug_renderer_info") == -1,
"WEBGL_debug_renderer_info should not be listed by getSupportedExtensions in"
+ " non-chrome contexts");
var ext = gl.getExtension("WEBGL_debug_renderer_info");
ok(!ext,
"WEBGL_debug_renderer_info should not be available through getExtension in"
+ " non-chrome contexts");
ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
"Should not be able to query UNMASKED_VENDOR_WEBGL if enabling"
+ " WEBGL_debug_renderer_info failed");
ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM,
"Should not be able to query UNMASKED_RENDERER_WEBGL if enabling"
+ " WEBGL_debug_renderer_info failed");
}
window.postMessage({allTestsFinished: true}, "*");
}
</script>
</html>

Просмотреть файл

@ -4,99 +4,48 @@
https://bugzilla.mozilla.org/show_bug.cgi?id=666446 https://bugzilla.mozilla.org/show_bug.cgi?id=666446
--> -->
<head> <head>
<title>Test for WEBGL_debug_renderer_info chrome-only extension</title> <title>Test that WEBGL_debug_renderer_info works in chrome code</title>
<script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script> <script type="application/javascript" src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head> </head>
<body> <body>
<pre id="test">
<script> <script>
const UNMASKED_VENDOR_WEBGL = 0x9245; const UNMASKED_VENDOR_WEBGL = 0x9245;
const UNMASKED_RENDERER_WEBGL = 0x9246; const UNMASKED_RENDERER_WEBGL = 0x9246;
function isNonEmptyString(s) {
var Cu = parent.Components.utils;
Cu.import("resource://gre/modules/AppConstants.jsm");
// This gives us `AppConstants` in the global scope.
// We need this because we only expose debug_renderer_info #ifndef RELEASE_OR_BETA.
// This should match AppConstants.RELEASE_OR_BETA.
const canBeUnprivileged = !AppConstants.RELEASE_OR_BETA;
function isNonEmptyString(s)
{
return s && (typeof s) == "string"; return s && (typeof s) == "string";
} }
function messageListener(e) { var canvas = document.createElement("canvas");
if (e.data.allTestsFinished) { var gl = canvas.getContext("experimental-webgl");
SimpleTest.finish(); ok(!gl.getError(), "getError on newly created WebGL context should return NO_ERROR");
} else if (e.data.subTestFinished) {
ok(e.data.result, "content iframe: " + e.data.message);
}
}
function checkChromeCase(canvas) { ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
var gl = canvas.getContext("experimental-webgl");
ok(!gl.getError(), "getError on newly created WebGL context should return NO_ERROR");
ok(!gl.getParameter(UNMASKED_VENDOR_WEBGL) && gl.getError() == gl.INVALID_ENUM,
"Should not be able to query UNMASKED_VENDOR_WEBGL without having enabled the WEBGL_debug_renderer_info extension"); "Should not be able to query UNMASKED_VENDOR_WEBGL without having enabled the WEBGL_debug_renderer_info extension");
ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM, ok(!gl.getParameter(UNMASKED_RENDERER_WEBGL) && gl.getError() == gl.INVALID_ENUM,
"Should not be able to query UNMASKED_RENDERER_WEBGL without having enabled the WEBGL_debug_renderer_info extension"); "Should not be able to query UNMASKED_RENDERER_WEBGL without having enabled the WEBGL_debug_renderer_info extension");
var exts = gl.getSupportedExtensions(); var exts = gl.getSupportedExtensions();
ok(exts.indexOf("WEBGL_debug_renderer_info") != -1, ok(exts.indexOf("WEBGL_debug_renderer_info") != -1,
"WEBGL_debug_renderer_info should be listed by getSupportedExtensions in chrome contexts"); "WEBGL_debug_renderer_info should be listed by getSupportedExtensions in chrome contexts");
var ext = gl.getExtension("WEBGL_debug_renderer_info"); var ext = gl.getExtension("WEBGL_debug_renderer_info");
ok(ext, ok(ext,
"WEBGL_debug_renderer_info should be available through getExtension in chrome contexts"); "WEBGL_debug_renderer_info should be available through getExtension in chrome contexts");
ok(ext.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL, ok(ext.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL,
"UNMASKED_VENDOR_WEBGL has the correct value"); "UNMASKED_VENDOR_WEBGL has the correct value");
ok(ext.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL, ok(ext.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL,
"UNMASKED_RENDERER_WEBGL has the correct value"); "UNMASKED_RENDERER_WEBGL has the correct value");
ok(isNonEmptyString(gl.getParameter(UNMASKED_VENDOR_WEBGL)) && gl.getError() == gl.NO_ERROR, ok(isNonEmptyString(gl.getParameter(UNMASKED_VENDOR_WEBGL)) && gl.getError() == gl.NO_ERROR,
"Should be able to query UNMASKED_VENDOR_WEBGL in chrome context with WEBGL_debug_renderer_info enabled"); "Should be able to query UNMASKED_VENDOR_WEBGL in chrome context with WEBGL_debug_renderer_info enabled");
ok(isNonEmptyString(gl.getParameter(UNMASKED_RENDERER_WEBGL)) && gl.getError() == gl.NO_ERROR, ok(isNonEmptyString(gl.getParameter(UNMASKED_RENDERER_WEBGL)) && gl.getError() == gl.NO_ERROR,
"Should be able to query UNMASKED_RENDERER_WEBGL in chrome context with WEBGL_debug_renderer_info enabled"); "Should be able to query UNMASKED_RENDERER_WEBGL in chrome context with WEBGL_debug_renderer_info enabled");
}
function main()
{
SimpleTest.waitForExplicitFinish();
checkChromeCase(document.createElement("canvas"));
// Now run the non-chrome code to verify the security of this WebGL chrome-only extension.
var iframe = document.createElement("iframe");
iframe.src = "http://mochi.test:8888/chrome/dom/canvas/test/chrome/nonchrome_webgl_debug_renderer_info.html";
iframe.onload = function () {
// test that chrome can get WEBGL_debug_renderer_info on a canvas on the iframe...
// this is useful to check in itself, and is also useful so the subsequent non-chrome test
// will also test that doing so doesn't confuse our chrome-only check.
checkChromeCase(iframe.contentDocument.createElement("canvas"));
iframe.contentWindow.addEventListener("message", messageListener);
iframe.contentWindow.postMessage({run: true,
canBeUnprivileged: canBeUnprivileged},
"*");
};
document.body.appendChild(iframe);
}
window.onload = main;
</script> </script>
</pre>
</body> </body>
</html> </html>

Просмотреть файл

@ -31,7 +31,7 @@ var defaultExts = [
['OES_texture_half_float_linear' , [ENSURE , FORBID ]], ['OES_texture_half_float_linear' , [ENSURE , FORBID ]],
['OES_vertex_array_object' , [ENSURE , FORBID ]], ['OES_vertex_array_object' , [ENSURE , FORBID ]],
['WEBGL_compressed_texture_s3tc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]], ['WEBGL_compressed_texture_s3tc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
// ['WEBGL_debug_renderer_info' , [FORBID , FORBID ]], // Complicated! ['WEBGL_debug_renderer_info' , [ENSURE , ENSURE ]],
['WEBGL_debug_shaders' , [FORBID , FORBID ]], ['WEBGL_debug_shaders' , [FORBID , FORBID ]],
['WEBGL_depth_texture' , [MACHINE_SPECIFIC, FORBID ]], ['WEBGL_depth_texture' , [MACHINE_SPECIFIC, FORBID ]],
['WEBGL_draw_buffers' , [MACHINE_SPECIFIC, FORBID ]], ['WEBGL_draw_buffers' , [MACHINE_SPECIFIC, FORBID ]],

Просмотреть файл

@ -13,6 +13,8 @@
#include "mozilla/dom/Event.h" #include "mozilla/dom/Event.h"
#include "mozilla/dom/StorageEventBinding.h" #include "mozilla/dom/StorageEventBinding.h"
class nsIPrincipal;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -34,6 +36,7 @@ protected:
nsString mNewValue; nsString mNewValue;
nsString mUrl; nsString mUrl;
RefPtr<Storage> mStorageArea; RefPtr<Storage> mStorageArea;
nsCOMPtr<nsIPrincipal> mPrincipal;
public: public:
virtual StorageEvent* AsStorageEvent(); virtual StorageEvent* AsStorageEvent();
@ -79,6 +82,18 @@ public:
{ {
return mStorageArea; return mStorageArea;
} }
// Non WebIDL methods
void SetPrincipal(nsIPrincipal* aPrincipal)
{
MOZ_ASSERT(!mPrincipal);
mPrincipal = aPrincipal;
}
nsIPrincipal* GetPrincipal() const
{
return mPrincipal;
}
}; };
} // namespace dom } // namespace dom

Просмотреть файл

@ -293,12 +293,37 @@ HTMLTrackElement::LoadResource()
mChannel = nullptr; mChannel = nullptr;
} }
// According to https://www.w3.org/TR/html5/embedded-content-0.html#sourcing-out-of-band-text-tracks
//
// "8: If the track element's parent is a media element then let CORS mode
// be the state of the parent media element's crossorigin content attribute.
// Otherwise, let CORS mode be No CORS."
//
CORSMode corsMode = mMediaParent ? mMediaParent->GetCORSMode() : CORS_NONE;
// Determine the security flag based on corsMode.
nsSecurityFlags secFlags;
if (CORS_NONE == corsMode) {
// Same-origin is required for track element.
secFlags = nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
} else {
secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
if (CORS_ANONYMOUS == corsMode) {
secFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
} else if (CORS_USE_CREDENTIALS == corsMode) {
secFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
} else {
NS_WARNING("Unknown CORS mode.");
secFlags = nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
}
}
nsCOMPtr<nsIChannel> channel; nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup(); nsCOMPtr<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup();
rv = NS_NewChannel(getter_AddRefs(channel), rv = NS_NewChannel(getter_AddRefs(channel),
uri, uri,
static_cast<Element*>(this), static_cast<Element*>(this),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS, secFlags,
nsIContentPolicy::TYPE_INTERNAL_TRACK, nsIContentPolicy::TYPE_INTERNAL_TRACK,
loadGroup, loadGroup,
nullptr, // aCallbacks nullptr, // aCallbacks
@ -313,7 +338,11 @@ HTMLTrackElement::LoadResource()
LOG(LogLevel::Debug, ("opening webvtt channel")); LOG(LogLevel::Debug, ("opening webvtt channel"));
rv = channel->AsyncOpen2(mListener); rv = channel->AsyncOpen2(mListener);
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
if (NS_FAILED(rv)) {
SetReadyState(TextTrackReadyState::FailedToLoad);
return;
}
mChannel = channel; mChannel = channel;
} }

Просмотреть файл

@ -51,9 +51,9 @@
let url = let url =
URL.createObjectURL(new Blob(["(", dummyWorkerScript.toSource(), ")()"])); URL.createObjectURL(new Blob(["(", dummyWorkerScript.toSource(), ")()"]));
let worker = new Worker(url); let worker1 = new Worker(url);
try { try {
worker.postMessage(mutableFile); worker1.postMessage(mutableFile);
ok(false, "Should have thrown!"); ok(false, "Should have thrown!");
} }
catch (e) { catch (e) {
@ -61,7 +61,6 @@
is(e.name, "DataCloneError", "Good error."); is(e.name, "DataCloneError", "Good error.");
is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.") is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
} }
worker.terminate();
mutableFile.onerror = errorHandler; mutableFile.onerror = errorHandler;
@ -77,10 +76,10 @@
let file = event.target.result; let file = event.target.result;
worker = new Worker(url); let worker2 = new Worker(url);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
try { try {
worker.postMessage(file); worker2.postMessage(file);
ok(false, "Should have thrown!"); ok(false, "Should have thrown!");
} }
catch (e) { catch (e) {
@ -88,7 +87,6 @@
is(e.name, "DataCloneError", "Good error."); is(e.name, "DataCloneError", "Good error.");
is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.") is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
} }
worker.terminate();
let objectStore = let objectStore =
db.transaction("Foo", "readwrite").objectStore("Foo"); db.transaction("Foo", "readwrite").objectStore("Foo");
@ -126,14 +124,18 @@
url = URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"])); url = URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
worker = new Worker(url); let worker3 = new Worker(url);
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
worker.postMessage(name); worker3.postMessage(name);
worker.onmessage = grabEventAndContinueHandler; worker3.onmessage = grabEventAndContinueHandler;
event = yield undefined; event = yield undefined;
is(event.data, "success", "Good response."); is(event.data, "success", "Good response.");
worker.terminate();
todo(false, "Terminate all workers at the end of the test to work around bug 1340941.");
worker1.terminate();
worker2.terminate();
worker3.terminate();
finishTest(); finishTest();
} }

Просмотреть файл

@ -20,8 +20,15 @@ interface nsIDOMStorageManager : nsISupports
/** /**
* This starts async preloading of a storage cache for scope * This starts async preloading of a storage cache for scope
* defined by the principal. * defined by the principal.
*
* Because of how multi-e10s support was implemented in bug 1285898, the
* StorageCache instance can no longer use a timer to keep itself alive. So a
* Storage instance is returned if precaching believes the principal may have
* localStorage data. (Previously the StorageCache would be brought into
* existence and kept alive by the timer so that it could be returned if a
* call to createStorage was made due to a request by the page.)
*/ */
void precacheStorage(in nsIPrincipal aPrincipal); nsIDOMStorage precacheStorage(in nsIPrincipal aPrincipal);
/** /**
* Returns instance of DOM storage object for given principal. * Returns instance of DOM storage object for given principal.

Просмотреть файл

@ -34,6 +34,7 @@
#include "mozilla/dom/MemoryReportRequest.h" #include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/dom/ProcessGlobal.h" #include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/PushNotifier.h" #include "mozilla/dom/PushNotifier.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageIPC.h" #include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/TabGroup.h" #include "mozilla/dom/TabGroup.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h" #include "mozilla/dom/workers/ServiceWorkerManager.h"
@ -3035,6 +3036,20 @@ ContentChild::RecvBlobURLUnregistration(const nsCString& aURI)
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult
ContentChild::RecvDispatchLocalStorageChange(const nsString& aDocumentURI,
const nsString& aKey,
const nsString& aOldValue,
const nsString& aNewValue,
const IPC::Principal& aPrincipal,
const bool& aIsPrivate)
{
Storage::DispatchStorageEvent(Storage::LocalStorage,
aDocumentURI, aKey, aOldValue, aNewValue,
aPrincipal, aIsPrivate, nullptr, true);
return IPC_OK();
}
#if defined(XP_WIN) && defined(ACCESSIBILITY) #if defined(XP_WIN) && defined(ACCESSIBILITY)
bool bool
ContentChild::SendGetA11yContentId() ContentChild::SendGetA11yContentId()

Просмотреть файл

@ -391,6 +391,14 @@ public:
virtual mozilla::ipc::IPCResult virtual mozilla::ipc::IPCResult
RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistations) override; RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistations) override;
virtual mozilla::ipc::IPCResult
RecvDispatchLocalStorageChange(const nsString& aDocumentURI,
const nsString& aKey,
const nsString& aOldValue,
const nsString& aNewValue,
const IPC::Principal& aPrincipal,
const bool& aIsPrivate) override;
virtual mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed() override; virtual mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed() override;
virtual mozilla::ipc::IPCResult RecvFilePathUpdate(const nsString& aStorageType, virtual mozilla::ipc::IPCResult RecvFilePathUpdate(const nsString& aStorageType,

Просмотреть файл

@ -51,6 +51,7 @@
#include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/PCycleCollectWithLogsParent.h" #include "mozilla/dom/PCycleCollectWithLogsParent.h"
#include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageIPC.h" #include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h" #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/power/PowerManagerService.h" #include "mozilla/dom/power/PowerManagerService.h"
@ -4771,6 +4772,25 @@ ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aUR
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult
ContentParent::RecvBroadcastLocalStorageChange(const nsString& aDocumentURI,
const nsString& aKey,
const nsString& aOldValue,
const nsString& aNewValue,
const Principal& aPrincipal,
const bool& aIsPrivate)
{
for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
if (cp != this) {
Unused << cp->SendDispatchLocalStorageChange(
nsString(aDocumentURI), nsString(aKey), nsString(aOldValue),
nsString(aNewValue), IPC::Principal(aPrincipal), aIsPrivate);
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
ContentParent::RecvGetA11yContentId(uint32_t* aContentId) ContentParent::RecvGetA11yContentId(uint32_t* aContentId)
{ {

Просмотреть файл

@ -574,6 +574,14 @@ public:
virtual mozilla::ipc::IPCResult virtual mozilla::ipc::IPCResult
RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) override; RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aURI) override;
virtual mozilla::ipc::IPCResult
RecvBroadcastLocalStorageChange(const nsString& aDocumentURI,
const nsString& aKey,
const nsString& aOldValue,
const nsString& aNewValue,
const IPC::Principal& aPrincipal,
const bool& aIsPrivate) override;
virtual mozilla::ipc::IPCResult virtual mozilla::ipc::IPCResult
RecvGetA11yContentId(uint32_t* aContentId) override; RecvGetA11yContentId(uint32_t* aContentId) override;

Просмотреть файл

@ -676,6 +676,12 @@ child:
async BlobURLUnregistration(nsCString aURI); async BlobURLUnregistration(nsCString aURI);
async DispatchLocalStorageChange(nsString documentURI,
nsString key,
nsString oldValue,
nsString newValue,
Principal principal,
bool isPrivate);
async GMPsChanged(GMPCapabilityData[] capabilities); async GMPsChanged(GMPCapabilityData[] capabilities);
@ -1178,6 +1184,13 @@ parent:
async UnstoreAndBroadcastBlobURLUnregistration(nsCString url); async UnstoreAndBroadcastBlobURLUnregistration(nsCString url);
async BroadcastLocalStorageChange(nsString documentURI,
nsString key,
nsString oldValue,
nsString newValue,
Principal principal,
bool isPrivate);
/** /**
* Messages for communicating child Telemetry to the parent process * Messages for communicating child Telemetry to the parent process
*/ */

Просмотреть файл

@ -769,7 +769,7 @@ public:
* Returns false if the data was not appended because no such track exists * Returns false if the data was not appended because no such track exists
* or the stream was already finished. * or the stream was already finished.
*/ */
bool AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment = nullptr); virtual bool AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment = nullptr);
/** /**
* Get the stream time of the end of the data that has been appended so far. * Get the stream time of the end of the data that has been appended so far.
* Can be called from any thread but won't be useful if it can race with * Can be called from any thread but won't be useful if it can race with

Просмотреть файл

@ -130,11 +130,12 @@ MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
mReadyState(MediaStreamTrackState::Live), mReadyState(MediaStreamTrackState::Live),
mEnabled(true), mConstraints(aConstraints) mEnabled(true), mConstraints(aConstraints)
{ {
GetSource().RegisterSink(this); GetSource().RegisterSink(this);
if (GetOwnedStream()) {
mPrincipalHandleListener = new PrincipalHandleListener(this); mPrincipalHandleListener = new PrincipalHandleListener(this);
AddListener(mPrincipalHandleListener); AddListener(mPrincipalHandleListener);
}
nsresult rv; nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen = nsCOMPtr<nsIUUIDGenerator> uuidgen =

Просмотреть файл

@ -394,7 +394,7 @@ public:
* Adds a MediaStreamTrackListener to the MediaStreamGraph representation of * Adds a MediaStreamTrackListener to the MediaStreamGraph representation of
* this track. * this track.
*/ */
void AddListener(MediaStreamTrackListener* aListener); virtual void AddListener(MediaStreamTrackListener* aListener);
/** /**
* Removes a MediaStreamTrackListener from the MediaStreamGraph representation * Removes a MediaStreamTrackListener from the MediaStreamGraph representation
@ -408,7 +408,7 @@ public:
* the listener succeeded (tracks originating from SourceMediaStreams) or * the listener succeeded (tracks originating from SourceMediaStreams) or
* failed (e.g., WebAudio originated tracks). * failed (e.g., WebAudio originated tracks).
*/ */
void AddDirectListener(DirectMediaStreamTrackListener *aListener); virtual void AddDirectListener(DirectMediaStreamTrackListener *aListener);
void RemoveDirectListener(DirectMediaStreamTrackListener *aListener); void RemoveDirectListener(DirectMediaStreamTrackListener *aListener);
/** /**

Просмотреть файл

@ -2720,6 +2720,26 @@ ForceWindowless(InfallibleTArray<nsCString>& names,
} }
} }
#endif // windows or linux #endif // windows or linux
#if defined(XP_WIN)
static void
ForceDirect(InfallibleTArray<nsCString>& names,
InfallibleTArray<nsCString>& values)
{
nsCaseInsensitiveUTF8StringArrayComparator comparator;
NS_NAMED_LITERAL_CSTRING(wmodeAttributeName, "wmode");
NS_NAMED_LITERAL_CSTRING(directAttributeValue, "direct");
auto wmodeAttributeIndex =
names.IndexOf(wmodeAttributeName, 0, comparator);
if (wmodeAttributeIndex != names.NoIndex) {
if (values[wmodeAttributeIndex].EqualsLiteral("window")) {
values[wmodeAttributeIndex].Assign(directAttributeValue);
}
} else {
names.AppendElement(wmodeAttributeName);
values.AppendElement(directAttributeValue);
}
}
#endif // windows
nsresult nsresult
PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance, PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
@ -2758,6 +2778,8 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
#ifdef XP_WIN #ifdef XP_WIN
bool supportsAsyncRender = bool supportsAsyncRender =
Preferences::GetBool("dom.ipc.plugins.asyncdrawing.enabled", false); Preferences::GetBool("dom.ipc.plugins.asyncdrawing.enabled", false);
bool supportsForceDirect =
Preferences::GetBool("dom.ipc.plugins.forcedirect.enabled", false);
if (supportsAsyncRender) { if (supportsAsyncRender) {
// Prefs indicates we want async plugin rendering, make sure // Prefs indicates we want async plugin rendering, make sure
// the flash module has support. // the flash module has support.
@ -2777,6 +2799,14 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
#elif defined(MOZ_WIDGET_GTK) #elif defined(MOZ_WIDGET_GTK)
// We no longer support windowed mode on Linux. // We no longer support windowed mode on Linux.
ForceWindowless(names, values); ForceWindowless(names, values);
#endif
#ifdef XP_WIN
// For all builds that use async rendering force use of the accelerated
// direct path for flash objects that have wmode=window or no wmode
// specified.
if (supportsAsyncRender && supportsForceDirect) {
ForceDirect(names, values);
}
#endif #endif
} }

Просмотреть файл

@ -14,6 +14,9 @@
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsICookiePermission.h" #include "nsICookiePermission.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/StorageBinding.h" #include "mozilla/dom/StorageBinding.h"
#include "mozilla/dom/StorageEvent.h" #include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h" #include "mozilla/dom/StorageEventBinding.h"
@ -25,6 +28,9 @@
#include "nsServiceManagerUtils.h" #include "nsServiceManagerUtils.h"
namespace mozilla { namespace mozilla {
using namespace ipc;
namespace dom { namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mManager, mPrincipal, mWindow) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mManager, mPrincipal, mWindow)
@ -58,7 +64,6 @@ Storage::Storage(nsPIDOMWindowInner* aWindow,
Storage::~Storage() Storage::~Storage()
{ {
mCache->KeepAlive();
} }
/* virtual */ JSObject* /* virtual */ JSObject*
@ -215,6 +220,30 @@ void
Storage::BroadcastChangeNotification(const nsSubstring& aKey, Storage::BroadcastChangeNotification(const nsSubstring& aKey,
const nsSubstring& aOldValue, const nsSubstring& aOldValue,
const nsSubstring& aNewValue) const nsSubstring& aNewValue)
{
if (!XRE_IsParentProcess() && GetType() == LocalStorage && mPrincipal) {
// If we are in a child process, we want to send a message to the parent in
// order to broadcast the StorageEvent correctly to any child process.
dom::ContentChild* cc = dom::ContentChild::GetSingleton();
Unused << NS_WARN_IF(!cc->SendBroadcastLocalStorageChange(
mDocumentURI, nsString(aKey), nsString(aOldValue), nsString(aNewValue),
IPC::Principal(mPrincipal), mIsPrivate));
}
DispatchStorageEvent(GetType(), mDocumentURI, aKey, aOldValue, aNewValue,
mPrincipal, mIsPrivate, this, false);
}
/* static */ void
Storage::DispatchStorageEvent(StorageType aStorageType,
const nsAString& aDocumentURI,
const nsAString& aKey,
const nsAString& aOldValue,
const nsAString& aNewValue,
nsIPrincipal* aPrincipal,
bool aIsPrivate,
Storage* aStorage,
bool aImmediateDispatch)
{ {
StorageEventInit dict; StorageEventInit dict;
dict.mBubbles = false; dict.mBubbles = false;
@ -222,21 +251,67 @@ Storage::BroadcastChangeNotification(const nsSubstring& aKey,
dict.mKey = aKey; dict.mKey = aKey;
dict.mNewValue = aNewValue; dict.mNewValue = aNewValue;
dict.mOldValue = aOldValue; dict.mOldValue = aOldValue;
dict.mStorageArea = this; dict.mStorageArea = aStorage;
dict.mUrl = mDocumentURI; dict.mUrl = aDocumentURI;
// Note, this DOM event should never reach JS. It is cloned later in // Note, this DOM event should never reach JS. It is cloned later in
// nsGlobalWindow. // nsGlobalWindow.
RefPtr<StorageEvent> event = RefPtr<StorageEvent> event =
StorageEvent::Constructor(nullptr, NS_LITERAL_STRING("storage"), dict); StorageEvent::Constructor(nullptr, NS_LITERAL_STRING("storage"), dict);
event->SetPrincipal(aPrincipal);
RefPtr<StorageNotifierRunnable> r = RefPtr<StorageNotifierRunnable> r =
new StorageNotifierRunnable(event, new StorageNotifierRunnable(event,
GetType() == LocalStorage aStorageType == LocalStorage
? u"localStorage" ? u"localStorage"
: u"sessionStorage", : u"sessionStorage",
IsPrivate()); aIsPrivate);
if (aImmediateDispatch) {
Unused << r->Run();
} else {
NS_DispatchToMainThread(r); NS_DispatchToMainThread(r);
}
// If we are in the parent process and we have the principal, we want to
// broadcast this event to every other process.
if (aStorageType == LocalStorage && XRE_IsParentProcess() && aPrincipal) {
for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
Unused << cp->SendDispatchLocalStorageChange(
nsString(aDocumentURI), nsString(aKey), nsString(aOldValue),
nsString(aNewValue), IPC::Principal(aPrincipal), aIsPrivate);
}
}
}
void
Storage::ApplyEvent(StorageEvent* aStorageEvent)
{
MOZ_ASSERT(aStorageEvent);
nsAutoString key;
nsAutoString old;
nsAutoString value;
aStorageEvent->GetKey(key);
aStorageEvent->GetNewValue(value);
// No key means clearing the full storage.
if (key.IsVoid()) {
MOZ_ASSERT(value.IsVoid());
mCache->Clear(this, StorageCache::E10sPropagated);
return;
}
// No new value means removing the key.
if (value.IsVoid()) {
mCache->RemoveItem(this, key, old, StorageCache::E10sPropagated);
return;
}
// Otherwise, we set the new value.
mCache->SetItem(this, key, value, old, StorageCache::E10sPropagated);
} }
static const char kPermissionType[] = "cookie"; static const char kPermissionType[] = "cookie";

Просмотреть файл

@ -24,6 +24,7 @@ namespace dom {
class StorageManagerBase; class StorageManagerBase;
class StorageCache; class StorageCache;
class StorageEvent;
class Storage final class Storage final
: public nsIDOMStorage : public nsIDOMStorage
@ -129,6 +130,28 @@ public:
return mCache == aOther->mCache; return mCache == aOther->mCache;
} }
// aStorage can be null if this method is called by ContentChild.
//
// aImmediateDispatch is for use by (main-thread) IPC code so that PContent
// ordering can be maintained. Without this, the event would be enqueued and
// run in a future turn of the event loop, potentially allowing other PContent
// Recv* methods to trigger script that wants to assume our localstorage
// changes have already been applied. This is the case for message manager
// messages which are used by ContentTask testing logic and webextensions.
static void
DispatchStorageEvent(StorageType aStorageType,
const nsAString& aDocumentURI,
const nsAString& aKey,
const nsAString& aOldValue,
const nsAString& aNewValue,
nsIPrincipal* aPrincipal,
bool aIsPrivate,
Storage* aStorage,
bool aImmediateDispatch);
void
ApplyEvent(StorageEvent* aStorageEvent);
protected: protected:
// The method checks whether the caller can use a storage. // The method checks whether the caller can use a storage.
// CanUseStorage is called before any DOM initiated operation // CanUseStorage is called before any DOM initiated operation

Просмотреть файл

@ -198,28 +198,33 @@ StorageCache::DataSet(const Storage* aStorage)
} }
bool bool
StorageCache::ProcessUsageDelta(const Storage* aStorage, int64_t aDelta) StorageCache::ProcessUsageDelta(const Storage* aStorage, int64_t aDelta,
const MutationSource aSource)
{ {
return ProcessUsageDelta(GetDataSetIndex(aStorage), aDelta); return ProcessUsageDelta(GetDataSetIndex(aStorage), aDelta, aSource);
} }
bool bool
StorageCache::ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta) StorageCache::ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta,
const MutationSource aSource)
{ {
// Check if we are in a low disk space situation // Check if we are in a low disk space situation
if (aDelta > 0 && mManager && mManager->IsLowDiskSpace()) { if (aSource == ContentMutation &&
aDelta > 0 && mManager && mManager->IsLowDiskSpace()) {
return false; return false;
} }
// Check limit per this origin // Check limit per this origin
Data& data = mData[aGetDataSetIndex]; Data& data = mData[aGetDataSetIndex];
uint64_t newOriginUsage = data.mOriginQuotaUsage + aDelta; uint64_t newOriginUsage = data.mOriginQuotaUsage + aDelta;
if (aDelta > 0 && newOriginUsage > StorageManagerBase::GetQuota()) { if (aSource == ContentMutation &&
aDelta > 0 && newOriginUsage > StorageManagerBase::GetQuota()) {
return false; return false;
} }
// Now check eTLD+1 limit // Now check eTLD+1 limit
if (mUsage && !mUsage->CheckAndSetETLD1UsageDelta(aGetDataSetIndex, aDelta)) { if (mUsage &&
!mUsage->CheckAndSetETLD1UsageDelta(aGetDataSetIndex, aDelta, aSource)) {
return false; return false;
} }
@ -246,73 +251,6 @@ StorageCache::Preload()
namespace { namespace {
// This class is passed to timer as a tick observer. It refers the cache
// and keeps it alive for a time.
class StorageCacheHolder : public nsITimerCallback, public nsINamed
{
virtual ~StorageCacheHolder() {}
NS_DECL_ISUPPORTS
NS_IMETHOD
Notify(nsITimer* aTimer) override
{
mCache = nullptr;
return NS_OK;
}
NS_IMETHOD
GetName(nsACString& aName) override
{
aName.AssignASCII("StorageCacheHolder_timer");
return NS_OK;
}
NS_IMETHOD
SetName(const char* aName) override
{
return NS_ERROR_NOT_IMPLEMENTED;
}
RefPtr<StorageCache> mCache;
public:
explicit StorageCacheHolder(StorageCache* aCache) : mCache(aCache) {}
};
NS_IMPL_ISUPPORTS(StorageCacheHolder, nsITimerCallback, nsINamed)
} // namespace
void
StorageCache::KeepAlive()
{
// Missing reference back to the manager means the cache is not responsible
// for its lifetime. Used for keeping sessionStorage live forever.
if (!mManager) {
return;
}
if (!NS_IsMainThread()) {
// Timer and the holder must be initialized on the main thread.
NS_DispatchToMainThread(NewRunnableMethod(this, &StorageCache::KeepAlive));
return;
}
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
if (!timer) {
return;
}
RefPtr<StorageCacheHolder> holder = new StorageCacheHolder(this);
timer->InitWithCallback(holder, DOM_STORAGE_CACHE_KEEP_ALIVE_TIME_MS,
nsITimer::TYPE_ONE_SHOT);
mKeepAliveTimer.swap(timer);
}
namespace {
// The AutoTimer provided by telemetry headers is only using static, // The AutoTimer provided by telemetry headers is only using static,
// i.e. compile time known ID, but here we know the ID only at run time. // i.e. compile time known ID, but here we know the ID only at run time.
// Hence a new class. // Hence a new class.
@ -452,7 +390,8 @@ StorageCache::GetItem(const Storage* aStorage, const nsAString& aKey,
nsresult nsresult
StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey, StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
const nsString& aValue, nsString& aOld) const nsString& aValue, nsString& aOld,
const MutationSource aSource)
{ {
// Size of the cache that will change after this action. // Size of the cache that will change after this action.
int64_t delta = 0; int64_t delta = 0;
@ -475,7 +414,7 @@ StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
delta += static_cast<int64_t>(aValue.Length()) - delta += static_cast<int64_t>(aValue.Length()) -
static_cast<int64_t>(aOld.Length()); static_cast<int64_t>(aOld.Length());
if (!ProcessUsageDelta(aStorage, delta)) { if (!ProcessUsageDelta(aStorage, delta, aSource)) {
return NS_ERROR_DOM_QUOTA_REACHED; return NS_ERROR_DOM_QUOTA_REACHED;
} }
@ -485,7 +424,7 @@ StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
data.mKeys.Put(aKey, aValue); data.mKeys.Put(aKey, aValue);
if (Persist(aStorage)) { if (aSource == ContentMutation && Persist(aStorage)) {
if (!sDatabase) { if (!sDatabase) {
NS_ERROR("Writing to localStorage after the database has been shut down" NS_ERROR("Writing to localStorage after the database has been shut down"
", data lose!"); ", data lose!");
@ -504,7 +443,7 @@ StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
nsresult nsresult
StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey, StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
nsString& aOld) nsString& aOld, const MutationSource aSource)
{ {
if (Persist(aStorage)) { if (Persist(aStorage)) {
WaitForPreload(Telemetry::LOCALDOMSTORAGE_REMOVEKEY_BLOCKING_MS); WaitForPreload(Telemetry::LOCALDOMSTORAGE_REMOVEKEY_BLOCKING_MS);
@ -522,10 +461,10 @@ StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
// Recalculate the cached data size // Recalculate the cached data size
const int64_t delta = -(static_cast<int64_t>(aOld.Length()) + const int64_t delta = -(static_cast<int64_t>(aOld.Length()) +
static_cast<int64_t>(aKey.Length())); static_cast<int64_t>(aKey.Length()));
Unused << ProcessUsageDelta(aStorage, delta); Unused << ProcessUsageDelta(aStorage, delta, aSource);
data.mKeys.Remove(aKey); data.mKeys.Remove(aKey);
if (Persist(aStorage)) { if (aSource == ContentMutation && Persist(aStorage)) {
if (!sDatabase) { if (!sDatabase) {
NS_ERROR("Writing to localStorage after the database has been shut down" NS_ERROR("Writing to localStorage after the database has been shut down"
", data lose!"); ", data lose!");
@ -539,7 +478,7 @@ StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
} }
nsresult nsresult
StorageCache::Clear(const Storage* aStorage) StorageCache::Clear(const Storage* aStorage, const MutationSource aSource)
{ {
bool refresh = false; bool refresh = false;
if (Persist(aStorage)) { if (Persist(aStorage)) {
@ -561,11 +500,11 @@ StorageCache::Clear(const Storage* aStorage)
bool hadData = !!data.mKeys.Count(); bool hadData = !!data.mKeys.Count();
if (hadData) { if (hadData) {
Unused << ProcessUsageDelta(aStorage, -data.mOriginQuotaUsage); Unused << ProcessUsageDelta(aStorage, -data.mOriginQuotaUsage, aSource);
data.mKeys.Clear(); data.mKeys.Clear();
} }
if (Persist(aStorage) && (refresh || hadData)) { if (aSource == ContentMutation && Persist(aStorage) && (refresh || hadData)) {
if (!sDatabase) { if (!sDatabase) {
NS_ERROR("Writing to localStorage after the database has been shut down" NS_ERROR("Writing to localStorage after the database has been shut down"
", data lose!"); ", data lose!");
@ -680,9 +619,6 @@ StorageCache::LoadItem(const nsAString& aKey, const nsString& aValue)
void void
StorageCache::LoadDone(nsresult aRv) StorageCache::LoadDone(nsresult aRv)
{ {
// Keep the preloaded cache alive for a time
KeepAlive();
MonitorAutoLock monitor(mMonitor); MonitorAutoLock monitor(mMonitor);
mLoadResult = aRv; mLoadResult = aRv;
mLoaded = true; mLoaded = true;
@ -743,12 +679,13 @@ StorageUsage::LoadUsage(const int64_t aUsage)
bool bool
StorageUsage::CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, StorageUsage::CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex,
const int64_t aDelta) const int64_t aDelta, const StorageCache::MutationSource aSource)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
int64_t newUsage = mUsage[aDataSetIndex] + aDelta; int64_t newUsage = mUsage[aDataSetIndex] + aDelta;
if (aDelta > 0 && newUsage > StorageManagerBase::GetQuota()) { if (aSource == StorageCache::ContentMutation &&
aDelta > 0 && newUsage > StorageManagerBase::GetQuota()) {
return false; return false;
} }

Просмотреть файл

@ -78,6 +78,22 @@ class StorageCache : public StorageCacheBridge
public: public:
NS_IMETHOD_(void) Release(void); NS_IMETHOD_(void) Release(void);
enum MutationSource {
// The mutation is a result of an explicit JS mutation in this process.
// The mutation should be sent to the sDatabase. Quota will be checked and
// QuotaExceededError may be returned without the mutation being applied.
ContentMutation,
// The mutation initially was triggered in a different process and is being
// propagated to this cache via Storage::ApplyEvent. The mutation should
// not be sent to the sDatabase because the originating process is already
// doing that. (In addition to the redundant writes being wasteful, there
// is the potential for other processes to see inconsistent state from the
// database while preloading.) Quota will be updated but not checked
// because it's assumed it was checked in another process and data-coherency
// is more important than slightly exceeding quota.
E10sPropagated
};
// Note: We pass aOriginNoSuffix through the ctor here, because // Note: We pass aOriginNoSuffix through the ctor here, because
// StorageCacheHashKey's ctor is creating this class and // StorageCacheHashKey's ctor is creating this class and
// accepts reversed-origin-no-suffix as an argument - the hashing key. // accepts reversed-origin-no-suffix as an argument - the hashing key.
@ -96,10 +112,6 @@ public:
// Starts async preload of this cache if it persistent and not loaded. // Starts async preload of this cache if it persistent and not loaded.
void Preload(); void Preload();
// Keeps the cache alive (i.e. present in the manager's hash table) for a
// time.
void KeepAlive();
// The set of methods that are invoked by DOM storage web API. // The set of methods that are invoked by DOM storage web API.
// We are passing the Storage object just to let the cache // We are passing the Storage object just to let the cache
// read properties like mPrivate, mPrincipal and mSessionOnly. // read properties like mPrivate, mPrincipal and mSessionOnly.
@ -109,10 +121,13 @@ public:
nsresult GetItem(const Storage* aStorage, const nsAString& aKey, nsresult GetItem(const Storage* aStorage, const nsAString& aKey,
nsAString& aRetval); nsAString& aRetval);
nsresult SetItem(const Storage* aStorage, const nsAString& aKey, nsresult SetItem(const Storage* aStorage, const nsAString& aKey,
const nsString& aValue, nsString& aOld); const nsString& aValue, nsString& aOld,
const MutationSource aSource=ContentMutation);
nsresult RemoveItem(const Storage* aStorage, const nsAString& aKey, nsresult RemoveItem(const Storage* aStorage, const nsAString& aKey,
nsString& aOld); nsString& aOld,
nsresult Clear(const Storage* aStorage); const MutationSource aSource=ContentMutation);
nsresult Clear(const Storage* aStorage,
const MutationSource aSource=ContentMutation);
void GetKeys(const Storage* aStorage, nsTArray<nsString>& aKeys); void GetKeys(const Storage* aStorage, nsTArray<nsString>& aKeys);
@ -182,8 +197,18 @@ private:
// Changes the quota usage on the given data set if it fits the quota. // Changes the quota usage on the given data set if it fits the quota.
// If not, then false is returned and no change to the set must be done. // If not, then false is returned and no change to the set must be done.
bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta); // A special case is if aSource==E10sPropagated, then we will return true even
bool ProcessUsageDelta(const Storage* aStorage, const int64_t aDelta); // if the change would put us over quota. This is done to ensure coherency of
// caches between processes in the face of races. It does allow an attacker
// to potentially use N multiples of the quota storage limit if they can
// arrange for their origin to execute code in N processes. However, this is
// not considered a particularly concerning threat model because it's already
// very possible for a rogue page to attempt to intentionally fill up the
// user's storage through the use of multiple domains.
bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta,
const MutationSource aSource=ContentMutation);
bool ProcessUsageDelta(const Storage* aStorage, const int64_t aDelta,
const MutationSource aSource=ContentMutation);
private: private:
// When a cache is reponsible for its life time (in case of localStorage data // When a cache is reponsible for its life time (in case of localStorage data
@ -196,9 +221,6 @@ private:
// Obtained from the manager during initialization (Init method). // Obtained from the manager during initialization (Init method).
RefPtr<StorageUsage> mUsage; RefPtr<StorageUsage> mUsage;
// Timer that holds this cache alive for a while after it has been preloaded.
nsCOMPtr<nsITimer> mKeepAliveTimer;
// Principal the cache has been initially created for, this is used only for // Principal the cache has been initially created for, this is used only for
// sessionStorage access checks since sessionStorage objects are strictly // sessionStorage access checks since sessionStorage objects are strictly
// scoped by a principal. localStorage objects on the other hand are scoped // scoped by a principal. localStorage objects on the other hand are scoped
@ -277,7 +299,8 @@ class StorageUsage : public StorageUsageBridge
public: public:
explicit StorageUsage(const nsACString& aOriginScope); explicit StorageUsage(const nsACString& aOriginScope);
bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta); bool CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex, int64_t aUsageDelta,
const StorageCache::MutationSource aSource);
private: private:
virtual const nsCString& OriginScope() { return mOriginScope; } virtual const nsCString& OriginScope() { return mOriginScope; }

Просмотреть файл

@ -224,6 +224,12 @@ StorageDBChild::RecvObserve(const nsCString& aTopic,
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
StorageDBChild::RecvOriginsHavingData(nsTArray<nsCString>&& aOrigins) StorageDBChild::RecvOriginsHavingData(nsTArray<nsCString>&& aOrigins)
{ {
// Force population of mOriginsHavingData even if there are no origins so that
// ShouldPreloadOrigin does not generate false positives for all origins.
if (!aOrigins.Length()) {
Unused << OriginsHavingData();
}
for (uint32_t i = 0; i < aOrigins.Length(); ++i) { for (uint32_t i = 0; i < aOrigins.Length(); ++i) {
OriginsHavingData().PutEntry(aOrigins[i]); OriginsHavingData().PutEntry(aOrigins[i]);
} }

Просмотреть файл

@ -309,7 +309,7 @@ StorageManagerBase::DropCache(StorageCache* aCache)
} }
nsresult nsresult
StorageManagerBase::GetStorageInternal(bool aCreate, StorageManagerBase::GetStorageInternal(CreateMode aCreateMode,
mozIDOMWindow* aWindow, mozIDOMWindow* aWindow,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI, const nsAString& aDocumentURI,
@ -331,12 +331,12 @@ StorageManagerBase::GetStorageInternal(bool aCreate,
// Get or create a cache for the given scope // Get or create a cache for the given scope
if (!cache) { if (!cache) {
if (!aCreate) { if (aCreateMode == CreateMode::UseIfExistsNeverCreate) {
*aRetval = nullptr; *aRetval = nullptr;
return NS_OK; return NS_OK;
} }
if (!aRetval) { if (aCreateMode == CreateMode::CreateIfShouldPreload) {
// This is a demand to just preload the cache, if the scope has // This is a demand to just preload the cache, if the scope has
// no data stored, bypass creation and preload of the cache. // no data stored, bypass creation and preload of the cache.
StorageDBBridge* db = StorageCache::GetDatabase(); StorageDBBridge* db = StorageCache::GetDatabase();
@ -372,10 +372,11 @@ StorageManagerBase::GetStorageInternal(bool aCreate,
} }
NS_IMETHODIMP NS_IMETHODIMP
StorageManagerBase::PrecacheStorage(nsIPrincipal* aPrincipal) StorageManagerBase::PrecacheStorage(nsIPrincipal* aPrincipal,
nsIDOMStorage** aRetval)
{ {
return GetStorageInternal(true, nullptr, aPrincipal, EmptyString(), false, return GetStorageInternal(CreateMode::CreateIfShouldPreload, nullptr,
nullptr); aPrincipal, EmptyString(), false, aRetval);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -385,8 +386,8 @@ StorageManagerBase::CreateStorage(mozIDOMWindow* aWindow,
bool aPrivate, bool aPrivate,
nsIDOMStorage** aRetval) nsIDOMStorage** aRetval)
{ {
return GetStorageInternal(true, aWindow, aPrincipal, aDocumentURI, aPrivate, return GetStorageInternal(CreateMode::CreateAlways, aWindow, aPrincipal,
aRetval); aDocumentURI, aPrivate, aRetval);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -395,8 +396,8 @@ StorageManagerBase::GetStorage(mozIDOMWindow* aWindow,
bool aPrivate, bool aPrivate,
nsIDOMStorage** aRetval) nsIDOMStorage** aRetval)
{ {
return GetStorageInternal(false, aWindow, aPrincipal, EmptyString(), aPrivate, return GetStorageInternal(CreateMode::UseIfExistsNeverCreate, aWindow,
aRetval); aPrincipal, EmptyString(), aPrivate, aRetval);
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -90,8 +90,17 @@ private:
const nsACString& aOriginNoSuffix, const nsACString& aOriginNoSuffix,
nsIPrincipal* aPrincipal); nsIPrincipal* aPrincipal);
enum class CreateMode {
// GetStorage: do not create if it's not already in memory.
UseIfExistsNeverCreate,
// CreateStorage: Create it if it's not already in memory.
CreateAlways,
// PrecacheStorage: Create only if the database says we ShouldPreloadOrigin.
CreateIfShouldPreload
};
// Helper for creation of DOM storage objects // Helper for creation of DOM storage objects
nsresult GetStorageInternal(bool aCreate, nsresult GetStorageInternal(CreateMode aCreate,
mozIDOMWindow* aWindow, mozIDOMWindow* aWindow,
nsIPrincipal* aPrincipal, nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI, const nsAString& aDocumentURI,

Просмотреть файл

@ -2,6 +2,7 @@
support-files = support-files =
browser_frame_elements.html browser_frame_elements.html
page_privatestorageevent.html page_privatestorageevent.html
page_localstorage_e10s.html
position.html position.html
test-console-api.html test-console-api.html
test_bug1004814.html test_bug1004814.html
@ -43,6 +44,8 @@ skip-if = e10s
skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires e10s skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires e10s
[browser_largeAllocation_non_win32.js] [browser_largeAllocation_non_win32.js]
skip-if = !e10s || (os == "win" && processor == "x86") # Large-Allocation requires e10s skip-if = !e10s || (os == "win" && processor == "x86") # Large-Allocation requires e10s
[browser_localStorage_e10s.js]
skip-if = !e10s # This is a test of e10s functionality.
[browser_localStorage_privatestorageevent.js] [browser_localStorage_privatestorageevent.js]
[browser_test__content.js] [browser_test__content.js]
[browser_test_focus_after_modal_state.js] [browser_test_focus_after_modal_state.js]

Просмотреть файл

@ -0,0 +1,360 @@
const HELPER_PAGE_URL =
"http://example.com/browser/dom/tests/browser/page_localstorage_e10s.html";
const HELPER_PAGE_ORIGIN = "http://example.com/";
// Simple tab wrapper abstracting our messaging mechanism;
class KnownTab {
constructor(name, tab) {
this.name = name;
this.tab = tab;
}
cleanup() {
this.tab = null;
}
}
// Simple data structure class to help us track opened tabs and their pids.
class KnownTabs {
constructor() {
this.byPid = new Map();
this.byName = new Map();
}
cleanup() {
this.byPid = null;
this.byName = null;
}
}
/**
* Open our helper page in a tab in its own content process, asserting that it
* really is in its own process.
*/
function* openTestTabInOwnProcess(name, knownTabs) {
let url = HELPER_PAGE_URL + '?' + encodeURIComponent(name);
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
let pid = tab.linkedBrowser.frameLoader.tabParent.osPid;
ok(!knownTabs.byName.has(name), "tab needs its own name: " + name);
ok(!knownTabs.byPid.has(pid), "tab needs to be in its own process: " + pid);
let knownTab = new KnownTab(name, tab);
knownTabs.byPid.set(pid, knownTab);
knownTabs.byName.set(name, knownTab);
return knownTab;
}
/**
* Close all the tabs we opened.
*/
function* cleanupTabs(knownTabs) {
for (let knownTab of knownTabs.byName.values()) {
yield BrowserTestUtils.removeTab(knownTab.tab);
knownTab.cleanup();
}
knownTabs.cleanup();
}
/**
* Clear the origin's storage so that "OriginsHavingData" will return false for
* our origin. Note that this is only the case for AsyncClear() which is
* explicitly issued against a cache, or AsyncClearAll() which we can trigger
* by wiping all storage. However, the more targeted domain clearings that
* we can trigger via observer, AsyncClearMatchingOrigin and
* AsyncClearMatchingOriginAttributes will not clear the hashtable entry for
* the origin.
*
* So we explicitly access the cache here in the parent for the origin and issue
* an explicit clear. Clearing all storage might be a little easier but seems
* like asking for intermittent failures.
*/
function clearOriginStorageEnsuringNoPreload() {
let principal =
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
HELPER_PAGE_ORIGIN);
// We want to use createStorage to force the cache to be created so we can
// issue the clear. It's possible for getStorage to return false but for the
// origin preload hash to still have our origin in it.
let storage = Services.domStorageManager.createStorage(null, principal, "");
storage.clear();
// We don't need to wait for anything. The clear call will have queued the
// clear operation on the database thread, and the child process requests
// for origins will likewise be answered via the database thread.
}
function* verifyTabPreload(knownTab, expectStorageExists) {
let storageExists = yield ContentTask.spawn(
knownTab.tab.linkedBrowser,
HELPER_PAGE_ORIGIN,
function(origin) {
let principal =
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
origin);
return !!Services.domStorageManager.getStorage(null, principal);
});
is(storageExists, expectStorageExists, "Storage existence === preload");
}
/**
* Instruct the given tab to execute the given series of mutations. For
* simplicity, the mutations representation matches the expected events rep.
*/
function* mutateTabStorage(knownTab, mutations) {
yield ContentTask.spawn(
knownTab.tab.linkedBrowser,
{ mutations },
function(args) {
return content.wrappedJSObject.mutateStorage(args.mutations);
});
}
/**
* Instruct the given tab to add a "storage" event listener and record all
* received events. verifyTabStorageEvents is the corresponding method to
* check and assert the recorded events.
*/
function* recordTabStorageEvents(knownTab) {
yield ContentTask.spawn(
knownTab.tab.linkedBrowser,
{},
function() {
return content.wrappedJSObject.listenForStorageEvents();
});
}
/**
* Retrieve the current localStorage contents perceived by the tab and assert
* that they match the provided expected state.
*/
function* verifyTabStorageState(knownTab, expectedState) {
let actualState = yield ContentTask.spawn(
knownTab.tab.linkedBrowser,
{},
function() {
return content.wrappedJSObject.getStorageState();
});
for (let [expectedKey, expectedValue] of Object.entries(expectedState)) {
ok(actualState.hasOwnProperty(expectedKey), "key present: " + expectedKey);
is(actualState[expectedKey], expectedValue, "value correct");
}
for (let actualKey of Object.keys(actualState)) {
if (!expectedState.hasOwnProperty(actualKey)) {
ok(false, "actual state has key it shouldn't have: " + actualKey);
}
}
}
/**
* Retrieve and clear the storage events recorded by the tab and assert that
* they match the provided expected events. For simplicity, the expected events
* representation is the same as that used by mutateTabStorage.
*/
function* verifyTabStorageEvents(knownTab, expectedEvents) {
let actualEvents = yield ContentTask.spawn(
knownTab.tab.linkedBrowser,
{},
function() {
return content.wrappedJSObject.returnAndClearStorageEvents();
});
is(actualEvents.length, expectedEvents.length, "right number of events");
for (let i = 0; i < actualEvents.length; i++) {
let [actualKey, actualNewValue, actualOldValue] = actualEvents[i];
let [expectedKey, expectedNewValue, expectedOldValue] = expectedEvents[i];
is(actualKey, expectedKey, "keys match");
is(actualNewValue, expectedNewValue, "new values match");
is(actualOldValue, expectedOldValue, "old values match");
}
}
// We spin up a ton of child processes.
requestLongerTimeout(4);
/**
* Verify the basics of our multi-e10s localStorage support. We are focused on
* whitebox testing two things. When this is being written, broadcast filtering
* is not in place, but the test is intended to attempt to verify that its
* implementation does not break things.
*
* 1) That pages see the same localStorage state in a timely fashion when
* engaging in non-conflicting operations. We are not testing races or
* conflict resolution; the spec does not cover that.
*
* 2) That there are no edge-cases related to when the Storage instance is
* created for the page or the StorageCache for the origin. (StorageCache is
* what actually backs the Storage binding exposed to the page.) This
* matters because the following reasons can exist for them to be created:
* - Preload, on the basis of knowing the origin uses localStorage. The
* interesting edge case is when we have the same origin open in different
* processes and the origin starts using localStorage when it did not
* before. Preload will not have instantiated bindings, which could impact
* correctness.
* - The page accessing localStorage for read or write purposes. This is the
* obvious, boring one.
* - The page adding a "storage" listener. This is less obvious and
* interacts with the preload edge-case mentioned above. The page needs to
* hear "storage" events even if the page has not touched localStorage
* itself and its origin had nothing stored in localStorage when the page
* was created.
*
* We use the same simple child page in all tabs that:
* - can be instructed to listen for and record "storage" events
* - can be instructed to issue a series of localStorage writes
* - can be instructed to return the current entire localStorage contents
*
* We open the 5 following tabs:
* - Open a "writer" tab that does not listen for "storage" events and will
* issue only writes.
* - Open a "listener" tab instructed to listen for "storage" events
* immediately. We expect it to capture all events.
* - Open an "reader" tab that does not listen for "storage" events and will
* only issue reads when instructed.
* - Open a "lateWriteThenListen" tab that initially does nothing. We will
* later tell it to issue a write and then listen for events to make sure it
* captures the later events.
* - Open "lateOpenSeesPreload" tab after we've done everything and ensure that
* it preloads/precaches the data without us having touched localStorage or
* added an event listener.
*/
add_task(function*() {
// - Boost process count so all of our tabs get new processes.
// Our test wants to assert things about the precache status which is only
// populated at process startup and never updated. (Per analysis at
// https://bugzilla.mozilla.org/show_bug.cgi?id=1312022 this still makes
// sense.) https://bugzilla.mozilla.org/show_bug.cgi?id=1312022 introduced
// a mechanism for keeping an arbitrary number of processes alive, modifying
// all browser chrome tests to keep alive whatever dom.ipc.processCount is set
// to. The mechanism was slightly modified later to be type-based, so now
// it's "dom.ipc.keepProcessesAlive.web" we care about.
//
// Our options for ensuring we get a new process are to either:
// 1) Try and push keepalive down to 1 and kill off the processes that are
// already hanging around.
// 2) Just bump the process count up enough so that every tab we open will
// get a new process.
//
// The first option turns out to be hard to get right. Specifically,
// although one can set the keepalive and process counts to 1 and open and
// close tabs to try and trigger process termination down to 1, since we don't
// know how many processes might exist, we can't reliably listen for observer
// notifications of their shutdown to ensure we're avoiding shutdown races.
// (If there are races then the processes won't actually be shut down.) So
// it's easiest to just boost the limit.
let keepAliveCount =
SpecialPowers.getIntPref("dom.ipc.keepProcessesAlive.web", 1);
let safeProcessCount = keepAliveCount + 6;
info("dom.ipc.keepProcessesAlive.web is " + keepAliveCount + ", boosting " +
"process count temporarily to " + safeProcessCount);
// (There's already one about:blank page open and we open 5 new tabs, so 6
// processes. Actually, 7, just in case.)
yield SpecialPowers.pushPrefEnv({
set: [
["dom.ipc.processCount", safeProcessCount],
["dom.ipc.processCount.web", safeProcessCount]
]
});
// Ensure that there is no localstorage data or potential false positives for
// localstorage preloads by forcing the origin to be cleared prior to the
// start of our test.
clearOriginStorageEnsuringNoPreload();
// - Open tabs. Don't configure any of them yet.
const knownTabs = new KnownTabs();
const writerTab = yield* openTestTabInOwnProcess("writer", knownTabs);
const listenerTab = yield* openTestTabInOwnProcess("listener", knownTabs);
const readerTab = yield* openTestTabInOwnProcess("reader", knownTabs);
const lateWriteThenListenTab = yield* openTestTabInOwnProcess(
"lateWriteThenListen", knownTabs);
// Sanity check that preloading did not occur in the tabs.
yield* verifyTabPreload(writerTab, false);
yield* verifyTabPreload(listenerTab, false);
yield* verifyTabPreload(readerTab, false);
// - Configure the tabs.
yield* recordTabStorageEvents(listenerTab);
// - Issue the initial batch of writes and verify.
const initialWriteMutations = [
//[key (null=clear), newValue (null=delete), oldValue (verification)]
["getsCleared", "1", null],
["alsoGetsCleared", "2", null],
[null, null, null],
["stays", "3", null],
["clobbered", "pre", null],
["getsDeletedLater", "4", null],
["getsDeletedImmediately", "5", null],
["getsDeletedImmediately", null, "5"],
["alsoStays", "6", null],
["getsDeletedLater", null, "4"],
["clobbered", "post", "pre"]
];
const initialWriteState = {
stays: "3",
clobbered: "post",
alsoStays: "6"
};
yield* mutateTabStorage(writerTab, initialWriteMutations);
yield* verifyTabStorageState(writerTab, initialWriteState);
yield* verifyTabStorageEvents(listenerTab, initialWriteMutations);
yield* verifyTabStorageState(listenerTab, initialWriteState);
yield* verifyTabStorageState(readerTab, initialWriteState);
// - Issue second set of writes from lateWriteThenListen
const lateWriteMutations = [
["lateStays", "10", null],
["lateClobbered", "latePre", null],
["lateDeleted", "11", null],
["lateClobbered", "lastPost", "latePre"],
["lateDeleted", null, "11"]
];
const lateWriteState = Object.assign({}, initialWriteState, {
lateStays: "10",
lateClobbered: "lastPost"
});
yield* mutateTabStorage(lateWriteThenListenTab, lateWriteMutations);
yield* recordTabStorageEvents(lateWriteThenListenTab);
yield* verifyTabStorageState(writerTab, lateWriteState);
yield* verifyTabStorageEvents(listenerTab, lateWriteMutations);
yield* verifyTabStorageState(listenerTab, lateWriteState);
yield* verifyTabStorageState(readerTab, lateWriteState);
// - Issue last set of writes from writerTab.
const lastWriteMutations = [
["lastStays", "20", null],
["lastDeleted", "21", null],
["lastClobbered", "lastPre", null],
["lastClobbered", "lastPost", "lastPre"],
["lastDeleted", null, "21"]
];
const lastWriteState = Object.assign({}, lateWriteState, {
lastStays: "20",
lastClobbered: "lastPost"
});
yield* mutateTabStorage(writerTab, lastWriteMutations);
yield* verifyTabStorageState(writerTab, lastWriteState);
yield* verifyTabStorageEvents(listenerTab, lastWriteMutations);
yield* verifyTabStorageState(listenerTab, lastWriteState);
yield* verifyTabStorageState(readerTab, lastWriteState);
yield* verifyTabStorageEvents(lateWriteThenListenTab, lastWriteMutations);
yield* verifyTabStorageState(lateWriteThenListenTab, lastWriteState);
// - Open a fresh tab and make sure it sees the precache/preload
const lateOpenSeesPreload =
yield* openTestTabInOwnProcess("lateOpenSeesPreload", knownTabs);
yield* verifyTabPreload(lateOpenSeesPreload, true);
// - Clean up.
yield* cleanupTabs(knownTabs);
clearOriginStorageEnsuringNoPreload();
});

Просмотреть файл

@ -0,0 +1,56 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script>
/**
* Helper page used by browser_localStorage_e10s.js.
**/
var pageName = document.location.search.substring(1);
window.addEventListener(
"load",
() => { document.getElementById("pageNameH").textContent = pageName; });
var recordedEvents = null;
function storageListener(event) {
recordedEvents.push([event.key, event.newValue, event.oldValue]);
}
function listenForStorageEvents() {
recordedEvents = [];
window.addEventListener("storage", storageListener);
}
function mutateStorage(mutations) {
mutations.forEach(function([key, value]) {
if (key !== null) {
if (value === null) {
localStorage.removeItem(key);
} else {
localStorage.setItem(key, value);
}
} else {
localStorage.clear();
}
});
}
function getStorageState() {
let numKeys = localStorage.length;
let state = {};
for (var iKey = 0; iKey < numKeys; iKey++) {
let key = localStorage.key(iKey);
state[key] = localStorage.getItem(key);
}
return state;
}
function returnAndClearStorageEvents() {
let loggedEvents = recordedEvents;
recordedEvents = [];
return loggedEvents;
}
</script>
</head>
<body><h2 id="pageNameH"></h2></body>
</html>

Просмотреть файл

@ -24,7 +24,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=674770
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(function() { SimpleTest.waitForFocus(function() {
SpecialPowers.pushPrefEnv({"set":[["middlemouse.paste", true], ["dom.ipc.processCount", 1]]}, startTests); SpecialPowers.pushPrefEnv({"set":[["middlemouse.paste", true]]}, startTests);
}); });
function startTests() { function startTests() {

Просмотреть файл

@ -33,6 +33,9 @@
#include "plbase64.h" #include "plbase64.h"
#include "plstr.h" #include "plstr.h"
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
#include "mozilla/Tokenizer.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "prmem.h" #include "prmem.h"
#include "prnetdb.h" #include "prnetdb.h"
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
@ -43,6 +46,7 @@
#include "nsIHttpAuthenticatorCallback.h" #include "nsIHttpAuthenticatorCallback.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "nsICancelable.h" #include "nsICancelable.h"
#include "nsUnicharUtils.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -633,13 +637,20 @@ nsHttpNegotiateAuth::TestPref(nsIURI *uri, const char *pref)
return false; return false;
if (NS_FAILED(uri->GetAsciiHost(host))) if (NS_FAILED(uri->GetAsciiHost(host)))
return false; return false;
if (NS_FAILED(uri->GetPort(&port)))
port = NS_GetRealPort(uri);
if (port == -1) {
return false; return false;
}
char *hostList; char *hostList;
if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList) if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList)
return false; return false;
struct FreePolicy { void operator()(void* p) { free(p); } };
mozilla::UniquePtr<char[], FreePolicy> hostListScope;
hostListScope.reset(hostList);
// pseudo-BNF // pseudo-BNF
// ---------- // ----------
// //
@ -652,24 +663,19 @@ nsHttpNegotiateAuth::TestPref(nsIURI *uri, const char *pref)
// "https://, http://office.foo.com" // "https://, http://office.foo.com"
// //
char *start = hostList, *end; mozilla::Tokenizer t(hostList);
for (;;) { while (!t.CheckEOF()) {
// skip past any whitespace t.SkipWhites();
while (*start == ' ' || *start == '\t') nsDependentCSubstring url;
++start; mozilla::Unused << t.ReadUntil(mozilla::Tokenizer::Token::Char(','), url);
end = strchr(start, ','); if (url.IsEmpty()) {
if (!end) continue;
end = start + strlen(start); }
if (start == end) if (MatchesBaseURI(scheme, host, port, url)) {
break;
if (MatchesBaseURI(scheme, host, port, start, end))
return true; return true;
if (*end == '\0') }
break;
start = end + 1;
} }
free(hostList);
return false; return false;
} }
@ -677,54 +683,90 @@ bool
nsHttpNegotiateAuth::MatchesBaseURI(const nsCSubstring &matchScheme, nsHttpNegotiateAuth::MatchesBaseURI(const nsCSubstring &matchScheme,
const nsCSubstring &matchHost, const nsCSubstring &matchHost,
int32_t matchPort, int32_t matchPort,
const char *baseStart, nsDependentCSubstring const& url)
const char *baseEnd)
{ {
// check if scheme://host:port matches baseURI // check if scheme://host:port matches baseURI
// parse the base URI // parse the base URI
const char *hostStart, *schemeEnd = strstr(baseStart, "://"); mozilla::Tokenizer t(url);
if (schemeEnd) { mozilla::Tokenizer::Token token;
// the given scheme must match the parsed scheme exactly
if (!matchScheme.Equals(Substring(baseStart, schemeEnd)))
return false;
hostStart = schemeEnd + 3;
}
else
hostStart = baseStart;
// XXX this does not work for IPv6-literals t.SkipWhites();
const char *hostEnd = strchr(hostStart, ':');
if (hostEnd && hostEnd < baseEnd) { // We don't know if the url to check against starts with scheme
// the given port must match the parsed port exactly // or a host name. Start recording here.
int port = atoi(hostEnd + 1); t.Record();
if (matchPort != (int32_t) port)
mozilla::Unused << t.Next(token);
// The ipv6 literals MUST be enclosed with [] in the preference.
bool ipv6 = false;
if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
nsDependentCSubstring ipv6BareLiteral;
if (!t.ReadUntil(mozilla::Tokenizer::Token::Char(']'), ipv6BareLiteral)) {
// Broken ipv6 literal
return false; return false;
} }
else
hostEnd = baseEnd;
nsDependentCSubstring ipv6Literal;
t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
if (!matchHost.Equals(ipv6Literal, nsCaseInsensitiveUTF8StringComparator()) &&
!matchHost.Equals(ipv6BareLiteral, nsCaseInsensitiveUTF8StringComparator())) {
return false;
}
// if we didn't parse out a host, then assume we got a match. ipv6 = true;
if (hostStart == hostEnd) } else if (t.CheckChar(':') && t.CheckChar('/') && t.CheckChar('/')) {
if (!matchScheme.Equals(token.Fragment())) {
return false;
}
// Re-start recording the hostname from the point after scheme://.
t.Record();
}
while (t.Next(token)) {
bool eof = token.Equals(mozilla::Tokenizer::Token::EndOfFile());
bool port = token.Equals(mozilla::Tokenizer::Token::Char(':'));
if (eof || port) {
if (!ipv6) { // Match already performed above.
nsDependentCSubstring hostName;
t.Claim(hostName);
// An empty hostname means to accept everything for the schema
if (!hostName.IsEmpty()) {
if (hostName.First() == '.') {
if (!StringEndsWith(matchHost, hostName, nsCaseInsensitiveUTF8StringComparator())) {
return false;
}
} else { // host to match doesn't begin with '.', do a full compare
if (!matchHost.Equals(hostName, nsCaseInsensitiveUTF8StringComparator())) {
return false;
}
}
}
}
if (port) {
uint16_t portNumber;
if (!t.ReadInteger(&portNumber)) {
// Missing port number
return false;
}
if (matchPort != portNumber) {
return false;
}
if (!t.CheckEOF()) {
return false;
}
}
} else if (ipv6) {
// After an ipv6 literal there can only be EOF or :port. Everything else
// must be treated as non-match/broken input.
return false;
}
}
// All negative checks has passed positively.
return true; return true;
uint32_t hostLen = hostEnd - hostStart;
// matchHost must either equal host or be a subdomain of host
if (matchHost.Length() < hostLen)
return false;
const char *end = matchHost.EndReading();
if (PL_strncasecmp(end - hostLen, hostStart, hostLen) == 0) {
// if matchHost ends with host from the base URI, then make sure it is
// either an exact match, or prefixed with a dot. we don't want
// "foobar.com" to match "bar.com"
if (matchHost.Length() == hostLen ||
*(end - hostLen) == '.' ||
*(end - hostLen - 1) == '.')
return true;
}
return false;
} }

Просмотреть файл

@ -36,8 +36,7 @@ private:
bool MatchesBaseURI(const nsCSubstring &scheme, bool MatchesBaseURI(const nsCSubstring &scheme,
const nsCSubstring &host, const nsCSubstring &host,
int32_t port, int32_t port,
const char *baseStart, nsDependentCSubstring const& url);
const char *baseEnd);
// Thread for GenerateCredentialsAsync // Thread for GenerateCredentialsAsync
RefPtr<mozilla::LazyIdleThread> mNegotiateThread; RefPtr<mozilla::LazyIdleThread> mNegotiateThread;
}; };

Просмотреть файл

@ -130,7 +130,7 @@ nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
rv = xpc->EvalInSandboxObject(convertedScript, filename, cx, rv = xpc->EvalInSandboxObject(convertedScript, filename, cx,
autoconfigSb, JSVERSION_LATEST, &v); autoconfigSb, &v);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return NS_OK; return NS_OK;

Просмотреть файл

@ -40,14 +40,36 @@ SourceSurfaceSkia::GetFormat() const
return mFormat; return mFormat;
} }
static sk_sp<SkData>
MakeSkData(unsigned char* aData, const IntSize& aSize, int32_t aStride)
{
CheckedInt<size_t> size = aStride;
size *= aSize.height;
if (size.isValid()) {
void* mem = sk_malloc_flags(size.value(), 0);
if (mem) {
if (aData) {
memcpy(mem, aData, size.value());
}
return SkData::MakeFromMalloc(mem, size.value());
}
}
return nullptr;
}
bool bool
SourceSurfaceSkia::InitFromData(unsigned char* aData, SourceSurfaceSkia::InitFromData(unsigned char* aData,
const IntSize &aSize, const IntSize &aSize,
int32_t aStride, int32_t aStride,
SurfaceFormat aFormat) SurfaceFormat aFormat)
{ {
SkPixmap pixmap(MakeSkiaImageInfo(aSize, aFormat), aData, aStride); sk_sp<SkData> data = MakeSkData(aData, aSize, aStride);
mImage = SkImage::MakeRasterCopy(pixmap); if (!data) {
return false;
}
SkImageInfo info = MakeSkiaImageInfo(aSize, aFormat);
mImage = SkImage::MakeRasterData(info, data, aStride);
if (!mImage) { if (!mImage) {
return false; return false;
} }
@ -106,16 +128,12 @@ SourceSurfaceSkia::GetData()
#ifdef USE_SKIA_GPU #ifdef USE_SKIA_GPU
if (mImage->isTextureBacked()) { if (mImage->isTextureBacked()) {
sk_sp<SkImage> raster; sk_sp<SkImage> raster;
CheckedInt<size_t> size = mStride; if (sk_sp<SkData> data = MakeSkData(nullptr, mSize, mStride)) {
size *= mSize.height;
if (size.isValid()) {
if (sk_sp<SkData> data = SkData::MakeUninitialized(size.value())) {
SkImageInfo info = MakeSkiaImageInfo(mSize, mFormat); SkImageInfo info = MakeSkiaImageInfo(mSize, mFormat);
if (mImage->readPixels(info, data->writable_data(), mStride, 0, 0, SkImage::kDisallow_CachingHint)) { if (mImage->readPixels(info, data->writable_data(), mStride, 0, 0, SkImage::kDisallow_CachingHint)) {
raster = SkImage::MakeRasterData(info, data, mStride); raster = SkImage::MakeRasterData(info, data, mStride);
} }
} }
}
if (raster) { if (raster) {
mImage = raster; mImage = raster;
} else { } else {

Просмотреть файл

@ -51,7 +51,8 @@ static const char* sEGLExtensionNames[] = {
"EGL_ANDROID_native_fence_sync", "EGL_ANDROID_native_fence_sync",
"EGL_ANDROID_image_crop", "EGL_ANDROID_image_crop",
"EGL_ANGLE_platform_angle", "EGL_ANGLE_platform_angle",
"EGL_ANGLE_platform_angle_d3d" "EGL_ANGLE_platform_angle_d3d",
"EGL_ANGLE_d3d_share_handle_client_buffer"
}; };
#if defined(ANDROID) #if defined(ANDROID)
@ -414,6 +415,7 @@ GLLibraryEGL::EnsureInitialized(bool forceAccel, nsACString* const out_failureId
SYMBOL(BindTexImage), SYMBOL(BindTexImage),
SYMBOL(ReleaseTexImage), SYMBOL(ReleaseTexImage),
SYMBOL(QuerySurface), SYMBOL(QuerySurface),
SYMBOL(CreatePbufferFromClientBuffer),
{ nullptr, { nullptr } } { nullptr, { nullptr } }
}; };

Просмотреть файл

@ -133,6 +133,7 @@ public:
mSymbols.fDestroySurface = nullptr; mSymbols.fDestroySurface = nullptr;
mSymbols.fCreateWindowSurface = nullptr; mSymbols.fCreateWindowSurface = nullptr;
mSymbols.fCreatePbufferSurface = nullptr; mSymbols.fCreatePbufferSurface = nullptr;
mSymbols.fCreatePbufferFromClientBuffer = nullptr;
mSymbols.fCreatePixmapSurface = nullptr; mSymbols.fCreatePixmapSurface = nullptr;
mSymbols.fBindAPI = nullptr; mSymbols.fBindAPI = nullptr;
mSymbols.fInitialize = nullptr; mSymbols.fInitialize = nullptr;
@ -185,6 +186,7 @@ public:
EGL_ANDROID_image_crop, EGL_ANDROID_image_crop,
ANGLE_platform_angle, ANGLE_platform_angle,
ANGLE_platform_angle_d3d, ANGLE_platform_angle_d3d,
ANGLE_d3d_share_handle_client_buffer,
Extensions_Max Extensions_Max
}; };
@ -289,6 +291,14 @@ public:
return surf; return surf;
} }
EGLSurface fCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
{
BEFORE_GL_CALL;
EGLSurface ret = mSymbols.fCreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
AFTER_GL_CALL;
return ret;
}
EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint* attrib_list) EGLSurface fCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint* attrib_list)
{ {
BEFORE_GL_CALL; BEFORE_GL_CALL;
@ -585,6 +595,8 @@ public:
pfnCreateWindowSurface fCreateWindowSurface; pfnCreateWindowSurface fCreateWindowSurface;
typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list); typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list);
pfnCreatePbufferSurface fCreatePbufferSurface; pfnCreatePbufferSurface fCreatePbufferSurface;
typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferFromClientBuffer)(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
pfnCreatePbufferFromClientBuffer fCreatePbufferFromClientBuffer;
typedef EGLSurface (GLAPIENTRY * pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint* attrib_list); typedef EGLSurface (GLAPIENTRY * pfnCreatePixmapSurface)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint* attrib_list);
pfnCreatePixmapSurface fCreatePixmapSurface; pfnCreatePixmapSurface fCreatePixmapSurface;
typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api); typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api);

Просмотреть файл

@ -107,6 +107,8 @@ DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
dateStyle = UDAT_SHORT; dateStyle = UDAT_SHORT;
break; break;
case kDateFormatYearMonth: case kDateFormatYearMonth:
case kDateFormatYearMonthLong:
case kDateFormatMonthLong:
case kDateFormatWeekday: case kDateFormatWeekday:
dateStyle = UDAT_PATTERN; dateStyle = UDAT_PATTERN;
break; break;
@ -169,7 +171,23 @@ DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
} }
} }
nsAutoString skeleton(aDateFormatSelector == kDateFormatYearMonth ? u"yyyyMM " : u"EEE "); nsAutoString skeleton;
switch (aDateFormatSelector) {
case kDateFormatYearMonth:
skeleton.AssignLiteral("yyyyMM ");
break;
case kDateFormatYearMonthLong:
skeleton.AssignLiteral("yyyyMMMM ");
break;
case kDateFormatMonthLong:
skeleton.AssignLiteral("MMMM ");
break;
case kDateFormatWeekday:
skeleton.AssignLiteral("EEE ");
break;
default:
break;
}
int32_t dateSkeletonLen = skeleton.Length(); int32_t dateSkeletonLen = skeleton.Length();
if (timeStyle != UDAT_NONE) { if (timeStyle != UDAT_NONE) {

Просмотреть файл

@ -13,6 +13,8 @@ enum
kDateFormatLong, // provides the long date format for the given locale kDateFormatLong, // provides the long date format for the given locale
kDateFormatShort, // provides the short date format for the given locale kDateFormatShort, // provides the short date format for the given locale
kDateFormatYearMonth, // formats using only the year and month kDateFormatYearMonth, // formats using only the year and month
kDateFormatYearMonthLong, // long version of kDateFormatYearMonth
kDateFormatMonthLong, // long format of month name only
kDateFormatWeekday // week day (e.g. Mon, Tue) kDateFormatWeekday // week day (e.g. Mon, Tue)
}; };
%} %}

Просмотреть файл

@ -58,6 +58,14 @@ TEST(DateTimeFormat, DateFormatSelectors) {
ASSERT_TRUE(NS_SUCCEEDED(rv)); ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("01/1970", NS_ConvertUTF16toUTF8(formattedTime).get()); ASSERT_STREQ("01/1970", NS_ConvertUTF16toUTF8(formattedTime).get());
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatYearMonthLong, kTimeFormatNone, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January 1970", NS_ConvertUTF16toUTF8(formattedTime).get());
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatMonthLong, kTimeFormatNone, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("January", NS_ConvertUTF16toUTF8(formattedTime).get());
rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatYearMonth, kTimeFormatNoSeconds, &prExplodedTime, formattedTime); rv = mozilla::DateTimeFormat::FormatPRExplodedTime(kDateFormatYearMonth, kTimeFormatNoSeconds, &prExplodedTime, formattedTime);
ASSERT_TRUE(NS_SUCCEEDED(rv)); ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("01/1970, 12:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get()); ASSERT_STREQ("01/1970, 12:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());

Просмотреть файл

@ -545,6 +545,22 @@ IProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
Manager()->SetEventTargetForActorInternal(aActor, aEventTarget); Manager()->SetEventTargetForActorInternal(aActor, aEventTarget);
} }
nsIEventTarget*
IProtocol::GetActorEventTarget()
{
// We should only call this function when this actor has been registered and
// is not unregistered yet.
MOZ_RELEASE_ASSERT(mId != kNullActorId && mId != kFreedActorId);
RefPtr<nsIEventTarget> target = Manager()->GetActorEventTargetInternal(this);
return target;
}
already_AddRefed<nsIEventTarget>
IProtocol::GetActorEventTargetInternal(IProtocol* aActor)
{
return Manager()->GetActorEventTargetInternal(aActor);
}
IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId, Side aSide) IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId, Side aSide)
: IProtocol(aSide), : IProtocol(aSide),
mProtocolId(aProtoId), mProtocolId(aProtoId),
@ -802,7 +818,7 @@ IToplevelProtocol::GetMessageEventTarget(const Message& aMsg)
} }
already_AddRefed<nsIEventTarget> already_AddRefed<nsIEventTarget>
IToplevelProtocol::GetActorEventTarget(IProtocol* aActor) IToplevelProtocol::GetActorEventTargetInternal(IProtocol* aActor)
{ {
MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId); MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId);
@ -811,10 +827,26 @@ IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
return target.forget(); return target.forget();
} }
already_AddRefed<nsIEventTarget>
IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
{
return GetActorEventTargetInternal(aActor);
}
nsIEventTarget*
IToplevelProtocol::GetActorEventTarget()
{
// The EventTarget of a ToplevelProtocol shall never be set.
return nullptr;
}
void void
IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor, IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
nsIEventTarget* aEventTarget) nsIEventTarget* aEventTarget)
{ {
// The EventTarget of a ToplevelProtocol shall never be set.
MOZ_RELEASE_ASSERT(aActor != this);
// We should only call this function on actors that haven't been used for IPC // We should only call this function on actors that haven't been used for IPC
// code yet. Otherwise we'll be posting stuff to the wrong event target before // code yet. Otherwise we'll be posting stuff to the wrong event target before
// we're called. // we're called.

Просмотреть файл

@ -189,6 +189,9 @@ public:
// aActor. // aActor.
void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget); void SetEventTargetForActor(IProtocol* aActor, nsIEventTarget* aEventTarget);
// Returns the event target set by SetEventTargetForActor() if available.
virtual nsIEventTarget* GetActorEventTarget();
protected: protected:
friend class IToplevelProtocol; friend class IToplevelProtocol;
@ -198,6 +201,9 @@ protected:
virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget); virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
virtual already_AddRefed<nsIEventTarget>
GetActorEventTargetInternal(IProtocol* aActor);
static const int32_t kNullActorId = 0; static const int32_t kNullActorId = 0;
static const int32_t kFreedActorId = 1; static const int32_t kFreedActorId = 1;
@ -365,12 +371,18 @@ public:
already_AddRefed<nsIEventTarget> already_AddRefed<nsIEventTarget>
GetActorEventTarget(IProtocol* aActor); GetActorEventTarget(IProtocol* aActor);
virtual nsIEventTarget*
GetActorEventTarget();
protected: protected:
virtual already_AddRefed<nsIEventTarget> virtual already_AddRefed<nsIEventTarget>
GetConstructedEventTarget(const Message& aMsg) { return nullptr; } GetConstructedEventTarget(const Message& aMsg) { return nullptr; }
virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget); virtual void SetEventTargetForActorInternal(IProtocol* aActor, nsIEventTarget* aEventTarget);
virtual already_AddRefed<nsIEventTarget>
GetActorEventTargetInternal(IProtocol* aActor);
private: private:
ProtocolId mProtocolId; ProtocolId mProtocolId;
UniquePtr<Transport> mTrans; UniquePtr<Transport> mTrans;

Просмотреть файл

@ -19,6 +19,7 @@ ipdl: $(ALL_IPDLSRCS)
$(PYTHON) $(topsrcdir)/config/pythonpath.py \ $(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) \ $(PLY_INCLUDE) \
$(srcdir)/ipdl.py \ $(srcdir)/ipdl.py \
--sync-msg-list=$(srcdir)/sync-messages.ini \
--outheaders-dir=_ipdlheaders \ --outheaders-dir=_ipdlheaders \
--outcpp-dir=. \ --outcpp-dir=. \
$(IPDLDIRS:%=-I%) \ $(IPDLDIRS:%=-I%) \

Просмотреть файл

@ -7,6 +7,7 @@ from cStringIO import StringIO
from mozbuild.pythonutil import iter_modules_in_path from mozbuild.pythonutil import iter_modules_in_path
import mozpack.path as mozpath import mozpack.path as mozpath
import itertools import itertools
from ConfigParser import RawConfigParser
import ipdl import ipdl
@ -20,6 +21,8 @@ op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
op.add_option('-I', '--include', dest='includedirs', default=[ ], op.add_option('-I', '--include', dest='includedirs', default=[ ],
action='append', action='append',
help='Additional directory to search for included protocol specifications') help='Additional directory to search for included protocol specifications')
op.add_option('-s', '--sync-msg-list', dest='syncMsgList', default='sync-messages.ini',
help="Config file listing allowed sync messages")
op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count', op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count',
help='Verbose logging (specify -vv or -vvv for very verbose logging)') help='Verbose logging (specify -vv or -vvv for very verbose logging)')
op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0, op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0,
@ -35,9 +38,9 @@ A protocol Foo in the namespace bar will cause the sources
cppdir/FooParent.cpp, cppdir/FooChild.cpp cppdir/FooParent.cpp, cppdir/FooChild.cpp
to be generated""") to be generated""")
options, files = op.parse_args() options, files = op.parse_args()
_verbosity = options.verbosity _verbosity = options.verbosity
syncMsgList = options.syncMsgList
headersdir = options.headersdir headersdir = options.headersdir
cppdir = options.cppdir cppdir = options.cppdir
includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ] includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
@ -113,6 +116,11 @@ def normalizedFilename(f):
return '<stdin>' return '<stdin>'
return f return f
log(2, 'Reading sync message list')
parser = RawConfigParser()
parser.readfp(open(options.syncMsgList))
syncMsgList = parser.sections()
# First pass: parse and type-check all protocols # First pass: parse and type-check all protocols
for f in files: for f in files:
log(2, os.path.basename(f)) log(2, os.path.basename(f))
@ -135,6 +143,10 @@ for f in files:
print >>sys.stderr, 'Specification is not well typed.' print >>sys.stderr, 'Specification is not well typed.'
sys.exit(1) sys.exit(1)
if not ipdl.checkSyncMessage(ast, syncMsgList):
print >>sys.stderr, 'Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s' % options.syncMsgList
sys.exit(1)
if _verbosity > 2: if _verbosity > 2:
log(3, ' pretty printed code:') log(3, ' pretty printed code:')
ipdl.genipdl(ast, codedir) ipdl.genipdl(ast, codedir)

Просмотреть файл

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this # License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified' ] __all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified', 'checkSyncMessage' ]
import os, sys import os, sys
from cStringIO import StringIO from cStringIO import StringIO
@ -11,6 +11,7 @@ from ipdl.cgen import IPDLCodeGen
from ipdl.lower import LowerToCxx, msgenums from ipdl.lower import LowerToCxx, msgenums
from ipdl.parser import Parser, ParseError from ipdl.parser import Parser, ParseError
from ipdl.type import TypeCheck from ipdl.type import TypeCheck
from ipdl.checker import checkSyncMessage
from ipdl.cxx.cgen import CxxCodeGen from ipdl.cxx.cgen import CxxCodeGen

43
ipc/ipdl/ipdl/checker.py Normal file
Просмотреть файл

@ -0,0 +1,43 @@
# vim: set ts=4 sw=4 tw=99 et:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import sys
from ipdl.ast import Visitor, ASYNC
class SyncMessageChecker(Visitor):
def __init__(self, syncMsgList):
self.syncMsgList = syncMsgList
self.errors = []
def prettyMsgName(self, msg):
return "%s::%s" % (self.currentProtocol, msg)
def errorUnknownSyncMessage(self, loc, msg):
self.errors.append('%s: error: Unknown sync IPC message %s' %
(str(loc), msg))
def errorAsyncMessageCanRemove(self, loc, msg):
self.errors.append('%s: error: IPC message %s is async, can be delisted' %
(str(loc), msg))
def visitProtocol(self, p):
self.currentProtocol = p.name
Visitor.visitProtocol(self, p)
def visitMessageDecl(self, md):
pn = self.prettyMsgName(md.name)
if md.sendSemantics is not ASYNC and pn not in self.syncMsgList:
self.errorUnknownSyncMessage(md.loc, pn)
if md.sendSemantics is ASYNC and pn in self.syncMsgList:
self.errorAsyncMessageCanRemove(md.loc, pn)
def checkSyncMessage(tu, syncMsgList, errout=sys.stderr):
checker = SyncMessageChecker(syncMsgList)
tu.accept(checker)
if len(checker.errors):
for error in checker.errors:
print >>errout, error
return False
return True

1013
ipc/ipdl/sync-messages.ini Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -13,5 +13,6 @@ check::
$(PYTHON) $(topsrcdir)/config/pythonpath.py \ $(PYTHON) $(topsrcdir)/config/pythonpath.py \
$(PLY_INCLUDE) \ $(PLY_INCLUDE) \
$(topsrcdir)/ipc/ipdl/ipdl.py \ $(topsrcdir)/ipc/ipdl/ipdl.py \
-s $(srcdir)/sync-messages.ini \
OKTESTS $(OKTESTS) \ OKTESTS $(OKTESTS) \
ERRORTESTS $(ERRORTESTS) ERRORTESTS $(ERRORTESTS)

Просмотреть файл

@ -0,0 +1,4 @@
protocol asyncMessageListed {
parent:
async Msg();
};

Просмотреть файл

@ -0,0 +1,4 @@
intr protocol unknownSyncMessage {
parent:
intr Msg();
};

Просмотреть файл

@ -0,0 +1,4 @@
sync protocol unknownSyncMessage {
parent:
sync Msg();
};

Просмотреть файл

@ -0,0 +1,22 @@
[actorreturn::Msg]
[array_Union::Msg]
[union_Basic::Msg]
[Struct::test]
[intrProtocol::SyncMsg]
[intrProtocol::InterruptMsg]
[shmem::SyncMsg]
[shmem::InterruptMsg]
[syncProtocol::SyncMsg]
[messageVerify::__delete__]
[messageVerify::msg3]
[messageVerify::msg4]
[messageVerifyTopLevel::messageVerify]
[DeleteSub::__delete__]
[intrMessageCompress::foo]
[intrMessageCompress::bar]
[syncMessageCompress::foo]
[syncParentToChild::Msg]
[tooWeakIntrSync::Msg]
[tooWeakSyncAsync::Msg]
[undeclReturnType::Msg]
[asyncMessageListed::Msg]

Просмотреть файл

@ -8052,6 +8052,8 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME); MUST_MATCH_TOKEN_FUNC(TokenKindIsPossibleIdentifier, JSMSG_NO_VARIABLE_NAME);
RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword)); RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword));
if (!name)
return null();
if (name == context->names().let) { if (name == context->names().let) {
error(JSMSG_LET_COMP_BINDING); error(JSMSG_LET_COMP_BINDING);
return null(); return null();

Просмотреть файл

@ -35,6 +35,9 @@ function mismatchError(actual, expect) {
return RegExp(str); return RegExp(str);
} }
const emptyStackError = /from empty stack/;
const unusedValuesError = /unused values not explicitly dropped by end of block/;
function jsify(wasmVal) { function jsify(wasmVal) {
if (wasmVal === 'nan') if (wasmVal === 'nan')
return NaN; return NaN;

Просмотреть файл

@ -0,0 +1,16 @@
if (helperThreadCount() === 0)
quit();
setInterruptCallback(function() { print("MainThread Interrupt!"); cooperativeYield(); return true; });
evalInCooperativeThread('\
setInterruptCallback(function() { print("Worker Interrupt!"); cooperativeYield(); return true; });\
for (var i = 0; i < 10; i++) {\
print("Worker: " + i);\
interruptIf(true);\
}\
print("Worker Done!");\
');
for (var i = 0; i < 10; i++) {
print("MainThread: " + i);
interruptIf(true);
}
print("MainThread Done!");

Просмотреть файл

@ -0,0 +1,7 @@
if (helperThreadCount() === 0)
quit();
evalInCooperativeThread("var x = 3");
evalInCooperativeThread("cooperativeYield()");
cooperativeYield();
evalInCooperativeThread("cooperativeYield(); gc();");
gc();

Просмотреть файл

@ -58,8 +58,8 @@ wasmFailValidateText('(module (func) (func) (export "a" 0) (export "a" 1))', /du
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// signatures // signatures
wasmFailValidateText('(module (func (result i32)))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32)))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (nop)))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (nop)))', emptyStackError);
wasmValidateText('(module (func (nop)))'); wasmValidateText('(module (func (nop)))');
wasmValidateText('(module (func (result i32) (i32.const 42)))'); wasmValidateText('(module (func (result i32) (i32.const 42)))');
@ -196,7 +196,7 @@ wasmFullPass('(module (func (result f32) (param i32) (local f32) (get_local 1))
wasmFailValidateText('(module (func (set_local 0 (i32.const 0))))', /set_local index out of range/); wasmFailValidateText('(module (func (set_local 0 (i32.const 0))))', /set_local index out of range/);
wasmFailValidateText('(module (func (local f32) (set_local 0 (i32.const 0))))', mismatchError("i32", "f32")); wasmFailValidateText('(module (func (local f32) (set_local 0 (i32.const 0))))', mismatchError("i32", "f32"));
wasmFailValidateText('(module (func (local f32) (set_local 0 (nop))))', /popping value from empty stack/); wasmFailValidateText('(module (func (local f32) (set_local 0 (nop))))', emptyStackError);
wasmFailValidateText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))', mismatchError("f32", "i32")); wasmFailValidateText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))', mismatchError("f32", "i32"));
wasmFailValidateText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))', mismatchError("i32", "f32")); wasmFailValidateText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))', mismatchError("i32", "f32"));
@ -217,9 +217,9 @@ wasmValidateText('(module (func (local i32) (local $a f32) (set_local 0 (i32.con
wasmFullPass('(module (func (block )) (export "run" 0))', undefined); wasmFullPass('(module (func (block )) (export "run" 0))', undefined);
wasmFailValidateText('(module (func (result i32) (block )))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (block )))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (block (block ))))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (block (block ))))', emptyStackError);
wasmFailValidateText('(module (func (local i32) (set_local 0 (block ))))', /popping value from empty stack/); wasmFailValidateText('(module (func (local i32) (set_local 0 (block ))))', emptyStackError);
wasmFullPass('(module (func (block (block ))) (export "run" 0))', undefined); wasmFullPass('(module (func (block (block ))) (export "run" 0))', undefined);
wasmFullPass('(module (func (result i32) (block i32 (i32.const 42))) (export "run" 0))', 42); wasmFullPass('(module (func (result i32) (block i32 (i32.const 42))) (export "run" 0))', 42);
@ -234,9 +234,9 @@ wasmFullPass('(module (func (result i32) (local i32) (set_local 0 (i32.const 42)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// calls // calls
wasmFailValidateText('(module (func (nop)) (func (call 0 (i32.const 0))))', /unused values not explicitly dropped by end of block/); wasmFailValidateText('(module (func (nop)) (func (call 0 (i32.const 0))))', unusedValuesError);
wasmFailValidateText('(module (func (param i32) (nop)) (func (call 0)))', /peeking at value from outside block/); wasmFailValidateText('(module (func (param i32) (nop)) (func (call 0)))', emptyStackError);
wasmFailValidateText('(module (func (param f32) (nop)) (func (call 0 (i32.const 0))))', mismatchError("i32", "f32")); wasmFailValidateText('(module (func (param f32) (nop)) (func (call 0 (i32.const 0))))', mismatchError("i32", "f32"));
wasmFailValidateText('(module (func (nop)) (func (call 3)))', /callee index out of range/); wasmFailValidateText('(module (func (nop)) (func (call 3)))', /callee index out of range/);
@ -250,8 +250,8 @@ assertThrowsInstanceOf(() => wasmEvalText('(module (func (call 1)) (func (call 0
wasmValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (f32.const nan))))'); wasmValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (f32.const nan))))');
wasmFailValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32")); wasmFailValidateText('(module (func (param i32 f32)) (func (call 0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
wasmFailValidateText('(module (import "a" "") (func (call 0 (i32.const 0))))', /unused values not explicitly dropped by end of block/); wasmFailValidateText('(module (import "a" "") (func (call 0 (i32.const 0))))', unusedValuesError);
wasmFailValidateText('(module (import "a" "" (param i32)) (func (call 0)))', /peeking at value from outside block/); wasmFailValidateText('(module (import "a" "" (param i32)) (func (call 0)))', emptyStackError);
wasmFailValidateText('(module (import "a" "" (param f32)) (func (call 0 (i32.const 0))))', mismatchError("i32", "f32")); wasmFailValidateText('(module (import "a" "" (param f32)) (func (call 0 (i32.const 0))))', mismatchError("i32", "f32"));
assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call 1)))'), TypeError, noImportObj); assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call 1)))'), TypeError, noImportObj);
@ -462,11 +462,12 @@ wasmValidateText('(module (import $bar "" "a") (func (call $bar)) (func $foo (no
wasmFailValidateText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32")); wasmFailValidateText('(module (func (select (i32.const 0) (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
wasmFailValidateText('(module (func (select (i32.const 0) (f32.const 0) (i32.const 0))) (export "" 0))', /select operand types must match/); wasmFailValidateText('(module (func (select (i32.const 0) (f32.const 0) (i32.const 0))) (export "" 0))', /select operand types must match/);
wasmFailValidateText('(module (func (select (block ) (i32.const 0) (i32.const 0))) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func (select (block ) (i32.const 0) (i32.const 0))) (export "" 0))', emptyStackError);
assertEq(wasmEvalText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))').exports[""](), undefined); wasmFailValidateText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))', unusedValuesError);
assertEq(wasmEvalText('(module (func (i32.add (i32.const 0) (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), undefined); assertEq(wasmEvalText('(module (func (drop (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), undefined);
assertEq(wasmEvalText('(module (func (result i32) (i32.add (i32.const 0) (select (return (i32.const 42)) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), 42);
wasmFailValidateText('(module (func (select (if i32 (i32.const 1) (i32.const 0) (f32.const 0)) (i32.const 0) (i32.const 0))) (export "" 0))', mismatchError("f32", "i32")); wasmFailValidateText('(module (func (select (if i32 (i32.const 1) (i32.const 0) (f32.const 0)) (i32.const 0) (i32.const 0))) (export "" 0))', mismatchError("f32", "i32"));
wasmFailValidateText('(module (func) (func (select (call 0) (call 0) (i32.const 0))) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func) (func (select (call 0) (call 0) (i32.const 0))) (export "" 0))', emptyStackError);
(function testSideEffects() { (function testSideEffects() {

Просмотреть файл

@ -157,11 +157,11 @@ assertEq(counter, 0);
// "if" doesn't return an expression value // "if" doesn't return an expression value
wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 42) (i32.const 0))))', /if without else with a result value/); wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 42) (i32.const 0))))', /if without else with a result value/);
wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 42) (drop (i32.const 0)))))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 42) (drop (i32.const 0)))))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 1) (i32.const 0) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/); wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 1) (i32.const 0) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/);
wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (if i32 (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))', emptyStackError);
wasmFailValidateText('(module (func (if i32 (i32.const 1) (i32.const 0) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/); wasmFailValidateText('(module (func (if i32 (i32.const 1) (i32.const 0) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/);
wasmFailValidateText('(module (func (if i32 (i32.const 1) (i32.const 0) (if (i32.const 1) (drop (i32.const 1))))))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (if i32 (i32.const 1) (i32.const 0) (if (i32.const 1) (drop (i32.const 1))))))', emptyStackError);
wasmFailValidateText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/); wasmFailValidateText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if i32 (i32.const 1) (i32.const 1)))))', /if without else with a result value/);
wasmEvalText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))'); wasmEvalText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if (i32.const 1) (drop (i32.const 1))))))');
@ -170,18 +170,18 @@ wasmEvalText('(module (func (if (i32.const 1) (drop (i32.const 0)) (if (i32.cons
wasmFullPass('(module (func (return)) (export "run" 0))', undefined); wasmFullPass('(module (func (return)) (export "run" 0))', undefined);
wasmFullPass('(module (func (result i32) (return (i32.const 1))) (export "run" 0))', 1); wasmFullPass('(module (func (result i32) (return (i32.const 1))) (export "run" 0))', 1);
wasmFullPass('(module (func (if (return) (i32.const 0))) (export "run" 0))', undefined); wasmFailValidateText('(module (func (if (return) (i32.const 0))) (export "run" 0))', unusedValuesError);
wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', emptyStackError);
wasmFullPass('(module (func (return (i32.const 1))) (export "run" 0))', undefined); wasmFullPass('(module (func (return (i32.const 1))) (export "run" 0))', undefined);
wasmFailValidateText('(module (func (result f32) (return (i32.const 1))) (export "" 0))', mismatchError("i32", "f32")); wasmFailValidateText('(module (func (result f32) (return (i32.const 1))) (export "" 0))', mismatchError("i32", "f32"));
wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', emptyStackError);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// br / br_if // br / br_if
wasmFailValidateText('(module (func (result i32) (block (br 0))) (export "" 0))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (block (br 0))) (export "" 0))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (br 0)) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func (result i32) (br 0)) (export "" 0))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (block (br_if 0 (i32.const 0)))) (export "" 0))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (block (br_if 0 (i32.const 0)))) (export "" 0))', emptyStackError);
const DEPTH_OUT_OF_BOUNDS = /branch depth exceeds current nesting level/; const DEPTH_OUT_OF_BOUNDS = /branch depth exceeds current nesting level/;
@ -197,14 +197,14 @@ wasmFailValidateText('(module (func (block (br_if 2 (i32.const 0)))))', DEPTH_OU
wasmFailValidateText('(module (func (loop (br_if 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS); wasmFailValidateText('(module (func (loop (br_if 2 (i32.const 0)))))', DEPTH_OUT_OF_BOUNDS);
wasmFailValidateText(`(module (func (result i32) wasmFailValidateText(`(module (func (result i32)
(block block
(if br 0
(br 0) if
(i32.const 0) i32.const 0
(i32.const 2) i32.const 2
) end
) end
) (export "" 0))`, mismatchError("void", "i32")); ) (export "" 0))`, unusedValuesError);
wasmFullPass(`(module (func (block $out (br_if $out (br 0)))) (export "run" 0))`, undefined); wasmFullPass(`(module (func (block $out (br_if $out (br 0)))) (export "run" 0))`, undefined);
@ -273,6 +273,7 @@ wasmFullPass(`(module (func
(i32.const 0) (i32.const 0)
(return (br 0)) (return (br 0))
) )
drop
) )
(return) (return)
) (export "run" 0))`, undefined); ) (export "run" 0))`, undefined);
@ -308,9 +309,9 @@ assertEq(isNonZero(-1), 1);
// branches with values // branches with values
// br/br_if and block // br/br_if and block
wasmFailValidateText('(module (func (result i32) (br 0)))', /popping value from empty stack/); wasmFailValidateText('(module (func (result i32) (br 0)))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (br 0 (f32.const 42))))', mismatchError("f32", "i32")); wasmFailValidateText('(module (func (result i32) (br 0 (f32.const 42))))', mismatchError("f32", "i32"));
wasmFailValidateText('(module (func (result i32) (block (br 0))))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (block (br 0))))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (block f32 (br 0 (f32.const 42)))))', mismatchError("f32", "i32")); wasmFailValidateText('(module (func (result i32) (block f32 (br 0 (f32.const 42)))))', mismatchError("f32", "i32"));
wasmFailValidateText(`(module (func (result i32) (param i32) (block (if i32 (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`, /if without else with a result value/); wasmFailValidateText(`(module (func (result i32) (param i32) (block (if i32 (get_local 0) (br 0 (i32.const 42))))) (export "" 0))`, /if without else with a result value/);
@ -319,8 +320,8 @@ wasmFailValidateText(`(module (func (result i32) (param i32) (block i32 (if (get
wasmFullPass('(module (func (result i32) (br 0 (i32.const 42)) (i32.const 13)) (export "run" 0))', 42); wasmFullPass('(module (func (result i32) (br 0 (i32.const 42)) (i32.const 13)) (export "run" 0))', 42);
wasmFullPass('(module (func (result i32) (block i32 (br 0 (i32.const 42)) (i32.const 13))) (export "run" 0))', 42); wasmFullPass('(module (func (result i32) (block i32 (br 0 (i32.const 42)) (i32.const 13))) (export "run" 0))', 42);
wasmFailValidateText('(module (func) (func (block i32 (br 0 (call 0)) (i32.const 13))) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func) (func (block i32 (br 0 (call 0)) (i32.const 13))) (export "" 0))', emptyStackError);
wasmFailValidateText('(module (func) (func (block i32 (br_if 0 (call 0) (i32.const 1)) (i32.const 13))) (export "" 0))', /popping value from empty stack/); wasmFailValidateText('(module (func) (func (block i32 (br_if 0 (call 0) (i32.const 1)) (i32.const 13))) (export "" 0))', emptyStackError);
var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (i32.const 43))) (export "" 0))`).exports[""]; var f = wasmEvalText(`(module (func (result i32) (param i32) (block i32 (if (get_local 0) (drop (i32.const 42))) (i32.const 43))) (export "" 0))`).exports[""];
assertEq(f(0), 43); assertEq(f(0), 43);
@ -414,7 +415,7 @@ assertEq(called, 0);
// br/br_if and loop // br/br_if and loop
wasmFullPass(`(module (func (param i32) (result i32) (loop $out $in i32 (br $out (get_local 0)))) (export "run" 0))`, 1, {}, 1); wasmFullPass(`(module (func (param i32) (result i32) (loop $out $in i32 (br $out (get_local 0)))) (export "run" 0))`, 1, {}, 1);
wasmFullPass(`(module (func (param i32) (result i32) (loop $in (br 1 (get_local 0)))) (export "run" 0))`, 1, {}, 1); wasmFullPass(`(module (func (param i32) (result i32) (loop $in i32 (br 1 (get_local 0)))) (export "run" 0))`, 1, {}, 1);
wasmFullPass(`(module (func (param i32) (result i32) (block $out i32 (loop $in i32 (br $out (get_local 0))))) (export "run" 0))`, 1, {}, 1); wasmFullPass(`(module (func (param i32) (result i32) (block $out i32 (loop $in i32 (br $out (get_local 0))))) (export "run" 0))`, 1, {}, 1);
wasmFailValidateText(`(module (func (param i32) (result i32) wasmFailValidateText(`(module (func (param i32) (result i32)
@ -432,9 +433,12 @@ wasmFullPass(`(module
(result i32) (result i32)
(local i32) (local i32)
(block $out i32 (block $out i32
(loop $in (loop $in i32
(set_local 0 (i32.add (get_local 0) (i32.const 1))) (set_local 0 (i32.add (get_local 0) (i32.const 1)))
(if (i32.ge_s (get_local 0) (i32.const 7)) (br $out (get_local 0))) (if
(i32.ge_s (get_local 0) (i32.const 7))
(br $out (get_local 0))
)
(br $in) (br $in)
) )
) )
@ -446,7 +450,7 @@ wasmFullPass(`(module
(result i32) (result i32)
(local i32) (local i32)
(block $out i32 (block $out i32
(loop $in (loop $in i32
(set_local 0 (i32.add (get_local 0) (i32.const 1))) (set_local 0 (i32.add (get_local 0) (i32.const 1)))
(br_if $out (get_local 0) (i32.ge_s (get_local 0) (i32.const 7))) (br_if $out (get_local 0) (i32.ge_s (get_local 0) (i32.const 7)))
(br $in) (br $in)
@ -687,7 +691,7 @@ assertEq(f(2), 2);
assertEq(f(3), -1); assertEq(f(3), -1);
// br_table with values // br_table with values
wasmFailValidateText('(module (func (result i32) (block (br_table 0 (i32.const 0)))))', mismatchError("void", "i32")); wasmFailValidateText('(module (func (result i32) (block i32 (br_table 0 (i32.const 0)))))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (block i32 (br_table 0 (f32.const 0) (i32.const 0)))))', mismatchError("f32", "i32")); wasmFailValidateText('(module (func (result i32) (block i32 (br_table 0 (f32.const 0) (i32.const 0)))))', mismatchError("f32", "i32"));
wasmFailValidateText(`(module wasmFailValidateText(`(module
@ -730,7 +734,7 @@ assertEq(f(4), 13);
const UNREACHABLE = /unreachable/; const UNREACHABLE = /unreachable/;
assertErrorMessage(wasmEvalText(`(module (func (unreachable)) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (unreachable)) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
assertErrorMessage(wasmEvalText(`(module (func (if (unreachable) (i32.const 0))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (if (unreachable) (nop))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
assertErrorMessage(wasmEvalText(`(module (func (block (br_if 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (block (br_if 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
assertErrorMessage(wasmEvalText(`(module (func (block (br_table 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (block (br_table 0 (unreachable)))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);
assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.add (i32.const 0) (unreachable))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE); assertErrorMessage(wasmEvalText(`(module (func (result i32) (i32.add (i32.const 0) (unreachable))) (export "" 0))`).exports[""], RuntimeError, UNREACHABLE);

Просмотреть файл

@ -16,7 +16,7 @@ wasmFullPass(`(module
i32.const 0 i32.const 0
call 3 call 3
i32.const 42 i32.const 42
f32.add i32.add
) )
(func) (func) (func) (func) (func) (func)
(export "run" 0))`, 43); (export "run" 0))`, 43);

Просмотреть файл

@ -16,7 +16,7 @@ wasmFailValidateText(`(module
(func (result i32) (param i32) (func (result i32) (param i32)
(loop (if (i32.const 0) (br 0)) (drop (get_local 0)))) (loop (if (i32.const 0) (br 0)) (drop (get_local 0))))
(export "" 0) (export "" 0)
)`, mismatchError("void", "i32")); )`, emptyStackError);
assertEq(wasmEvalText(`(module assertEq(wasmEvalText(`(module
(func (result i32) (param i32) (func (result i32) (param i32)
@ -113,19 +113,20 @@ wasmEvalText(`
}).exports.foo(); }).exports.foo();
assertEq(wasmEvalText(`(module (func assertEq(wasmEvalText(`(module (func
(return) return
(select (select
(loop (i32.const 1)) (loop i32 (i32.const 1))
(loop (i32.const 2)) (loop i32 (i32.const 2))
(i32.const 3) (i32.const 3)
) )
drop
) (export "" 0))`).exports[""](), undefined); ) (export "" 0))`).exports[""](), undefined);
wasmEvalText(`(module (func (result i32) wasmEvalText(`(module (func (result i32)
(return (i32.const 0)) (return (i32.const 0))
(select (select
(loop (i32.const 1)) (loop i32 (i32.const 1))
(loop (i32.const 2)) (loop i32 (i32.const 2))
(i32.const 3) (i32.const 3)
) )
))`); ))`);
@ -203,7 +204,7 @@ wasmFailValidateText(`
(br_table 1 0 (i32.const 15)) (br_table 1 0 (i32.const 15))
) )
) )
)`, mismatchError("i32", "void")); )`, /br_table targets must all have the same value type/);
wasmFailValidateText(` wasmFailValidateText(`
(module (module
@ -213,7 +214,7 @@ wasmFailValidateText(`
(br_table 1 0 (i32.const 15)) (br_table 1 0 (i32.const 15))
) )
) )
)`, mismatchError("i32", "void")); )`, /br_table targets must all have the same value type/);
wasmValidateText(` wasmValidateText(`
(module (module

Просмотреть файл

@ -25,7 +25,7 @@ for (let body of bodies) {
wasmFullPass(` wasmFullPass(`
(module (module
(func $f (param $x i32) (result i32) (func $f (param $x i32) (result i32)
loop $top loop $top i32
get_local $x get_local $x
if if
get_local $x get_local $x

Просмотреть файл

@ -6,7 +6,13 @@ var m1 = wasmEvalText(
`(module `(module
(type $type0 (func)) (type $type0 (func))
(func $func0 (func $func0
(select (unreachable) (return (nop)) (loop (i32.const 1)))) (select
(unreachable)
(return (nop))
(loop i32 (i32.const 1))
)
drop
)
(export "" 0))`).exports[""]; (export "" 0))`).exports[""];
try { try {
@ -20,7 +26,13 @@ var m2 = wasmEvalText(
`(module `(module
(type $type0 (func)) (type $type0 (func))
(func $func0 (func $func0
(select (i32.const 26) (unreachable) (i32.const 3))) (select
(i32.const 26)
(unreachable)
(i32.const 3)
)
drop
)
(export "" 0))`).exports[""]; (export "" 0))`).exports[""];
try { try {

Просмотреть файл

@ -1401,6 +1401,17 @@
)) ))
"type mismatch" "type mismatch"
) )
(assert_invalid
(module (func $type-arg-num-vs-arg-num
(block
(block f32
(br_table 0 1 (f32.const 0) (i64.const 0))
)
(drop)
)
))
"type mismatch"
)
(assert_invalid (assert_invalid
(module (func $type-index-void-vs-i32 (module (func $type-index-void-vs-i32

Просмотреть файл

@ -361,8 +361,40 @@
"unknown type" "unknown type"
) )
;; invalid table
;; Unbound function in table
(assert_invalid (assert_invalid
(module (table anyfunc (elem 0 0))) (module (table anyfunc (elem 0 0)))
"unknown function 0" "unknown function 0"
) )
;; Invalid bounds for elements
(assert_unlinkable
(module
(table 10 anyfunc)
(elem (i32.const 10) $f)
(func $f)
)
"elements segment does not fit"
)
(assert_unlinkable
(module
(table 10 anyfunc)
(elem (i32.const -1) $f)
(func $f)
)
"elements segment does not fit"
)
(assert_unlinkable
(module
(table 10 anyfunc)
(elem (i32.const -10) $f)
(func $f)
)
"elements segment does not fit"
)

Просмотреть файл

@ -156,12 +156,21 @@
(assert_trap (invoke $Ot "call" (i32.const 20)) "undefined") (assert_trap (invoke $Ot "call" (i32.const 20)) "undefined")
(module $Pt (module
(table (import "Mt" "tab") 0 anyfunc) (table (import "Mt" "tab") 0 anyfunc)
(elem (i32.const 9) $f) (elem (i32.const 9) $f)
(func $f) (func $f)
) )
(assert_unlinkable
(module
(table (import "Mt" "tab") 0 anyfunc)
(elem (i32.const 10) $f)
(func $f)
)
"elements segment does not fit"
)
(assert_unlinkable (assert_unlinkable
(module (module
(table (import "Mt" "tab") 10 anyfunc) (table (import "Mt" "tab") 10 anyfunc)
@ -240,12 +249,20 @@
(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2)) (assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
(assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7)) (assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7))
(module $Pm (module
(memory (import "Mm" "mem") 0) (memory (import "Mm" "mem") 0)
(data (i32.const 1000) "abc") (data (i32.const 0xffff) "a")
) )
(module $Qm (assert_unlinkable
(module
(memory (import "Mm" "mem") 0)
(data (i32.const 0x10000) "a")
)
"data segment does not fit"
)
(module $Pm
(memory (import "Mm" "mem") 1 8) (memory (import "Mm" "mem") 1 8)
(func (export "grow") (param $a i32) (result i32) (func (export "grow") (param $a i32) (result i32)
@ -253,14 +270,14 @@
) )
) )
(assert_return (invoke $Qm "grow" (i32.const 0)) (i32.const 1)) (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 1))
(assert_return (invoke $Qm "grow" (i32.const 2)) (i32.const 1)) (assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1))
(assert_return (invoke $Qm "grow" (i32.const 0)) (i32.const 3)) (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3))
(assert_return (invoke $Qm "grow" (i32.const 1)) (i32.const 3)) (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3))
(assert_return (invoke $Qm "grow" (i32.const 1)) (i32.const 4)) (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4))
(assert_return (invoke $Qm "grow" (i32.const 0)) (i32.const 5)) (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
(assert_return (invoke $Qm "grow" (i32.const 1)) (i32.const -1)) (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1))
(assert_return (invoke $Qm "grow" (i32.const 0)) (i32.const 5)) (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
(assert_unlinkable (assert_unlinkable
(module (module

Просмотреть файл

@ -82,6 +82,14 @@
(module (memory 0 1) (data (i32.const 0) "a")) (module (memory 0 1) (data (i32.const 0) "a"))
"data segment does not fit" "data segment does not fit"
) )
(assert_unlinkable
(module (memory 1 2) (data (i32.const -1) "a"))
"data segment does not fit"
)
(assert_unlinkable
(module (memory 1 2) (data (i32.const -1000) "a"))
"data segment does not fit"
)
(assert_unlinkable (assert_unlinkable
(module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 98304) "b")) (module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 98304) "b"))
"data segment does not fit" "data segment does not fit"
@ -94,13 +102,20 @@
(module (memory 1) (data (i32.const 0x12000) "")) (module (memory 1) (data (i32.const 0x12000) ""))
"data segment does not fit" "data segment does not fit"
) )
(assert_unlinkable
(module (memory 1 2) (data (i32.const -1) ""))
"data segment does not fit"
)
;; This seems to cause a time-out on Travis. ;; This seems to cause a time-out on Travis.
(;assert_unlinkable (;assert_unlinkable
(module (memory 0x10000) (data (i32.const 0xffffffff) "ab")) (module (memory 0x10000) (data (i32.const 0xffffffff) "ab"))
"" ;; either out of memory or segment does not fit "" ;; either out of memory or segment does not fit
;) ;)
(assert_unlinkable (assert_unlinkable
(module (global (import "spectest" "global") i32) (memory 0) (data (get_global 0) "a")) (module
(global (import "spectest" "global") i32)
(memory 0) (data (get_global 0) "a")
)
"data segment does not fit" "data segment does not fit"
) )

Просмотреть файл

@ -1 +0,0 @@
var importedArgs = ['soft-fail.wast']; load(scriptdir + '../wast.js');

Просмотреть файл

@ -75,6 +75,9 @@
(func (export "as-br_table-value-index") (result i32) (func (export "as-br_table-value-index") (result i32)
(block i32 (br_table 0 0 (i32.const 6) (unreachable)) (i32.const 7)) (block i32 (br_table 0 0 (i32.const 6) (unreachable)) (i32.const 7))
) )
(func (export "as-br_table-value-and-index") (result i32)
(block i32 (br_table 0 0 (unreachable)) (i32.const 8))
)
(func (export "as-return-value") (result i64) (func (export "as-return-value") (result i64)
(return (unreachable)) (return (unreachable))

Просмотреть файл

@ -1,21 +1,35 @@
;; Test soft failures ;; Failures in unreachable code.
;; These are invalid Wasm, but the failure is in dead code, which
;; implementations are not required to validate. If they do, they shall
;; diagnose the correct error.
(assert_soft_invalid (assert_invalid
(module (func $local-index (unreachable) (drop (get_local 0))))
"unknown local"
)
(assert_invalid
(module (func $global-index (unreachable) (drop (get_global 0))))
"unknown global"
)
(assert_invalid
(module (func $func-index (unreachable) (call 1)))
"unknown function"
)
(assert_invalid
(module (func $label-index (unreachable) (br 1)))
"unknown label"
)
(assert_invalid
(module (func $type-num-vs-num (module (func $type-num-vs-num
(unreachable) (drop (i64.eqz (i32.const 0)))) (unreachable) (drop (i64.eqz (i32.const 0))))
) )
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-poly-num-vs-num (result i32) (module (func $type-poly-num-vs-num (result i32)
(unreachable) (i64.const 0) (i32.const 0) (select) (unreachable) (i64.const 0) (i32.const 0) (select)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-poly-transitive-num-vs-num (result i32) (module (func $type-poly-transitive-num-vs-num (result i32)
(unreachable) (unreachable)
(i64.const 0) (i32.const 0) (select) (i64.const 0) (i32.const 0) (select)
@ -24,275 +38,279 @@
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unconsumed-const (unreachable) (i32.const 0))) (module (func $type-unconsumed-const (unreachable) (i32.const 0)))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unconsumed-result (unreachable) (i32.eqz))) (module (func $type-unconsumed-result (unreachable) (i32.eqz)))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unconsumed-result2 (module (func $type-unconsumed-result2
(unreachable) (i32.const 0) (i32.add) (unreachable) (i32.const 0) (i32.add)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unconsumed-poly0 (unreachable) (select))) (module (func $type-unconsumed-poly0 (unreachable) (select)))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unconsumed-poly1 (unreachable) (i32.const 0) (select))) (module (func $type-unconsumed-poly1 (unreachable) (i32.const 0) (select)))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unconsumed-poly2 (module (func $type-unconsumed-poly2
(unreachable) (i32.const 0) (i32.const 0) (select) (unreachable) (i32.const 0) (i32.const 0) (select)
)) ))
"type mismatch" "type mismatch"
) )
(assert_invalid
(module (func $type-select-any (result i32) (i32.const 1) (if i64 (then (i64.const 0)) (else (unreachable) (select)))))
"type mismatch"
)
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-void-after-break (module (func $type-unary-num-vs-void-after-break
(block (br 0) (block (drop (i32.eqz (nop))))) (block (br 0) (block (drop (i32.eqz (nop)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-num-after-break (module (func $type-unary-num-vs-num-after-break
(block (br 0) (drop (i32.eqz (f32.const 1)))) (block (br 0) (drop (i32.eqz (f32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-void-after-break (module (func $type-binary-num-vs-void-after-break
(block (br 0) (block (drop (f32.eq (i32.const 1))))) (block (br 0) (block (drop (f32.eq (i32.const 1)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-num-after-break (module (func $type-binary-num-vs-num-after-break
(block (br 0) (drop (f32.eq (i32.const 1) (f32.const 0)))) (block (br 0) (drop (f32.eq (i32.const 1) (f32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-after-break (module (func $type-block-value-num-vs-void-after-break
(block (br 0) (i32.const 1)) (block (br 0) (i32.const 1))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-after-break (result i32) (module (func $type-block-value-num-vs-num-after-break (result i32)
(block i32 (i32.const 1) (br 0) (f32.const 0)) (block i32 (i32.const 1) (br 0) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-void-after-break (module (func $type-loop-value-num-vs-void-after-break
(block (loop (br 1) (i32.const 1))) (block (loop (br 1) (i32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-num-after-break (result i32) (module (func $type-loop-value-num-vs-num-after-break (result i32)
(loop i32 (br 1 (i32.const 1)) (f32.const 0)) (loop i32 (br 1 (i32.const 1)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-void-after-break (module (func $type-func-value-num-vs-void-after-break
(br 0) (i32.const 1) (br 0) (i32.const 1)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-num-after-break (result i32) (module (func $type-func-value-num-vs-num-after-break (result i32)
(br 0 (i32.const 1)) (f32.const 0) (br 0 (i32.const 1)) (f32.const 0)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-void-after-return (module (func $type-unary-num-vs-void-after-return
(return) (block (drop (i32.eqz (nop)))) (return) (block (drop (i32.eqz (nop))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-num-after-return (module (func $type-unary-num-vs-num-after-return
(return) (drop (i32.eqz (f32.const 1))) (return) (drop (i32.eqz (f32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-void-after-return (module (func $type-binary-num-vs-void-after-return
(return) (block (drop (f32.eq (i32.const 1)))) (return) (block (drop (f32.eq (i32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-num-after-return (module (func $type-binary-num-vs-num-after-return
(return) (drop (f32.eq (i32.const 1) (f32.const 0))) (return) (drop (f32.eq (i32.const 1) (f32.const 0)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-after-return (module (func $type-block-value-num-vs-void-after-return
(block (return) (i32.const 1)) (block (return) (i32.const 1))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-after-return (result i32) (module (func $type-block-value-num-vs-num-after-return (result i32)
(block i32 (i32.const 1) (return (i32.const 0)) (f32.const 0)) (block i32 (i32.const 1) (return (i32.const 0)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-void-after-return (module (func $type-loop-value-num-vs-void-after-return
(block (loop (return) (i32.const 1))) (block (loop (return) (i32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-num-after-return (result i32) (module (func $type-loop-value-num-vs-num-after-return (result i32)
(loop i32 (return (i32.const 1)) (f32.const 0)) (loop i32 (return (i32.const 1)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-void-after-return (module (func $type-func-value-num-vs-void-after-return
(return) (i32.const 1) (return) (i32.const 1)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-num-after-return (result i32) (module (func $type-func-value-num-vs-num-after-return (result i32)
(return (i32.const 1)) (f32.const 0) (return (i32.const 1)) (f32.const 0)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-void-after-unreachable (module (func $type-unary-num-vs-void-after-unreachable
(unreachable) (block (drop (i32.eqz (nop)))) (unreachable) (block (drop (i32.eqz (nop))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-num-after-unreachable (module (func $type-unary-num-vs-num-after-unreachable
(unreachable) (drop (i32.eqz (f32.const 1))) (unreachable) (drop (i32.eqz (f32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-void-after-unreachable (module (func $type-binary-num-vs-void-after-unreachable
(unreachable) (block (drop (f32.eq (i32.const 1)))) (unreachable) (block (drop (f32.eq (i32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-num-after-unreachable (module (func $type-binary-num-vs-num-after-unreachable
(unreachable) (drop (f32.eq (i32.const 1) (f32.const 0))) (unreachable) (drop (f32.eq (i32.const 1) (f32.const 0)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-after-unreachable (module (func $type-block-value-num-vs-void-after-unreachable
(block (unreachable) (i32.const 1)) (block (unreachable) (i32.const 1))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-after-unreachable (result i32) (module (func $type-block-value-num-vs-num-after-unreachable (result i32)
(block i32 (i32.const 1) (unreachable) (f32.const 0)) (block i32 (i32.const 1) (unreachable) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-void-after-unreachable (module (func $type-loop-value-num-vs-void-after-unreachable
(block (loop (unreachable) (i32.const 1))) (block (loop (unreachable) (i32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-num-after-unreachable (result i32) (module (func $type-loop-value-num-vs-num-after-unreachable (result i32)
(loop i32 (unreachable) (f32.const 0)) (loop i32 (unreachable) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-void-after-unreachable (module (func $type-func-value-num-vs-void-after-unreachable
(unreachable) (i32.const 1) (unreachable) (i32.const 1)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-num-after-unreachable (result i32) (module (func $type-func-value-num-vs-num-after-unreachable (result i32)
(unreachable) (f32.const 0) (unreachable) (f32.const 0)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-void-after-nested-unreachable (module (func $type-unary-num-vs-void-after-nested-unreachable
(block (unreachable)) (block (drop (i32.eqz (nop)))) (block (unreachable)) (block (drop (i32.eqz (nop))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-num-after-nested-unreachable (module (func $type-unary-num-vs-num-after-nested-unreachable
(block (unreachable)) (drop (i32.eqz (f32.const 1))) (block (unreachable)) (drop (i32.eqz (f32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-void-after-nested-unreachable (module (func $type-binary-num-vs-void-after-nested-unreachable
(block (unreachable)) (block (drop (f32.eq (i32.const 1)))) (block (unreachable)) (block (drop (f32.eq (i32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-num-after-nested-unreachable (module (func $type-binary-num-vs-num-after-nested-unreachable
(block (unreachable)) (drop (f32.eq (i32.const 1) (f32.const 0))) (block (unreachable)) (drop (f32.eq (i32.const 1) (f32.const 0)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-after-nested-unreachable (module (func $type-block-value-num-vs-void-after-nested-unreachable
(block (block (unreachable)) (i32.const 1)) (block (block (unreachable)) (i32.const 1))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-after-nested-unreachable (module (func $type-block-value-num-vs-num-after-nested-unreachable
(result i32) (result i32)
(block i32 (i32.const 1) (block (unreachable)) (f32.const 0)) (block i32 (i32.const 1) (block (unreachable)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-void-after-nested-unreachable (module (func $type-loop-value-num-vs-void-after-nested-unreachable
(block (loop (block (unreachable)) (i32.const 1))) (block (loop (block (unreachable)) (i32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-num-after-nested-unreachable (module (func $type-loop-value-num-vs-num-after-nested-unreachable
(result i32) (result i32)
(loop i32 (block (unreachable)) (f32.const 0)) (loop i32 (block (unreachable)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-void-after-nested-unreachable (module (func $type-func-value-num-vs-void-after-nested-unreachable
(block (unreachable)) (i32.const 1) (block (unreachable)) (i32.const 1)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-num-after-nested-unreachable (module (func $type-func-value-num-vs-num-after-nested-unreachable
(result i32) (result i32)
(block (unreachable)) (f32.const 0) (block (unreachable)) (f32.const 0)
@ -300,243 +318,275 @@
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-void-after-infinite-loop (module (func $type-unary-num-vs-void-after-infinite-loop
(loop (br 0)) (block (drop (i32.eqz (nop)))) (loop (br 0)) (block (drop (i32.eqz (nop))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-num-after-infinite-loop (module (func $type-unary-num-vs-num-after-infinite-loop
(loop (br 0)) (drop (i32.eqz (f32.const 1))) (loop (br 0)) (drop (i32.eqz (f32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-void-after-infinite-loop (module (func $type-binary-num-vs-void-after-infinite-loop
(loop (br 0)) (block (drop (f32.eq (i32.const 1)))) (loop (br 0)) (block (drop (f32.eq (i32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-num-after-infinite-loop (module (func $type-binary-num-vs-num-after-infinite-loop
(loop (br 0)) (drop (f32.eq (i32.const 1) (f32.const 0))) (loop (br 0)) (drop (f32.eq (i32.const 1) (f32.const 0)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-after-infinite-loop (module (func $type-block-value-num-vs-void-after-infinite-loop
(block (loop (br 0)) (i32.const 1)) (block (loop (br 0)) (i32.const 1))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-after-infinite-loop (result i32) (module (func $type-block-value-num-vs-num-after-infinite-loop (result i32)
(block i32 (i32.const 1) (loop (br 0)) (f32.const 0)) (block i32 (i32.const 1) (loop (br 0)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-void-after-infinite-loop (module (func $type-loop-value-num-vs-void-after-infinite-loop
(block (loop (loop (br 0)) (i32.const 1))) (block (loop (loop (br 0)) (i32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-num-vs-num-after-infinite-loop (result i32) (module (func $type-loop-value-num-vs-num-after-infinite-loop (result i32)
(loop i32 (loop (br 0)) (f32.const 0)) (loop i32 (loop (br 0)) (f32.const 0))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-void-after-infinite-loop (module (func $type-func-value-num-vs-void-after-infinite-loop
(loop (br 0)) (i32.const 1) (loop (br 0)) (i32.const 1)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-func-value-num-vs-num-after-infinite-loop (result i32) (module (func $type-func-value-num-vs-num-after-infinite-loop (result i32)
(loop (br 0)) (f32.const 0) (loop (br 0)) (f32.const 0)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-void-in-dead-body (module (func $type-unary-num-vs-void-in-dead-body
(if (i32.const 0) (then (drop (i32.eqz (nop))))) (if (i32.const 0) (then (drop (i32.eqz (nop)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-unary-num-vs-num-in-dead-body (module (func $type-unary-num-vs-num-in-dead-body
(if (i32.const 0) (then (drop (i32.eqz (f32.const 1))))) (if (i32.const 0) (then (drop (i32.eqz (f32.const 1)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-void-in-dead-body (module (func $type-binary-num-vs-void-in-dead-body
(if (i32.const 0) (then (drop (f32.eq (i32.const 1))))) (if (i32.const 0) (then (drop (f32.eq (i32.const 1)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-binary-num-vs-num-in-dead-body (module (func $type-binary-num-vs-num-in-dead-body
(if (i32.const 0) (then (drop (f32.eq (i32.const 1) (f32.const 0))))) (if (i32.const 0) (then (drop (f32.eq (i32.const 1) (f32.const 0)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-if-value-num-vs-void-in-dead-body (module (func $type-if-value-num-vs-void-in-dead-body
(if (i32.const 0) (then (i32.const 1))) (if (i32.const 0) (then (i32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-if-value-num-vs-num-in-dead-body (result i32) (module (func $type-if-value-num-vs-num-in-dead-body (result i32)
(if i32 (i32.const 0) (then (f32.const 0))) (if i32 (i32.const 0) (then (f32.const 0)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-in-dead-body (module (func $type-block-value-num-vs-void-in-dead-body
(if (i32.const 0) (then (block (i32.const 1)))) (if (i32.const 0) (then (block (i32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-in-dead-body (result i32) (module (func $type-block-value-num-vs-num-in-dead-body (result i32)
(if i32 (i32.const 0) (then (block i32 (f32.const 0)))) (if i32 (i32.const 0) (then (block i32 (f32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-void-in-dead-body (module (func $type-block-value-num-vs-void-in-dead-body
(if (i32.const 0) (then (loop (i32.const 1)))) (if (i32.const 0) (then (loop (i32.const 1))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-num-vs-num-in-dead-body (result i32) (module (func $type-block-value-num-vs-num-in-dead-body (result i32)
(if i32 (i32.const 0) (then (loop i32 (f32.const 0)))) (if i32 (i32.const 0) (then (loop i32 (f32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-return-second-num-vs-num (result i32) (module (func $type-return-second-num-vs-num (result i32)
(return (i32.const 1)) (return (f64.const 1)) (return (i32.const 1)) (return (f64.const 1))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-br-second-num-vs-num (result i32) (module (func $type-br-second-num-vs-num (result i32)
(block i32 (br 0 (i32.const 1)) (br 0 (f64.const 1))) (block i32 (br 0 (i32.const 1)) (br 0 (f64.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-br_if-cond-num-vs-num-after-unreachable (module (func $type-br_if-cond-num-vs-num-after-unreachable
(block (br_if 0 (unreachable) (f32.const 0))) (block (br_if 0 (unreachable) (f32.const 0)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-br_table-num-vs-num-after-unreachable (module (func $type-br_table-num-vs-num-after-unreachable
(block (br_table 0 (unreachable) (f32.const 1))) (block (br_table 0 (unreachable) (f32.const 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_invalid
(module (func $type-br_table-label-num-vs-num-after-unreachable (result i32)
(block i32 (unreachable) (br_table 0 (f32.const 0) (i32.const 1)))
))
"type mismatch"
)
(assert_invalid
(module (func $type-br_table-label-num-vs-label-void-after-unreachable
(block
(block f32
(unreachable)
(br_table 0 1 0 (i32.const 1))
)
(drop)
)
))
"type mismatch"
)
(assert_invalid
(module (func $type-br_table-label-num-vs-label-num-after-unreachable
(block f64
(block f32
(unreachable)
(br_table 0 1 1 (i32.const 1))
)
(drop)
(f64.const 0)
)
(drop)
))
"type mismatch"
)
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-unreachable-num-vs-void (module (func $type-block-value-nested-unreachable-num-vs-void
(block (i32.const 3) (block (unreachable))) (block (i32.const 3) (block (unreachable)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-unreachable-void-vs-num (result i32) (module (func $type-block-value-nested-unreachable-void-vs-num (result i32)
(block (block (unreachable))) (block (block (unreachable)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-unreachable-num-vs-num (result i32) (module (func $type-block-value-nested-unreachable-num-vs-num (result i32)
(block i64 (i64.const 0) (block (unreachable))) (block i64 (i64.const 0) (block (unreachable)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-unreachable-num2-vs-void (result i32) (module (func $type-block-value-nested-unreachable-num2-vs-void (result i32)
(block (i32.const 3) (block (i64.const 1) (unreachable))) (i32.const 9) (block (i32.const 3) (block (i64.const 1) (unreachable))) (i32.const 9)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-br-num-vs-void (module (func $type-block-value-nested-br-num-vs-void
(block (i32.const 3) (block (br 1))) (block (i32.const 3) (block (br 1)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-br-void-vs-num (result i32) (module (func $type-block-value-nested-br-void-vs-num (result i32)
(block i32 (block (br 1 (i32.const 0)))) (block i32 (block (br 1 (i32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-br-num-vs-num (result i32) (module (func $type-block-value-nested-br-num-vs-num (result i32)
(block i32 (i64.const 0) (block (br 1 (i32.const 0)))) (block i32 (i64.const 0) (block (br 1 (i32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested2-br-num-vs-void (module (func $type-block-value-nested2-br-num-vs-void
(block (block (i32.const 3) (block (br 2)))) (block (block (i32.const 3) (block (br 2))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested2-br-void-vs-num (result i32) (module (func $type-block-value-nested2-br-void-vs-num (result i32)
(block i32 (block (block (br 2 (i32.const 0))))) (block i32 (block (block (br 2 (i32.const 0)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested2-br-num-vs-num (result i32) (module (func $type-block-value-nested2-br-num-vs-num (result i32)
(block i32 (block i64 (i64.const 0) (block (br 2 (i32.const 0))))) (block i32 (block i64 (i64.const 0) (block (br 2 (i32.const 0)))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested2-br-num2-vs-void (result i32) (module (func $type-block-value-nested2-br-num2-vs-void (result i32)
(block (i32.const 3) (block (i64.const 1) (br 1))) (i32.const 9) (block (i32.const 3) (block (i64.const 1) (br 1))) (i32.const 9)
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-return-num-vs-void (module (func $type-block-value-nested-return-num-vs-void
(block (i32.const 3) (block (return))) (block (i32.const 3) (block (return)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-return-void-vs-num (result i32) (module (func $type-block-value-nested-return-void-vs-num (result i32)
(block (block (return (i32.const 0)))) (block (block (return (i32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-return-num-vs-num (result i32) (module (func $type-block-value-nested-return-num-vs-num (result i32)
(block i64 (i64.const 0) (block (return (i32.const 0)))) (block i64 (i64.const 0) (block (return (i32.const 0))))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-block-value-nested-return-num2-vs-void (result i32) (module (func $type-block-value-nested-return-num2-vs-void (result i32)
(block (i32.const 3) (block (i64.const 1) (return (i32.const 0)))) (block (i32.const 3) (block (i64.const 1) (return (i32.const 0))))
(i32.const 9) (i32.const 9)
@ -544,32 +594,32 @@
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-nested-unreachable-num-vs-void (module (func $type-loop-value-nested-unreachable-num-vs-void
(loop (i32.const 3) (block (unreachable))) (loop (i32.const 3) (block (unreachable)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-nested-unreachable-void-vs-num (result i32) (module (func $type-loop-value-nested-unreachable-void-vs-num (result i32)
(loop (block (unreachable))) (loop (block (unreachable)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-loop-value-nested-unreachable-num-vs-num (result i32) (module (func $type-loop-value-nested-unreachable-num-vs-num (result i32)
(loop i64 (i64.const 0) (block (unreachable))) (loop i64 (i64.const 0) (block (unreachable)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-cont-last-void-vs-empty (result i32) (module (func $type-cont-last-void-vs-empty (result i32)
(loop (br 0 (nop))) (loop (br 0 (nop)))
)) ))
"type mismatch" "type mismatch"
) )
(assert_soft_invalid (assert_invalid
(module (func $type-cont-last-num-vs-empty (result i32) (module (func $type-cont-last-num-vs-empty (result i32)
(loop (br 0 (i32.const 0))) (loop (br 0 (i32.const 0)))
)) ))

Просмотреть файл

@ -0,0 +1 @@
var importedArgs = ['unreached-invalid.wast']; load(scriptdir + '../wast.js');

Просмотреть файл

@ -62,7 +62,7 @@ wasmFailValidateText(
) )
(export "test" 0) (export "test" 0)
(memory 1 10) (memory 1 10)
)`, /popping value from empty stack/); )`, emptyStackError);
// function calls // function calls
runTest(` runTest(`

Просмотреть файл

@ -1,30 +0,0 @@
load(libdir + "wasm.js");
// In unreachable code, the current design is that validation is disabled,
// meaning we have to have a special mode in the decoder for decoding code
// that won't actually run.
wasmFullPass(`(module
(func (result i32)
(return (i32.const 42))
(i32.add (f64.const 1.0) (f32.const 0.0))
(return (f64.const 2.0))
(if (f32.const 3.0) (i64.const 2) (i32.const 1))
(select (f64.const -5.0) (f32.const 2.3) (f64.const 8.9))
)
(export "run" 0)
)`, 42);
wasmFullPass(`(module
(func (result i32) (param i32)
(block
(br_if 1 (i32.const 41) (get_local 0))
(br 1 (i32.const 42))
)
(i32.add (f32.const 0.0) (f64.const 1.0))
(return (f64.const 2.0))
(if (f32.const 3.0) (i64.const 2) (i32.const 1))
(select (f64.const -5.0) (f32.const 2.3) (f64.const 8.9))
)
(export "run" 0)
)`, 42, {}, 0);

Просмотреть файл

@ -435,23 +435,6 @@ function exec(e) {
return; return;
} }
if (exprName === "assert_soft_invalid") {
let moduleText = e.list[1].toString();
let errMsg = e.list[2];
if (errMsg) {
assert(errMsg.quoted, "assert_soft_invalid second argument must be a string");
errMsg.quoted = false;
}
try {
new WebAssembly.Module(wasmTextToBinary(moduleText));
} catch(e) {
debug('assert_soft_invalid caught:\nExpected:', errMsg, '\nActual:', e.toString());
}
return;
}
if (exprName === 'assert_trap') { if (exprName === 'assert_trap') {
let caught = false; let caught = false;
let errMsg = e.list[2]; let errMsg = e.list[2];

Просмотреть файл

@ -474,6 +474,24 @@ JS_NewContext(uint32_t maxbytes, uint32_t maxNurseryBytes, JSRuntime* parentRunt
return NewContext(maxbytes, maxNurseryBytes, parentRuntime); return NewContext(maxbytes, maxNurseryBytes, parentRuntime);
} }
JS_PUBLIC_API(JSContext*)
JS_NewCooperativeContext(JSContext* siblingContext)
{
return NewCooperativeContext(siblingContext);
}
JS_PUBLIC_API(void)
JS_YieldCooperativeContext(JSContext* cx)
{
YieldCooperativeContext(cx);
}
JS_PUBLIC_API(void)
JS_ResumeCooperativeContext(JSContext* cx)
{
ResumeCooperativeContext(cx);
}
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
JS_DestroyContext(JSContext* cx) JS_DestroyContext(JSContext* cx)
{ {

Просмотреть файл

@ -981,11 +981,37 @@ JS_IsBuiltinFunctionConstructor(JSFunction* fun);
* See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference
*/ */
// Create a new runtime, with a single cooperative context for this thread.
// On success, the new context will be the active context for the runtime.
extern JS_PUBLIC_API(JSContext*) extern JS_PUBLIC_API(JSContext*)
JS_NewContext(uint32_t maxbytes, JS_NewContext(uint32_t maxbytes,
uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes,
JSRuntime* parentRuntime = nullptr); JSRuntime* parentRuntime = nullptr);
// The methods below for controlling the active context in a cooperatively
// multithreaded runtime are not threadsafe, and the caller must ensure they
// are called serially if there is a chance for contention between threads.
// Called from the active context for a runtime, yield execution so that
// this context is no longer active and can no longer use the API.
extern JS_PUBLIC_API(void)
JS_YieldCooperativeContext(JSContext* cx);
// Called from a context whose runtime has no active context, this thread
// becomes the active context for that runtime and may use the API.
extern JS_PUBLIC_API(void)
JS_ResumeCooperativeContext(JSContext* cx);
// Create a new context on this thread for cooperative multithreading in the
// same runtime as siblingContext. Called on a runtime (as indicated by
// siblingContet) which has no active context, on success the new context will
// become the runtime's active context.
extern JS_PUBLIC_API(JSContext*)
JS_NewCooperativeContext(JSContext* siblingContext);
// Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext.
// The context must be the current active context in the runtime, and after
// this call the runtime will have no active context.
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_DestroyContext(JSContext* cx); JS_DestroyContext(JSContext* cx);

Просмотреть файл

@ -99,8 +99,10 @@ js::TraceCycleDetectionSet(JSTracer* trc, AutoCycleDetector::Set& set)
} }
bool bool
JSContext::init() JSContext::init(ContextKind kind)
{ {
// Skip most of the initialization if this thread will not be running JS.
if (kind == ContextKind::Cooperative) {
// Get a platform-native handle for this thread, used by js::InterruptRunningJitCode. // Get a platform-native handle for this thread, used by js::InterruptRunningJitCode.
#ifdef XP_WIN #ifdef XP_WIN
size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
@ -129,6 +131,11 @@ JSContext::init()
if (!wasm::EnsureSignalHandlers(this)) if (!wasm::EnsureSignalHandlers(this))
return false; return false;
}
// Set the ContextKind last, so that ProtectedData checks will allow us to
// initialize this context before it becomes the runtime's active context.
kind_ = kind;
return true; return true;
} }
@ -156,8 +163,7 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
return nullptr; return nullptr;
} }
if (!cx->init(ContextKind::Cooperative)) {
if (!cx->init()) {
js_delete(cx); js_delete(cx);
js_delete(runtime); js_delete(runtime);
return nullptr; return nullptr;
@ -166,6 +172,39 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
return cx; return cx;
} }
JSContext*
js::NewCooperativeContext(JSContext* siblingContext)
{
MOZ_RELEASE_ASSERT(!TlsContext.get());
JSRuntime* runtime = siblingContext->runtime();
JSContext* cx = js_new<JSContext>(runtime, JS::ContextOptions());
if (!cx || !cx->init(ContextKind::Cooperative)) {
js_delete(cx);
return nullptr;
}
runtime->setNewbornActiveContext(cx);
return cx;
}
void
js::YieldCooperativeContext(JSContext* cx)
{
MOZ_ASSERT(cx == TlsContext.get());
MOZ_ASSERT(cx->runtime()->activeContext() == cx);
cx->runtime()->setActiveContext(nullptr);
}
void
js::ResumeCooperativeContext(JSContext* cx)
{
MOZ_ASSERT(cx == TlsContext.get());
MOZ_ASSERT(cx->runtime()->activeContext() == nullptr);
cx->runtime()->setActiveContext(cx);
}
void void
js::DestroyContext(JSContext* cx) js::DestroyContext(JSContext* cx)
{ {
@ -186,6 +225,8 @@ js::DestroyContext(JSContext* cx)
// Destroy the runtime along with its last context. // Destroy the runtime along with its last context.
cx->runtime()->destroyRuntime(); cx->runtime()->destroyRuntime();
js_delete(cx->runtime()); js_delete(cx->runtime());
js_delete_poison(cx);
} else { } else {
DebugOnly<bool> found = false; DebugOnly<bool> found = false;
for (size_t i = 0; i < cx->runtime()->cooperatingContexts().length(); i++) { for (size_t i = 0; i < cx->runtime()->cooperatingContexts().length(); i++) {
@ -197,9 +238,9 @@ js::DestroyContext(JSContext* cx)
} }
} }
MOZ_ASSERT(found); MOZ_ASSERT(found);
}
js_delete_poison(cx); cx->runtime()->deleteActiveContext(cx);
}
} }
void void
@ -1092,6 +1133,7 @@ JSContext::alreadyReportedError()
JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options) JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
: runtime_(runtime), : runtime_(runtime),
kind_(ContextKind::Background),
threadNative_(0), threadNative_(0),
helperThread_(nullptr), helperThread_(nullptr),
options_(options), options_(options),
@ -1171,15 +1213,20 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
{ {
MOZ_ASSERT(static_cast<JS::RootingContext*>(this) == MOZ_ASSERT(static_cast<JS::RootingContext*>(this) ==
JS::RootingContext::get(this)); JS::RootingContext::get(this));
for (size_t i = 0; i < mozilla::ArrayLength(nativeStackQuota); i++)
nativeStackQuota[i] = 0;
MOZ_ASSERT(!TlsContext.get()); MOZ_ASSERT(!TlsContext.get());
TlsContext.set(this); TlsContext.set(this);
for (size_t i = 0; i < mozilla::ArrayLength(nativeStackQuota); i++)
nativeStackQuota[i] = 0;
} }
JSContext::~JSContext() JSContext::~JSContext()
{ {
// Clear the ContextKind first, so that ProtectedData checks will allow us to
// destroy this context even if the runtime is already gone.
kind_ = ContextKind::Background;
#ifdef XP_WIN #ifdef XP_WIN
if (threadNative_) if (threadNative_)
CloseHandle((HANDLE)threadNative_.ref()); CloseHandle((HANDLE)threadNative_.ref());

Просмотреть файл

@ -80,6 +80,12 @@ void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
/* Thread Local Storage slot for storing the context for a thread. */ /* Thread Local Storage slot for storing the context for a thread. */
extern MOZ_THREAD_LOCAL(JSContext*) TlsContext; extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
enum class ContextKind
{
Cooperative,
Background
};
} /* namespace js */ } /* namespace js */
/* /*
@ -89,13 +95,14 @@ extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
struct JSContext : public JS::RootingContext, struct JSContext : public JS::RootingContext,
public js::MallocProvider<JSContext> public js::MallocProvider<JSContext>
{ {
explicit JSContext(JSRuntime* runtime, const JS::ContextOptions& options); JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
~JSContext(); ~JSContext();
bool init(); bool init(js::ContextKind kind);
private: private:
js::UnprotectedData<JSRuntime*> runtime_; js::UnprotectedData<JSRuntime*> runtime_;
js::WriteOnceData<js::ContextKind> kind_;
// System handle for the thread this context is associated with. // System handle for the thread this context is associated with.
js::WriteOnceData<size_t> threadNative_; js::WriteOnceData<size_t> threadNative_;
@ -112,6 +119,7 @@ struct JSContext : public JS::RootingContext,
// currently operating on. // currently operating on.
void setRuntime(JSRuntime* rt); void setRuntime(JSRuntime* rt);
bool isCooperativelyScheduled() const { return kind_ == js::ContextKind::Cooperative; }
size_t threadNative() const { return threadNative_; } size_t threadNative() const { return threadNative_; }
inline js::gc::ArenaLists* arenas() const { return arenas_; } inline js::gc::ArenaLists* arenas() const { return arenas_; }
@ -639,7 +647,7 @@ struct JSContext : public JS::RootingContext,
const js::AutoCycleDetector::Set& cycleDetectorSet() const { return cycleDetectorSet_.ref(); } const js::AutoCycleDetector::Set& cycleDetectorSet() const { return cycleDetectorSet_.ref(); }
/* Client opaque pointer. */ /* Client opaque pointer. */
void* data; js::UnprotectedData<void*> data;
void initJitStackLimit(); void initJitStackLimit();
void resetJitStackLimit(); void resetJitStackLimit();
@ -951,6 +959,15 @@ struct MOZ_RAII AutoResolving {
extern JSContext* extern JSContext*
NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime); NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime);
extern JSContext*
NewCooperativeContext(JSContext* siblingContext);
extern void
YieldCooperativeContext(JSContext* cx);
extern void
ResumeCooperativeContext(JSContext* cx);
extern void extern void
DestroyContext(JSContext* cx); DestroyContext(JSContext* cx);

Просмотреть файл

@ -984,9 +984,10 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
if (op == JSOP_TRY) { if (op == JSOP_TRY) {
TryNoteArray* trynotes = script->trynotes(); TryNoteArray* trynotes = script->trynotes();
uint32_t i; uint32_t i;
size_t mainOffset = script->mainOffset();
for(i = 0; i < trynotes->length; i++) { for(i = 0; i < trynotes->length; i++) {
JSTryNote note = trynotes->vector[i]; JSTryNote note = trynotes->vector[i];
if (note.kind == JSTRY_CATCH && note.start == loc + 1) { if (note.kind == JSTRY_CATCH && note.start + mainOffset == loc + 1) {
if (!sp->jsprintf(" %u (%+d)", if (!sp->jsprintf(" %u (%+d)",
unsigned(loc + note.length + 1), unsigned(loc + note.length + 1),
int(note.length + 1))) int(note.length + 1)))

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше