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.
if (gTestPath.includes("test-oop-extensions")) {
SpecialPowers.pushPrefEnv({set: [
["dom.ipc.processCount.extension", 1],
["extensions.webextensions.remote", true],
]});
// 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
from marionette_harness import MarionetteTestCase
from marionette_driver.errors import NoAlertPresentException
class TestFirefoxRefresh(MarionetteTestCase):
@ -269,11 +270,17 @@ class TestFirefoxRefresh(MarionetteTestCase):
""")
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("""
let mm = gBrowser.selectedBrowser.messageManager;
let fs = function() {
content.document.getElementById("errorTryAgain").click();
};
let {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
window.addEventListener("SSWindowStateReady", function testSSPostReset() {
window.removeEventListener("SSWindowStateReady", testSSPostReset, false);
@ -281,6 +288,17 @@ class TestFirefoxRefresh(MarionetteTestCase):
marionetteScriptFinished([... gBrowser.browsers].map(b => b.currentURI && b.currentURI.spec));
});
}, 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);
""")
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 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/TelemetryLog.jsm");
function startup() {
if (Services.appinfo.OS != "WINNT") {
@ -18,12 +43,13 @@ function startup() {
const regCPUPath = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
let wrk;
let cpuErrorCode = CPU_SUCCESS;
try {
wrk = Cc["@mozilla.org/windows-registry-key;1"].createInstance(Ci.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, regCPUPath, wrk.ACCESS_READ);
} catch (e) {
Cu.reportError("Unable to open registry. Exception: " + e);
TelemetryLog.log("AUSHELPER_FATAL_ERROR", [e]);
Cu.reportError("AUSHelper - unable to open registry. Exception: " + e);
cpuErrorCode |= CPU_REG_OPEN_ERROR;
}
// If any of the following values are successfully retrieved and they don't
@ -41,9 +67,9 @@ function startup() {
cpuVendorIDMatch = true;
}
} catch (e) {
Cu.reportError("AUSHelper - error getting CPU vendor indentifier. Exception: " + e);
cpuVendorIDMatch = null;
Cu.reportError("Error getting CPU vendor indentifier. Exception: " + e);
TelemetryLog.log("AUSHELPER_CPU_VENDOR_ID_ERROR", [e]);
cpuErrorCode |= CPU_VENDOR_ID_ERROR;
}
let cpuIDMatch = false;
@ -53,9 +79,9 @@ function startup() {
cpuIDMatch = true;
}
} catch (e) {
Cu.reportError("AUSHelper - error getting CPU indentifier. Exception: " + e);
cpuIDMatch = null;
Cu.reportError("Error getting CPU indentifier. Exception: " + e);
TelemetryLog.log("AUSHELPER_CPU_ID_ERROR", [e]);
cpuErrorCode |= CPU_ID_ERROR;
}
let microCodeVersions = [0xe, 0x11, 0x12, 0x13, 0x16, 0x18, 0x19];
@ -67,8 +93,8 @@ function startup() {
let regVal = wrk.readBinaryValue(keyNames[i]);
if (regVal.length == 8) {
let hexVal = [];
// We are only inyterested in the highest byte and return the little
// endian value for it.
// We are only inyterested in the upper 4 bytes and the little endian
// value for it.
for (let j = 4; j < 8; j++) {
let c = regVal.charCodeAt(j).toString(16);
if (c.length == 1) {
@ -86,44 +112,78 @@ function startup() {
if (i == keyNames.length - 1) {
// The registry key name's value was not successfully queried.
cpuRevMatch = null;
TelemetryLog.log("AUSHELPER_CPU_REV_ERROR", [e]);
cpuErrorCode |= CPU_REV_ERROR;
}
}
}
wrk.close();
} catch (ex) {
Cu.reportError("AUSHelper - error getting CPU revision. Exception: " + ex);
cpuRevMatch = null;
Cu.reportError("Error getting CPU revision. Exception: " + ex);
TelemetryLog.log("AUSHELPER_CPU_REV_ERROR", [ex]);
cpuErrorCode |= CPU_REV_ERROR;
}
let resultCode = 3;
let newValue = "(unkBug1296630v1)";
let cpuResult = CPU_UNKNOWN_BUG1296630;
let cpuValue = "(unkBug1296630v1)";
// The following uses strict equality checks since the values can be true,
// false, or null.
if (cpuVendorIDMatch === false || cpuIDMatch === false || cpuRevMatch === false) {
// 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.
newValue = "(noBug1296630v1)";
resultCode = 0;
cpuValue = "(noBug1296630v1)";
cpuResult = CPU_NO_BUG1296630;
} 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
// be affected by bug 1296630.
newValue = "(errBug1296630v1)";
resultCode = 2;
cpuValue = "(errBug1296630v1)";
cpuResult = CPU_ERR_BUG1296630;
} else if (cpuVendorIDMatch === true && cpuIDMatch === true && cpuRevMatch === true) {
// Since all of the values are true we can say that the system will be
// affected by bug 1296630.
newValue = "(yesBug1296630v1)";
resultCode = 1;
cpuValue = "(yesBug1296630v1)";
cpuResult = CPU_YES_BUG1296630;
}
let defaultBranch = Services.prefs.getDefaultBranch("");
let curPrefValue = defaultBranch.getCharPref(APP_UPDATE_URL_PREF);
let newPrefValue = curPrefValue.replace(REPLACE_KEY + "/", REPLACE_KEY + newValue + "/");
defaultBranch.setCharPref(APP_UPDATE_URL_PREF, newPrefValue);
TelemetryLog.log("AUSHELPER_RESULT", [resultCode]);
}
Services.telemetry.getHistogramById(AUSHELPER_CPU_RESULT_CODE_HISTOGRAM_ID).add(cpuResult);
Services.telemetry.getHistogramById(AUSHELPER_CPU_ERROR_CODE_HISTOGRAM_ID).add(cpuErrorCode);
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 install() {}
function uninstall() {}

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

@ -10,7 +10,7 @@
<Description about="urn:mozilla:install-manifest">
<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:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1094,50 +1094,9 @@ Inspector.prototype = {
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({
label: INSPECTOR_L10N.getStr("inspectorCopyHTMLSubmenu.label"),
submenu: copySubmenu,
submenu: this._getCopySubmenu(markupContainer, isSelectionElement),
}));
menu.append(new MenuItem({
@ -1210,6 +1169,51 @@ Inspector.prototype = {
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) {
let isPasteable = isEditableElement && this._getClipboardContentForPaste();
let disableAdjacentPaste = !isPasteable ||
@ -1283,6 +1287,14 @@ Inspector.prototype = {
disabled: !isEditableElement,
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({
id: "node-menu-edit-attribute",
label: INSPECTOR_L10N.getFormatStr("inspectorEditAttribute.label",
@ -1291,13 +1303,11 @@ Inspector.prototype = {
disabled: !isAttributeClicked,
click: () => this.onEditAttribute(),
}));
attributesSubmenu.append(new MenuItem({
id: "node-menu-remove-attribute",
label: INSPECTOR_L10N.getFormatStr("inspectorRemoveAttribute.label",
isAttributeClicked ? `"${nodeInfo.name}"` : ""),
accesskey:
INSPECTOR_L10N.getStr("inspectorRemoveAttribute.accesskey"),
accesskey: INSPECTOR_L10N.getStr("inspectorRemoveAttribute.accesskey"),
disabled: !isAttributeClicked,
click: () => this.onRemoveAttribute(),
}));
@ -1817,6 +1827,14 @@ Inspector.prototype = {
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.
* 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_05.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_01.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",
});
// 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.
if (this.ruleEditor.isEditable) {
this.enable.addEventListener("click", this._onEnableClicked, true);
@ -454,8 +460,9 @@ TextPropertyEditor.prototype = {
elToClick.click();
}
// Populate the computed styles.
// Populate the computed styles and shorthand overridden styles.
this._updateComputed();
this._updateShorthandOverridden();
// Update the rule property highlight.
this.ruleView._updatePropertyHighlight(this);
@ -469,7 +476,7 @@ TextPropertyEditor.prototype = {
/**
* 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 () {
if (this.prop.enabled) {
@ -527,45 +534,86 @@ TextPropertyEditor.prototype = {
continue;
}
let li = createChild(this.computed, "li", {
class: "ruleview-computed"
});
if (computed.overridden) {
li.classList.add("ruleview-overridden");
}
createChild(li, "span", {
class: "ruleview-propertyname theme-fg-color5",
textContent: computed.name
});
appendText(li, ": ");
let outputParser = this.ruleView._outputParser;
let frag = outputParser.parseCssProperty(
computed.name, computed.value, {
colorSwatchClass: "ruleview-swatch ruleview-colorswatch",
urlClass: "theme-link",
baseURI: this.sheetHref
}
);
// Store the computed property value that was parsed for output
computed.parsedValue = frag.textContent;
createChild(li, "span", {
class: "ruleview-propertyvalue theme-fg-color1",
child: frag
});
appendText(li, ";");
// Store the computed style element for easy access when highlighting
// styles
computed.element = li;
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) {
li.classList.add("ruleview-overridden");
}
createChild(li, "span", {
class: "ruleview-propertyname theme-fg-color5",
textContent: computed.name
});
appendText(li, ": ");
let outputParser = this.ruleView._outputParser;
let frag = outputParser.parseCssProperty(
computed.name, computed.value, {
colorSwatchClass: "ruleview-swatch ruleview-colorswatch",
urlClass: "theme-link",
baseURI: this.sheetHref
}
);
// Store the computed property value that was parsed for output
computed.parsedValue = frag.textContent;
createChild(li, "span", {
class: "ruleview-propertyvalue theme-fg-color1",
child: frag
});
appendText(li, ";");
return li;
},
/**
* Handles clicks on the disabled property.
*/
@ -593,9 +641,12 @@ TextPropertyEditor.prototype = {
this.expander.removeAttribute("open");
this.computed.removeAttribute("filter-open");
this.computed.removeAttribute("user-open");
this.shorthandOverridden.removeAttribute("hidden");
this._populateShorthandOverridden();
} else {
this.expander.setAttribute("open", "true");
this.computed.setAttribute("user-open", "");
this.shorthandOverridden.setAttribute("hidden", "true");
this._populateComputed();
}

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

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

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

@ -12,6 +12,7 @@ add_task(function* () {
yield selectNode("#attributes", inspector);
yield testAddAttribute();
yield testCopyAttributeValue();
yield testEditAttribute();
yield testRemoveAttribute();
@ -29,6 +30,20 @@ add_task(function* () {
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() {
info("Testing 'Edit Attribute' menu item");
let editAttribute = getMenuItem("node-menu-edit-attribute");

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

@ -23,7 +23,7 @@
</div>
<p id="console-var">Paragraph for testing 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>
</body>
</html>

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

@ -117,6 +117,13 @@ inspectorEditAttribute.accesskey=E
inspectorRemoveAttribute.label=Remove Attribute %S
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):
# This string is displayed in a tooltip that is shown when hovering over a DOM
# node preview (e.g. something like "div#foo.bar").

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

@ -123,13 +123,15 @@
}
.ruleview-computedlist,
.ruleview-overridden-items[hidden],
.ruleview-overridden-rule-filter[hidden],
.ruleview-warning[hidden] {
display: none;
}
.ruleview-computedlist[user-open],
.ruleview-computedlist[filter-open] {
.ruleview-computedlist[filter-open],
.ruleview-overridden-items {
display: block;
}
@ -362,6 +364,42 @@
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-swatch {
cursor: pointer;

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

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

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

@ -7967,13 +7967,8 @@ nsDocument::FlushPendingNotifications(FlushType aType)
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 (shell->NeedFlush(aType)) {
nsCOMPtr<nsIPresShell> presShell = shell;
presShell->FlushPendingNotifications(aType);
}
shell->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(mIdleService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
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(mIdleService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
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
// only try to precache storage when we're not a private browsing window.
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;
}
bool isPrivateBrowsing = IsPrivateBrowsing();
if ((!nsCRT::strcmp(aTopic, "dom-storage2-changed") && !isPrivateBrowsing) ||
(!nsCRT::strcmp(aTopic, "dom-private-storage2-changed") && isPrivateBrowsing)) {
if (!IsInnerWindow() || !AsInner()->IsCurrentInnerWindow()) {
// 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();
if ((isNonPrivateLocalStorageChange && isPrivateBrowsing) ||
(isPrivateLocalStorageChange && !isPrivateBrowsing)) {
return NS_OK;
}
nsIPrincipal *principal;
nsresult rv;
// We require that aData be either u"SessionStorage" or u"localStorage".
// 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);
if (!event) {
return NS_ERROR_FAILURE;
}
RefPtr<Storage> changingStorage = event->GetStorageArea();
if (!changingStorage) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMStorage> istorage = changingStorage.get();
bool fireMozStorageChanged = false;
nsAutoString eventType;
eventType.AssignLiteral("storage");
principal = GetPrincipal();
if (!principal) {
return NS_OK;
}
if (changingStorage->IsPrivate() != IsPrivateBrowsing()) {
return NS_OK;
}
if (!NS_strcmp(aData, u"sessionStorage")) {
nsCOMPtr<nsIDOMStorage> changingStorage = event->GetStorageArea();
MOZ_ASSERT(changingStorage);
switch (changingStorage->GetType())
{
case Storage::SessionStorage:
{
bool check = false;
nsCOMPtr<nsIDOMStorageManager> storageManager = do_QueryInterface(GetDocShell());
if (storageManager) {
rv = storageManager->CheckStorage(principal, istorage, &check);
nsresult rv = storageManager->CheckStorage(principal, changingStorage,
&check);
if (NS_FAILED(rv)) {
return rv;
}
@ -11969,58 +11988,48 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
if (fireMozStorageChanged) {
eventType.AssignLiteral("MozSessionStorageChanged");
}
break;
}
case Storage::LocalStorage:
{
// Allow event fire only for the same principal storages
// XXX We have to use EqualsIgnoreDomain after bug 495337 lands
nsIPrincipal* storagePrincipal = changingStorage->GetPrincipal();
else {
MOZ_ASSERT(!NS_strcmp(aData, u"localStorage"));
nsIPrincipal* storagePrincipal = event->GetPrincipal();
if (!storagePrincipal) {
return NS_OK;
}
bool equals = false;
rv = storagePrincipal->Equals(principal, &equals);
nsresult rv = storagePrincipal->Equals(principal, &equals);
NS_ENSURE_SUCCESS(rv, rv);
if (!equals)
if (!equals) {
return NS_OK;
}
fireMozStorageChanged = mLocalStorage == event->GetStorageArea();
fireMozStorageChanged = mLocalStorage == changingStorage;
if (fireMozStorageChanged) {
eventType.AssignLiteral("MozLocalStorageChanged");
}
break;
}
default:
return NS_OK;
}
// Clone the storage event included in the observer notification. We want
// to dispatch clones rather than the original event.
ErrorResult error;
RefPtr<StorageEvent> newEvent = CloneStorageEvent(eventType, event, error);
RefPtr<StorageEvent> clonedEvent =
CloneStorageEvent(eventType, event, error);
if (error.Failed()) {
return error.StealNSResult();
}
newEvent->SetTrusted(true);
clonedEvent->SetTrusted(true);
if (fireMozStorageChanged) {
WidgetEvent* internalEvent = newEvent->WidgetEventPtr();
WidgetEvent* internalEvent = clonedEvent->WidgetEventPtr();
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;
DispatchEvent(newEvent, &defaultActionEnabled);
DispatchEvent(clonedEvent, &defaultActionEnabled);
return NS_OK;
}
@ -12111,10 +12120,19 @@ nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
aEvent->GetUrl(dict.mUrl);
RefPtr<Storage> storageArea = aEvent->GetStorageArea();
MOZ_ASSERT(storageArea);
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);
} else {
MOZ_ASSERT(storageArea->GetType() == Storage::SessionStorage);
@ -12126,7 +12144,7 @@ nsGlobalWindow::CloneStorageEvent(const nsAString& aType,
}
MOZ_ASSERT(storage);
MOZ_ASSERT(storage->IsForkOf(storageArea));
MOZ_ASSERT_IF(storageArea, storage->IsForkOf(storageArea));
dict.mStorageArea = storage;
@ -12419,11 +12437,6 @@ nsGlobalWindow::FireDelayedDOMEvents()
{
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) {
static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();
}
@ -13293,6 +13306,13 @@ nsGlobalWindow::EventListenerAdded(nsIAtom* aType)
aType == nsGkAtoms::onvrdisplaypresentchange) {
NotifyVREventListenerAdded();
}
// We need to initialize localStorage in order to receive notifications.
if (aType == nsGkAtoms::onstorage) {
ErrorResult rv;
GetLocalStorage(rv);
rv.SuppressException();
}
}
void

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

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

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

@ -1,8 +1,7 @@
[DEFAULT]
skip-if = os == 'android'
support-files = nonchrome_webgl_debug_renderer_info.html
[test_webgl_debug_renderer_info.html]
subsuite = gpu
[test_drawWindow_widget_layers.html]
skip-if = os == 'android'
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
-->
<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/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script>
const UNMASKED_VENDOR_WEBGL = 0x9245;
const UNMASKED_RENDERER_WEBGL = 0x9246;
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)
{
function isNonEmptyString(s) {
return s && (typeof s) == "string";
}
function messageListener(e) {
if (e.data.allTestsFinished) {
SimpleTest.finish();
} else if (e.data.subTestFinished) {
ok(e.data.result, "content iframe: " + e.data.message);
}
}
var canvas = document.createElement("canvas");
var gl = canvas.getContext("experimental-webgl");
ok(!gl.getError(), "getError on newly created WebGL context should return NO_ERROR");
function checkChromeCase(canvas) {
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 gl = canvas.getContext("experimental-webgl");
ok(!gl.getError(), "getError on newly created WebGL context should return NO_ERROR");
var exts = gl.getSupportedExtensions();
ok(exts.indexOf("WEBGL_debug_renderer_info") != -1,
"WEBGL_debug_renderer_info should be listed by getSupportedExtensions in chrome contexts");
var ext = gl.getExtension("WEBGL_debug_renderer_info");
ok(ext,
"WEBGL_debug_renderer_info should be available through getExtension in chrome contexts");
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");
ok(ext.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL,
"UNMASKED_VENDOR_WEBGL has the correct value");
ok(ext.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL,
"UNMASKED_RENDERER_WEBGL has the correct value");
var exts = gl.getSupportedExtensions();
ok(exts.indexOf("WEBGL_debug_renderer_info") != -1,
"WEBGL_debug_renderer_info should be listed by getSupportedExtensions in chrome contexts");
var ext = gl.getExtension("WEBGL_debug_renderer_info");
ok(ext,
"WEBGL_debug_renderer_info should be available through getExtension in chrome contexts");
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");
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");
ok(ext.UNMASKED_VENDOR_WEBGL == UNMASKED_VENDOR_WEBGL,
"UNMASKED_VENDOR_WEBGL has the correct value");
ok(ext.UNMASKED_RENDERER_WEBGL == UNMASKED_RENDERER_WEBGL,
"UNMASKED_RENDERER_WEBGL has the correct value");
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");
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");
}
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>
</pre>
</body>
</html>

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

@ -31,7 +31,7 @@ var defaultExts = [
['OES_texture_half_float_linear' , [ENSURE , FORBID ]],
['OES_vertex_array_object' , [ENSURE , FORBID ]],
['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_depth_texture' , [MACHINE_SPECIFIC, FORBID ]],
['WEBGL_draw_buffers' , [MACHINE_SPECIFIC, FORBID ]],

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

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

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

@ -293,12 +293,37 @@ HTMLTrackElement::LoadResource()
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<nsILoadGroup> loadGroup = OwnerDoc()->GetDocumentLoadGroup();
rv = NS_NewChannel(getter_AddRefs(channel),
uri,
static_cast<Element*>(this),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
secFlags,
nsIContentPolicy::TYPE_INTERNAL_TRACK,
loadGroup,
nullptr, // aCallbacks
@ -313,7 +338,11 @@ HTMLTrackElement::LoadResource()
LOG(LogLevel::Debug, ("opening webvtt channel"));
rv = channel->AsyncOpen2(mListener);
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
if (NS_FAILED(rv)) {
SetReadyState(TextTrackReadyState::FailedToLoad);
return;
}
mChannel = channel;
}

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

@ -51,9 +51,9 @@
let url =
URL.createObjectURL(new Blob(["(", dummyWorkerScript.toSource(), ")()"]));
let worker = new Worker(url);
let worker1 = new Worker(url);
try {
worker.postMessage(mutableFile);
worker1.postMessage(mutableFile);
ok(false, "Should have thrown!");
}
catch (e) {
@ -61,7 +61,6 @@
is(e.name, "DataCloneError", "Good error.");
is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
}
worker.terminate();
mutableFile.onerror = errorHandler;
@ -77,10 +76,10 @@
let file = event.target.result;
worker = new Worker(url);
let worker2 = new Worker(url);
URL.revokeObjectURL(url);
try {
worker.postMessage(file);
worker2.postMessage(file);
ok(false, "Should have thrown!");
}
catch (e) {
@ -88,7 +87,6 @@
is(e.name, "DataCloneError", "Good error.");
is(e.code, DOMException.DATA_CLONE_ERR, "Good error code.")
}
worker.terminate();
let objectStore =
db.transaction("Foo", "readwrite").objectStore("Foo");
@ -126,14 +124,18 @@
url = URL.createObjectURL(new Blob(["(", workerScript.toSource(), ")()"]));
worker = new Worker(url);
let worker3 = new Worker(url);
URL.revokeObjectURL(url);
worker.postMessage(name);
worker.onmessage = grabEventAndContinueHandler;
worker3.postMessage(name);
worker3.onmessage = grabEventAndContinueHandler;
event = yield undefined;
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();
}

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

@ -20,8 +20,15 @@ interface nsIDOMStorageManager : nsISupports
/**
* This starts async preloading of a storage cache for scope
* 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.

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

@ -34,6 +34,7 @@
#include "mozilla/dom/MemoryReportRequest.h"
#include "mozilla/dom/ProcessGlobal.h"
#include "mozilla/dom/PushNotifier.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/TabGroup.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
@ -3035,6 +3036,20 @@ ContentChild::RecvBlobURLUnregistration(const nsCString& aURI)
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)
bool
ContentChild::SendGetA11yContentId()

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

@ -391,6 +391,14 @@ public:
virtual mozilla::ipc::IPCResult
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 RecvFilePathUpdate(const nsString& aStorageType,

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

@ -51,6 +51,7 @@
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
#include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/Storage.h"
#include "mozilla/dom/StorageIPC.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/power/PowerManagerService.h"
@ -4771,6 +4772,25 @@ ContentParent::RecvUnstoreAndBroadcastBlobURLUnregistration(const nsCString& aUR
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
ContentParent::RecvGetA11yContentId(uint32_t* aContentId)
{

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

@ -574,6 +574,14 @@ public:
virtual mozilla::ipc::IPCResult
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
RecvGetA11yContentId(uint32_t* aContentId) override;

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

@ -676,6 +676,12 @@ child:
async BlobURLUnregistration(nsCString aURI);
async DispatchLocalStorageChange(nsString documentURI,
nsString key,
nsString oldValue,
nsString newValue,
Principal principal,
bool isPrivate);
async GMPsChanged(GMPCapabilityData[] capabilities);
@ -1178,6 +1184,13 @@ parent:
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
*/

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

@ -769,7 +769,7 @@ public:
* Returns false if the data was not appended because no such track exists
* 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.
* 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),
mEnabled(true), mConstraints(aConstraints)
{
GetSource().RegisterSink(this);
mPrincipalHandleListener = new PrincipalHandleListener(this);
AddListener(mPrincipalHandleListener);
if (GetOwnedStream()) {
mPrincipalHandleListener = new PrincipalHandleListener(this);
AddListener(mPrincipalHandleListener);
}
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =

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

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

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

@ -2720,6 +2720,26 @@ ForceWindowless(InfallibleTArray<nsCString>& names,
}
}
#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
PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
@ -2758,6 +2778,8 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
#ifdef XP_WIN
bool supportsAsyncRender =
Preferences::GetBool("dom.ipc.plugins.asyncdrawing.enabled", false);
bool supportsForceDirect =
Preferences::GetBool("dom.ipc.plugins.forcedirect.enabled", false);
if (supportsAsyncRender) {
// Prefs indicates we want async plugin rendering, make sure
// the flash module has support.
@ -2777,6 +2799,14 @@ PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
#elif defined(MOZ_WIDGET_GTK)
// We no longer support windowed mode on Linux.
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
}

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

@ -14,6 +14,9 @@
#include "nsIPrincipal.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/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
@ -25,6 +28,9 @@
#include "nsServiceManagerUtils.h"
namespace mozilla {
using namespace ipc;
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Storage, mManager, mPrincipal, mWindow)
@ -58,7 +64,6 @@ Storage::Storage(nsPIDOMWindowInner* aWindow,
Storage::~Storage()
{
mCache->KeepAlive();
}
/* virtual */ JSObject*
@ -215,6 +220,30 @@ void
Storage::BroadcastChangeNotification(const nsSubstring& aKey,
const nsSubstring& aOldValue,
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;
dict.mBubbles = false;
@ -222,21 +251,67 @@ Storage::BroadcastChangeNotification(const nsSubstring& aKey,
dict.mKey = aKey;
dict.mNewValue = aNewValue;
dict.mOldValue = aOldValue;
dict.mStorageArea = this;
dict.mUrl = mDocumentURI;
dict.mStorageArea = aStorage;
dict.mUrl = aDocumentURI;
// Note, this DOM event should never reach JS. It is cloned later in
// nsGlobalWindow.
RefPtr<StorageEvent> event =
StorageEvent::Constructor(nullptr, NS_LITERAL_STRING("storage"), dict);
event->SetPrincipal(aPrincipal);
RefPtr<StorageNotifierRunnable> r =
new StorageNotifierRunnable(event,
GetType() == LocalStorage
aStorageType == LocalStorage
? u"localStorage"
: u"sessionStorage",
IsPrivate());
NS_DispatchToMainThread(r);
aIsPrivate);
if (aImmediateDispatch) {
Unused << r->Run();
} else {
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";

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

@ -24,6 +24,7 @@ namespace dom {
class StorageManagerBase;
class StorageCache;
class StorageEvent;
class Storage final
: public nsIDOMStorage
@ -129,6 +130,28 @@ public:
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:
// The method checks whether the caller can use a storage.
// CanUseStorage is called before any DOM initiated operation

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

@ -59,7 +59,7 @@ GetDataSetIndex(const Storage* aStorage)
NS_IMPL_ADDREF(StorageCacheBridge)
// Since there is no consumer of return value of Release, we can turn this
// Since there is no consumer of return value of Release, we can turn this
// method to void to make implementation of asynchronous StorageCache::Release
// much simpler.
NS_IMETHODIMP_(void) StorageCacheBridge::Release(void)
@ -149,7 +149,7 @@ StorageCache::Init(StorageManagerBase* aManager,
// Check the quota string has (or has not) the identical origin suffix as
// this storage cache is bound to.
MOZ_ASSERT(StringBeginsWith(mQuotaOriginScope, mOriginSuffix));
MOZ_ASSERT(mOriginSuffix.IsEmpty() != StringBeginsWith(mQuotaOriginScope,
MOZ_ASSERT(mOriginSuffix.IsEmpty() != StringBeginsWith(mQuotaOriginScope,
NS_LITERAL_CSTRING("^")));
mUsage = aManager->GetOriginUsage(mQuotaOriginScope);
@ -198,28 +198,33 @@ StorageCache::DataSet(const Storage* aStorage)
}
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
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
if (aDelta > 0 && mManager && mManager->IsLowDiskSpace()) {
if (aSource == ContentMutation &&
aDelta > 0 && mManager && mManager->IsLowDiskSpace()) {
return false;
}
// Check limit per this origin
Data& data = mData[aGetDataSetIndex];
uint64_t newOriginUsage = data.mOriginQuotaUsage + aDelta;
if (aDelta > 0 && newOriginUsage > StorageManagerBase::GetQuota()) {
if (aSource == ContentMutation &&
aDelta > 0 && newOriginUsage > StorageManagerBase::GetQuota()) {
return false;
}
// Now check eTLD+1 limit
if (mUsage && !mUsage->CheckAndSetETLD1UsageDelta(aGetDataSetIndex, aDelta)) {
if (mUsage &&
!mUsage->CheckAndSetETLD1UsageDelta(aGetDataSetIndex, aDelta, aSource)) {
return false;
}
@ -246,73 +251,6 @@ StorageCache::Preload()
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,
// i.e. compile time known ID, but here we know the ID only at run time.
// Hence a new class.
@ -452,7 +390,8 @@ StorageCache::GetItem(const Storage* aStorage, const nsAString& aKey,
nsresult
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.
int64_t delta = 0;
@ -475,7 +414,7 @@ StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
delta += static_cast<int64_t>(aValue.Length()) -
static_cast<int64_t>(aOld.Length());
if (!ProcessUsageDelta(aStorage, delta)) {
if (!ProcessUsageDelta(aStorage, delta, aSource)) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
@ -485,7 +424,7 @@ StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
data.mKeys.Put(aKey, aValue);
if (Persist(aStorage)) {
if (aSource == ContentMutation && Persist(aStorage)) {
if (!sDatabase) {
NS_ERROR("Writing to localStorage after the database has been shut down"
", data lose!");
@ -504,7 +443,7 @@ StorageCache::SetItem(const Storage* aStorage, const nsAString& aKey,
nsresult
StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
nsString& aOld)
nsString& aOld, const MutationSource aSource)
{
if (Persist(aStorage)) {
WaitForPreload(Telemetry::LOCALDOMSTORAGE_REMOVEKEY_BLOCKING_MS);
@ -522,10 +461,10 @@ StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
// Recalculate the cached data size
const int64_t delta = -(static_cast<int64_t>(aOld.Length()) +
static_cast<int64_t>(aKey.Length()));
Unused << ProcessUsageDelta(aStorage, delta);
Unused << ProcessUsageDelta(aStorage, delta, aSource);
data.mKeys.Remove(aKey);
if (Persist(aStorage)) {
if (aSource == ContentMutation && Persist(aStorage)) {
if (!sDatabase) {
NS_ERROR("Writing to localStorage after the database has been shut down"
", data lose!");
@ -539,7 +478,7 @@ StorageCache::RemoveItem(const Storage* aStorage, const nsAString& aKey,
}
nsresult
StorageCache::Clear(const Storage* aStorage)
StorageCache::Clear(const Storage* aStorage, const MutationSource aSource)
{
bool refresh = false;
if (Persist(aStorage)) {
@ -561,11 +500,11 @@ StorageCache::Clear(const Storage* aStorage)
bool hadData = !!data.mKeys.Count();
if (hadData) {
Unused << ProcessUsageDelta(aStorage, -data.mOriginQuotaUsage);
Unused << ProcessUsageDelta(aStorage, -data.mOriginQuotaUsage, aSource);
data.mKeys.Clear();
}
if (Persist(aStorage) && (refresh || hadData)) {
if (aSource == ContentMutation && Persist(aStorage) && (refresh || hadData)) {
if (!sDatabase) {
NS_ERROR("Writing to localStorage after the database has been shut down"
", data lose!");
@ -680,9 +619,6 @@ StorageCache::LoadItem(const nsAString& aKey, const nsString& aValue)
void
StorageCache::LoadDone(nsresult aRv)
{
// Keep the preloaded cache alive for a time
KeepAlive();
MonitorAutoLock monitor(mMonitor);
mLoadResult = aRv;
mLoaded = true;
@ -743,12 +679,13 @@ StorageUsage::LoadUsage(const int64_t aUsage)
bool
StorageUsage::CheckAndSetETLD1UsageDelta(uint32_t aDataSetIndex,
const int64_t aDelta)
const int64_t aDelta, const StorageCache::MutationSource aSource)
{
MOZ_ASSERT(NS_IsMainThread());
int64_t newUsage = mUsage[aDataSetIndex] + aDelta;
if (aDelta > 0 && newUsage > StorageManagerBase::GetQuota()) {
if (aSource == StorageCache::ContentMutation &&
aDelta > 0 && newUsage > StorageManagerBase::GetQuota()) {
return false;
}

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

@ -78,8 +78,24 @@ class StorageCache : public StorageCacheBridge
public:
NS_IMETHOD_(void) Release(void);
// Note: We pass aOriginNoSuffix through the ctor here, because
// StorageCacheHashKey's ctor is creating this class and
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
// StorageCacheHashKey's ctor is creating this class and
// accepts reversed-origin-no-suffix as an argument - the hashing key.
explicit StorageCache(const nsACString* aOriginNoSuffix);
@ -96,10 +112,6 @@ public:
// Starts async preload of this cache if it persistent and not loaded.
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.
// We are passing the Storage object just to let the cache
// read properties like mPrivate, mPrincipal and mSessionOnly.
@ -109,10 +121,13 @@ public:
nsresult GetItem(const Storage* aStorage, const nsAString& aKey,
nsAString& aRetval);
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,
nsString& aOld);
nsresult Clear(const Storage* aStorage);
nsString& aOld,
const MutationSource aSource=ContentMutation);
nsresult Clear(const Storage* aStorage,
const MutationSource aSource=ContentMutation);
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.
// If not, then false is returned and no change to the set must be done.
bool ProcessUsageDelta(uint32_t aGetDataSetIndex, const int64_t aDelta);
bool ProcessUsageDelta(const Storage* aStorage, const int64_t aDelta);
// A special case is if aSource==E10sPropagated, then we will return true even
// 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:
// 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).
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
// sessionStorage access checks since sessionStorage objects are strictly
// scoped by a principal. localStorage objects on the other hand are scoped
@ -211,7 +233,7 @@ private:
// The origin attributes suffix
nsCString mOriginSuffix;
// The eTLD+1 scope used to count quota usage. It is in the reversed format
// The eTLD+1 scope used to count quota usage. It is in the reversed format
// and contains the origin attributes suffix.
nsCString mQuotaOriginScope;
@ -277,7 +299,8 @@ class StorageUsage : public StorageUsageBridge
public:
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:
virtual const nsCString& OriginScope() { return mOriginScope; }

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

@ -224,6 +224,12 @@ StorageDBChild::RecvObserve(const nsCString& aTopic,
mozilla::ipc::IPCResult
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) {
OriginsHavingData().PutEntry(aOrigins[i]);
}

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

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

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

@ -90,8 +90,17 @@ private:
const nsACString& aOriginNoSuffix,
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
nsresult GetStorageInternal(bool aCreate,
nsresult GetStorageInternal(CreateMode aCreate,
mozIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
const nsAString& aDocumentURI,

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

@ -2,6 +2,7 @@
support-files =
browser_frame_elements.html
page_privatestorageevent.html
page_localstorage_e10s.html
position.html
test-console-api.html
test_bug1004814.html
@ -43,6 +44,8 @@ skip-if = e10s
skip-if = !e10s || os != "win" || processor != "x86" # Large-Allocation requires e10s
[browser_largeAllocation_non_win32.js]
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_test__content.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.waitForFocus(function() {
SpecialPowers.pushPrefEnv({"set":[["middlemouse.paste", true], ["dom.ipc.processCount", 1]]}, startTests);
SpecialPowers.pushPrefEnv({"set":[["middlemouse.paste", true]]}, startTests);
});
function startTests() {

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

@ -33,6 +33,9 @@
#include "plbase64.h"
#include "plstr.h"
#include "mozilla/Logging.h"
#include "mozilla/Tokenizer.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "prmem.h"
#include "prnetdb.h"
#include "mozilla/Likely.h"
@ -43,6 +46,7 @@
#include "nsIHttpAuthenticatorCallback.h"
#include "mozilla/Mutex.h"
#include "nsICancelable.h"
#include "nsUnicharUtils.h"
//-----------------------------------------------------------------------------
@ -633,13 +637,20 @@ nsHttpNegotiateAuth::TestPref(nsIURI *uri, const char *pref)
return false;
if (NS_FAILED(uri->GetAsciiHost(host)))
return false;
if (NS_FAILED(uri->GetPort(&port)))
port = NS_GetRealPort(uri);
if (port == -1) {
return false;
}
char *hostList;
if (NS_FAILED(prefs->GetCharPref(pref, &hostList)) || !hostList)
return false;
struct FreePolicy { void operator()(void* p) { free(p); } };
mozilla::UniquePtr<char[], FreePolicy> hostListScope;
hostListScope.reset(hostList);
// pseudo-BNF
// ----------
//
@ -652,24 +663,19 @@ nsHttpNegotiateAuth::TestPref(nsIURI *uri, const char *pref)
// "https://, http://office.foo.com"
//
char *start = hostList, *end;
for (;;) {
// skip past any whitespace
while (*start == ' ' || *start == '\t')
++start;
end = strchr(start, ',');
if (!end)
end = start + strlen(start);
if (start == end)
break;
if (MatchesBaseURI(scheme, host, port, start, end))
mozilla::Tokenizer t(hostList);
while (!t.CheckEOF()) {
t.SkipWhites();
nsDependentCSubstring url;
mozilla::Unused << t.ReadUntil(mozilla::Tokenizer::Token::Char(','), url);
if (url.IsEmpty()) {
continue;
}
if (MatchesBaseURI(scheme, host, port, url)) {
return true;
if (*end == '\0')
break;
start = end + 1;
}
}
free(hostList);
return false;
}
@ -677,54 +683,90 @@ bool
nsHttpNegotiateAuth::MatchesBaseURI(const nsCSubstring &matchScheme,
const nsCSubstring &matchHost,
int32_t matchPort,
const char *baseStart,
const char *baseEnd)
nsDependentCSubstring const& url)
{
// check if scheme://host:port matches baseURI
// check if scheme://host:port matches baseURI
// parse the base URI
const char *hostStart, *schemeEnd = strstr(baseStart, "://");
if (schemeEnd) {
// the given scheme must match the parsed scheme exactly
if (!matchScheme.Equals(Substring(baseStart, schemeEnd)))
return false;
hostStart = schemeEnd + 3;
}
else
hostStart = baseStart;
// parse the base URI
mozilla::Tokenizer t(url);
mozilla::Tokenizer::Token token;
// XXX this does not work for IPv6-literals
const char *hostEnd = strchr(hostStart, ':');
if (hostEnd && hostEnd < baseEnd) {
// the given port must match the parsed port exactly
int port = atoi(hostEnd + 1);
if (matchPort != (int32_t) port)
return false;
}
else
hostEnd = baseEnd;
t.SkipWhites();
// We don't know if the url to check against starts with scheme
// or a host name. Start recording here.
t.Record();
// if we didn't parse out a host, then assume we got a match.
if (hostStart == hostEnd)
return true;
mozilla::Unused << t.Next(token);
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;
// 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;
nsDependentCSubstring ipv6Literal;
t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
if (!matchHost.Equals(ipv6Literal, nsCaseInsensitiveUTF8StringComparator()) &&
!matchHost.Equals(ipv6BareLiteral, nsCaseInsensitiveUTF8StringComparator())) {
return false;
}
ipv6 = true;
} 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;
}

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

@ -34,10 +34,9 @@ private:
bool TestPref(nsIURI *, const char *pref);
bool MatchesBaseURI(const nsCSubstring &scheme,
const nsCSubstring &host,
int32_t port,
const char *baseStart,
const char *baseEnd);
const nsCSubstring &host,
int32_t port,
nsDependentCSubstring const& url);
// Thread for GenerateCredentialsAsync
RefPtr<mozilla::LazyIdleThread> mNegotiateThread;
};

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

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

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

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

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

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

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

@ -133,6 +133,7 @@ public:
mSymbols.fDestroySurface = nullptr;
mSymbols.fCreateWindowSurface = nullptr;
mSymbols.fCreatePbufferSurface = nullptr;
mSymbols.fCreatePbufferFromClientBuffer = nullptr;
mSymbols.fCreatePixmapSurface = nullptr;
mSymbols.fBindAPI = nullptr;
mSymbols.fInitialize = nullptr;
@ -185,6 +186,7 @@ public:
EGL_ANDROID_image_crop,
ANGLE_platform_angle,
ANGLE_platform_angle_d3d,
ANGLE_d3d_share_handle_client_buffer,
Extensions_Max
};
@ -289,6 +291,14 @@ public:
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)
{
BEFORE_GL_CALL;
@ -585,6 +595,8 @@ public:
pfnCreateWindowSurface fCreateWindowSurface;
typedef EGLSurface (GLAPIENTRY * pfnCreatePbufferSurface)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list);
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);
pfnCreatePixmapSurface fCreatePixmapSurface;
typedef EGLBoolean (GLAPIENTRY * pfnBindAPI)(EGLenum api);

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

@ -107,6 +107,8 @@ DateTimeFormat::FormatUDateTime(const nsDateFormatSelector aDateFormatSelector,
dateStyle = UDAT_SHORT;
break;
case kDateFormatYearMonth:
case kDateFormatYearMonthLong:
case kDateFormatMonthLong:
case kDateFormatWeekday:
dateStyle = UDAT_PATTERN;
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();
if (timeStyle != UDAT_NONE) {

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

@ -13,6 +13,8 @@ enum
kDateFormatLong, // provides the long date format for the given locale
kDateFormatShort, // provides the short date format for the given locale
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)
};
%}

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

@ -58,6 +58,14 @@ TEST(DateTimeFormat, DateFormatSelectors) {
ASSERT_TRUE(NS_SUCCEEDED(rv));
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);
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_STREQ("01/1970, 12:00 AM", NS_ConvertUTF16toUTF8(formattedTime).get());

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

@ -545,6 +545,22 @@ IProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
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)
: IProtocol(aSide),
mProtocolId(aProtoId),
@ -802,7 +818,7 @@ IToplevelProtocol::GetMessageEventTarget(const Message& aMsg)
}
already_AddRefed<nsIEventTarget>
IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
IToplevelProtocol::GetActorEventTargetInternal(IProtocol* aActor)
{
MOZ_RELEASE_ASSERT(aActor->Id() != kNullActorId && aActor->Id() != kFreedActorId);
@ -811,10 +827,26 @@ IToplevelProtocol::GetActorEventTarget(IProtocol* aActor)
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
IToplevelProtocol::SetEventTargetForActorInternal(IProtocol* aActor,
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
// code yet. Otherwise we'll be posting stuff to the wrong event target before
// we're called.

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

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

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

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

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

@ -7,6 +7,7 @@ from cStringIO import StringIO
from mozbuild.pythonutil import iter_modules_in_path
import mozpack.path as mozpath
import itertools
from ConfigParser import RawConfigParser
import ipdl
@ -20,6 +21,8 @@ op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
op.add_option('-I', '--include', dest='includedirs', default=[ ],
action='append',
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',
help='Verbose logging (specify -vv or -vvv for very verbose logging)')
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
to be generated""")
options, files = op.parse_args()
_verbosity = options.verbosity
syncMsgList = options.syncMsgList
headersdir = options.headersdir
cppdir = options.cppdir
includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
@ -113,6 +116,11 @@ def normalizedFilename(f):
return '<stdin>'
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
for f in files:
log(2, os.path.basename(f))
@ -135,6 +143,10 @@ for f in files:
print >>sys.stderr, 'Specification is not well typed.'
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:
log(3, ' pretty printed code:')
ipdl.genipdl(ast, codedir)

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

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified' ]
__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified', 'checkSyncMessage' ]
import os, sys
from cStringIO import StringIO
@ -11,6 +11,7 @@ from ipdl.cgen import IPDLCodeGen
from ipdl.lower import LowerToCxx, msgenums
from ipdl.parser import Parser, ParseError
from ipdl.type import TypeCheck
from ipdl.checker import checkSyncMessage
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 \
$(PLY_INCLUDE) \
$(topsrcdir)/ipc/ipdl/ipdl.py \
-s $(srcdir)/sync-messages.ini \
OKTESTS $(OKTESTS) \
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);
RootedPropertyName name(context, bindingIdentifier(YieldIsKeyword));
if (!name)
return null();
if (name == context->names().let) {
error(JSMSG_LET_COMP_BINDING);
return null();

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

@ -35,6 +35,9 @@ function mismatchError(actual, expect) {
return RegExp(str);
}
const emptyStackError = /from empty stack/;
const unusedValuesError = /unused values not explicitly dropped by end of block/;
function jsify(wasmVal) {
if (wasmVal === 'nan')
return NaN;
@ -179,4 +182,4 @@ function wasmGetScriptBreakpoints(wasmScript) {
result.push({str: line.trim(), line: i + 1, offset: lineOffsets[0]});
});
return result;
}
}

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

@ -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
wasmFailValidateText('(module (func (result i32)))', mismatchError("void", "i32"));
wasmFailValidateText('(module (func (result i32) (nop)))', mismatchError("void", "i32"));
wasmFailValidateText('(module (func (result i32)))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (nop)))', emptyStackError);
wasmValidateText('(module (func (nop)))');
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 (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 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);
wasmFailValidateText('(module (func (result i32) (block )))', mismatchError("void", "i32"));
wasmFailValidateText('(module (func (result i32) (block (block ))))', mismatchError("void", "i32"));
wasmFailValidateText('(module (func (local i32) (set_local 0 (block ))))', /popping value from empty stack/);
wasmFailValidateText('(module (func (result i32) (block )))', emptyStackError);
wasmFailValidateText('(module (func (result i32) (block (block ))))', emptyStackError);
wasmFailValidateText('(module (func (local i32) (set_local 0 (block ))))', emptyStackError);
wasmFullPass('(module (func (block (block ))) (export "run" 0))', undefined);
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
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 (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))))');
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" "" (param i32)) (func (call 0)))', /peeking at value from outside block/);
wasmFailValidateText('(module (import "a" "") (func (call 0 (i32.const 0))))', unusedValuesError);
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"));
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) (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/);
assertEq(wasmEvalText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))').exports[""](), undefined);
assertEq(wasmEvalText('(module (func (i32.add (i32.const 0) (select (return) (i32.const 0) (i32.const 0)))) (export "" 0))').exports[""](), undefined);
wasmFailValidateText('(module (func (select (block ) (i32.const 0) (i32.const 0))) (export "" 0))', emptyStackError);
wasmFailValidateText('(module (func (select (return) (i32.const 0) (i32.const 0))) (export "" 0))', unusedValuesError);
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) (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() {

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

@ -157,11 +157,11 @@ assertEq(counter, 0);
// "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) (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) (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.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/);
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 (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 (result i32) (return)) (export "" 0))', /popping value from empty stack/);
wasmFailValidateText('(module (func (if (return) (i32.const 0))) (export "run" 0))', unusedValuesError);
wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', emptyStackError);
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 i32) (return)) (export "" 0))', /popping value from empty stack/);
wasmFailValidateText('(module (func (result i32) (return)) (export "" 0))', emptyStackError);
// ----------------------------------------------------------------------------
// br / br_if
wasmFailValidateText('(module (func (result i32) (block (br 0))) (export "" 0))', mismatchError("void", "i32"));
wasmFailValidateText('(module (func (result i32) (br 0)) (export "" 0))', /popping value from empty stack/);
wasmFailValidateText('(module (func (result i32) (block (br_if 0 (i32.const 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))', emptyStackError);
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/;
@ -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 (result i32)
(block
(if
(br 0)
(i32.const 0)
(i32.const 2)
)
)
) (export "" 0))`, mismatchError("void", "i32"));
block
br 0
if
i32.const 0
i32.const 2
end
end
) (export "" 0))`, unusedValuesError);
wasmFullPass(`(module (func (block $out (br_if $out (br 0)))) (export "run" 0))`, undefined);
@ -273,6 +273,7 @@ wasmFullPass(`(module (func
(i32.const 0)
(return (br 0))
)
drop
)
(return)
) (export "run" 0))`, undefined);
@ -308,9 +309,9 @@ assertEq(isNonZero(-1), 1);
// branches with values
// 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) (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) (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) (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_if 0 (call 0) (i32.const 1)) (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))', 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[""];
assertEq(f(0), 43);
@ -414,7 +415,7 @@ assertEq(called, 0);
// 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 $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);
wasmFailValidateText(`(module (func (param i32) (result i32)
@ -432,11 +433,14 @@ wasmFullPass(`(module
(result i32)
(local i32)
(block $out i32
(loop $in
(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)))
(br $in)
)
(loop $in i32
(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))
)
(br $in)
)
)
)
(export "run" 0))`, 7);
@ -446,7 +450,7 @@ wasmFullPass(`(module
(result i32)
(local i32)
(block $out i32
(loop $in
(loop $in i32
(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 $in)
@ -687,7 +691,7 @@ assertEq(f(2), 2);
assertEq(f(3), -1);
// 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
@ -730,7 +734,7 @@ assertEq(f(4), 13);
const UNREACHABLE = /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_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);

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

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

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

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

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

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

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

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

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

@ -1401,6 +1401,17 @@
))
"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
(module (func $type-index-void-vs-i32

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

@ -361,8 +361,40 @@
"unknown type"
)
;; invalid table
;; Unbound function in table
(assert_invalid
(module (table anyfunc (elem 0 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")
(module $Pt
(module
(table (import "Mt" "tab") 0 anyfunc)
(elem (i32.const 9) $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
(module
(table (import "Mt" "tab") 10 anyfunc)
@ -240,12 +249,20 @@
(assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2))
(assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7))
(module $Pm
(module
(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)
(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 $Qm "grow" (i32.const 2)) (i32.const 1))
(assert_return (invoke $Qm "grow" (i32.const 0)) (i32.const 3))
(assert_return (invoke $Qm "grow" (i32.const 1)) (i32.const 3))
(assert_return (invoke $Qm "grow" (i32.const 1)) (i32.const 4))
(assert_return (invoke $Qm "grow" (i32.const 0)) (i32.const 5))
(assert_return (invoke $Qm "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 1))
(assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1))
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3))
(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3))
(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4))
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
(assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1))
(assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5))
(assert_unlinkable
(module

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

@ -82,6 +82,14 @@
(module (memory 0 1) (data (i32.const 0) "a"))
"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
(module (memory 1 2) (data (i32.const 0) "a") (data (i32.const 98304) "b"))
"data segment does not fit"
@ -94,13 +102,20 @@
(module (memory 1) (data (i32.const 0x12000) ""))
"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.
(;assert_unlinkable
(module (memory 0x10000) (data (i32.const 0xffffffff) "ab"))
"" ;; either out of memory or segment does not fit
;)
(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"
)

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

@ -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)
(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)
(return (unreachable))

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

@ -1,21 +1,35 @@
;; Test soft failures
;; 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.
;; Failures in unreachable code.
(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
(unreachable) (drop (i64.eqz (i32.const 0))))
)
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-poly-num-vs-num (result i32)
(unreachable) (i64.const 0) (i32.const 0) (select)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-poly-transitive-num-vs-num (result i32)
(unreachable)
(i64.const 0) (i32.const 0) (select)
@ -24,275 +38,279 @@
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unconsumed-const (unreachable) (i32.const 0)))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unconsumed-result (unreachable) (i32.eqz)))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unconsumed-result2
(unreachable) (i32.const 0) (i32.add)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unconsumed-poly0 (unreachable) (select)))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unconsumed-poly1 (unreachable) (i32.const 0) (select)))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unconsumed-poly2
(unreachable) (i32.const 0) (i32.const 0) (select)
))
"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
(block (br 0) (block (drop (i32.eqz (nop)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-num-after-break
(block (br 0) (drop (i32.eqz (f32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-void-after-break
(block (br 0) (block (drop (f32.eq (i32.const 1)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-num-after-break
(block (br 0) (drop (f32.eq (i32.const 1) (f32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-after-break
(block (br 0) (i32.const 1))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-after-break (result i32)
(block i32 (i32.const 1) (br 0) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-void-after-break
(block (loop (br 1) (i32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-num-after-break (result i32)
(loop i32 (br 1 (i32.const 1)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-void-after-break
(br 0) (i32.const 1)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-num-after-break (result i32)
(br 0 (i32.const 1)) (f32.const 0)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-void-after-return
(return) (block (drop (i32.eqz (nop))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-num-after-return
(return) (drop (i32.eqz (f32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-void-after-return
(return) (block (drop (f32.eq (i32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-num-after-return
(return) (drop (f32.eq (i32.const 1) (f32.const 0)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-after-return
(block (return) (i32.const 1))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-after-return (result i32)
(block i32 (i32.const 1) (return (i32.const 0)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-void-after-return
(block (loop (return) (i32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-num-after-return (result i32)
(loop i32 (return (i32.const 1)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-void-after-return
(return) (i32.const 1)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-num-after-return (result i32)
(return (i32.const 1)) (f32.const 0)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-void-after-unreachable
(unreachable) (block (drop (i32.eqz (nop))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-num-after-unreachable
(unreachable) (drop (i32.eqz (f32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-void-after-unreachable
(unreachable) (block (drop (f32.eq (i32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-num-after-unreachable
(unreachable) (drop (f32.eq (i32.const 1) (f32.const 0)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-after-unreachable
(block (unreachable) (i32.const 1))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-after-unreachable (result i32)
(block i32 (i32.const 1) (unreachable) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-void-after-unreachable
(block (loop (unreachable) (i32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-num-after-unreachable (result i32)
(loop i32 (unreachable) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-void-after-unreachable
(unreachable) (i32.const 1)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-num-after-unreachable (result i32)
(unreachable) (f32.const 0)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-void-after-nested-unreachable
(block (unreachable)) (block (drop (i32.eqz (nop))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-num-after-nested-unreachable
(block (unreachable)) (drop (i32.eqz (f32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-void-after-nested-unreachable
(block (unreachable)) (block (drop (f32.eq (i32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-num-after-nested-unreachable
(block (unreachable)) (drop (f32.eq (i32.const 1) (f32.const 0)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-after-nested-unreachable
(block (block (unreachable)) (i32.const 1))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-after-nested-unreachable
(result i32)
(block i32 (i32.const 1) (block (unreachable)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-void-after-nested-unreachable
(block (loop (block (unreachable)) (i32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-num-after-nested-unreachable
(result i32)
(loop i32 (block (unreachable)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-void-after-nested-unreachable
(block (unreachable)) (i32.const 1)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-num-after-nested-unreachable
(result i32)
(block (unreachable)) (f32.const 0)
@ -300,243 +318,275 @@
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-void-after-infinite-loop
(loop (br 0)) (block (drop (i32.eqz (nop))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-num-after-infinite-loop
(loop (br 0)) (drop (i32.eqz (f32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-void-after-infinite-loop
(loop (br 0)) (block (drop (f32.eq (i32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-num-after-infinite-loop
(loop (br 0)) (drop (f32.eq (i32.const 1) (f32.const 0)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-after-infinite-loop
(block (loop (br 0)) (i32.const 1))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-after-infinite-loop (result i32)
(block i32 (i32.const 1) (loop (br 0)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-void-after-infinite-loop
(block (loop (loop (br 0)) (i32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-num-vs-num-after-infinite-loop (result i32)
(loop i32 (loop (br 0)) (f32.const 0))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-void-after-infinite-loop
(loop (br 0)) (i32.const 1)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-func-value-num-vs-num-after-infinite-loop (result i32)
(loop (br 0)) (f32.const 0)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-void-in-dead-body
(if (i32.const 0) (then (drop (i32.eqz (nop)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-unary-num-vs-num-in-dead-body
(if (i32.const 0) (then (drop (i32.eqz (f32.const 1)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-void-in-dead-body
(if (i32.const 0) (then (drop (f32.eq (i32.const 1)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-binary-num-vs-num-in-dead-body
(if (i32.const 0) (then (drop (f32.eq (i32.const 1) (f32.const 0)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-if-value-num-vs-void-in-dead-body
(if (i32.const 0) (then (i32.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-if-value-num-vs-num-in-dead-body (result i32)
(if i32 (i32.const 0) (then (f32.const 0)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-in-dead-body
(if (i32.const 0) (then (block (i32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-in-dead-body (result i32)
(if i32 (i32.const 0) (then (block i32 (f32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-void-in-dead-body
(if (i32.const 0) (then (loop (i32.const 1))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-num-vs-num-in-dead-body (result i32)
(if i32 (i32.const 0) (then (loop i32 (f32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-return-second-num-vs-num (result i32)
(return (i32.const 1)) (return (f64.const 1))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-br-second-num-vs-num (result i32)
(block i32 (br 0 (i32.const 1)) (br 0 (f64.const 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-br_if-cond-num-vs-num-after-unreachable
(block (br_if 0 (unreachable) (f32.const 0)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-br_table-num-vs-num-after-unreachable
(block (br_table 0 (unreachable) (f32.const 1)))
))
"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
(block (i32.const 3) (block (unreachable)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-unreachable-void-vs-num (result i32)
(block (block (unreachable)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-unreachable-num-vs-num (result i32)
(block i64 (i64.const 0) (block (unreachable)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-unreachable-num2-vs-void (result i32)
(block (i32.const 3) (block (i64.const 1) (unreachable))) (i32.const 9)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-br-num-vs-void
(block (i32.const 3) (block (br 1)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-br-void-vs-num (result i32)
(block i32 (block (br 1 (i32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-br-num-vs-num (result i32)
(block i32 (i64.const 0) (block (br 1 (i32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested2-br-num-vs-void
(block (block (i32.const 3) (block (br 2))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested2-br-void-vs-num (result i32)
(block i32 (block (block (br 2 (i32.const 0)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(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)))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(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)
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-return-num-vs-void
(block (i32.const 3) (block (return)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-return-void-vs-num (result i32)
(block (block (return (i32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-return-num-vs-num (result i32)
(block i64 (i64.const 0) (block (return (i32.const 0))))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-block-value-nested-return-num2-vs-void (result i32)
(block (i32.const 3) (block (i64.const 1) (return (i32.const 0))))
(i32.const 9)
@ -544,32 +594,32 @@
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-nested-unreachable-num-vs-void
(loop (i32.const 3) (block (unreachable)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-nested-unreachable-void-vs-num (result i32)
(loop (block (unreachable)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-loop-value-nested-unreachable-num-vs-num (result i32)
(loop i64 (i64.const 0) (block (unreachable)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-cont-last-void-vs-empty (result i32)
(loop (br 0 (nop)))
))
"type mismatch"
)
(assert_soft_invalid
(assert_invalid
(module (func $type-cont-last-num-vs-empty (result i32)
(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)
(memory 1 10)
)`, /popping value from empty stack/);
)`, emptyStackError);
// function calls
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;
}
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') {
let caught = false;
let errMsg = e.list[2];

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

@ -474,6 +474,24 @@ JS_NewContext(uint32_t maxbytes, uint32_t maxNurseryBytes, JSRuntime* parentRunt
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_DestroyContext(JSContext* cx)
{

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

@ -981,11 +981,37 @@ JS_IsBuiltinFunctionConstructor(JSFunction* fun);
* 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*)
JS_NewContext(uint32_t maxbytes,
uint32_t maxNurseryBytes = JS::DefaultNurseryBytes,
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)
JS_DestroyContext(JSContext* cx);

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

@ -99,36 +99,43 @@ js::TraceCycleDetectionSet(JSTracer* trc, AutoCycleDetector::Set& set)
}
bool
JSContext::init()
JSContext::init(ContextKind kind)
{
// Get a platform-native handle for this thread, used by js::InterruptRunningJitCode.
// 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.
#ifdef XP_WIN
size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
THREAD_QUERY_INFORMATION;
HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId());
if (!self)
size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
THREAD_QUERY_INFORMATION;
HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId());
if (!self)
return false;
static_assert(sizeof(HANDLE) <= sizeof(threadNative_), "need bigger field");
threadNative_ = (size_t)self;
static_assert(sizeof(HANDLE) <= sizeof(threadNative_), "need bigger field");
threadNative_ = (size_t)self;
#else
static_assert(sizeof(pthread_t) <= sizeof(threadNative_), "need bigger field");
threadNative_ = (size_t)pthread_self();
static_assert(sizeof(pthread_t) <= sizeof(threadNative_), "need bigger field");
threadNative_ = (size_t)pthread_self();
#endif
if (!regexpStack.ref().init())
return false;
if (!regexpStack.ref().init())
return false;
if (!fx.initInstance())
return false;
if (!fx.initInstance())
return false;
#ifdef JS_SIMULATOR
simulator_ = js::jit::Simulator::Create(this);
if (!simulator_)
return false;
simulator_ = js::jit::Simulator::Create(this);
if (!simulator_)
return false;
#endif
if (!wasm::EnsureSignalHandlers(this))
return false;
if (!wasm::EnsureSignalHandlers(this))
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;
}
@ -156,8 +163,7 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
return nullptr;
}
if (!cx->init()) {
if (!cx->init(ContextKind::Cooperative)) {
js_delete(cx);
js_delete(runtime);
return nullptr;
@ -166,6 +172,39 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
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
js::DestroyContext(JSContext* cx)
{
@ -186,6 +225,8 @@ js::DestroyContext(JSContext* cx)
// Destroy the runtime along with its last context.
cx->runtime()->destroyRuntime();
js_delete(cx->runtime());
js_delete_poison(cx);
} else {
DebugOnly<bool> found = false;
for (size_t i = 0; i < cx->runtime()->cooperatingContexts().length(); i++) {
@ -197,9 +238,9 @@ js::DestroyContext(JSContext* cx)
}
}
MOZ_ASSERT(found);
}
js_delete_poison(cx);
cx->runtime()->deleteActiveContext(cx);
}
}
void
@ -1092,6 +1133,7 @@ JSContext::alreadyReportedError()
JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
: runtime_(runtime),
kind_(ContextKind::Background),
threadNative_(0),
helperThread_(nullptr),
options_(options),
@ -1171,15 +1213,20 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
{
MOZ_ASSERT(static_cast<JS::RootingContext*>(this) ==
JS::RootingContext::get(this));
for (size_t i = 0; i < mozilla::ArrayLength(nativeStackQuota); i++)
nativeStackQuota[i] = 0;
MOZ_ASSERT(!TlsContext.get());
TlsContext.set(this);
for (size_t i = 0; i < mozilla::ArrayLength(nativeStackQuota); i++)
nativeStackQuota[i] = 0;
}
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
if (threadNative_)
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. */
extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
enum class ContextKind
{
Cooperative,
Background
};
} /* namespace js */
/*
@ -89,13 +95,14 @@ extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
struct JSContext : public JS::RootingContext,
public js::MallocProvider<JSContext>
{
explicit JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
~JSContext();
bool init();
bool init(js::ContextKind kind);
private:
js::UnprotectedData<JSRuntime*> runtime_;
js::WriteOnceData<js::ContextKind> kind_;
// System handle for the thread this context is associated with.
js::WriteOnceData<size_t> threadNative_;
@ -112,6 +119,7 @@ struct JSContext : public JS::RootingContext,
// currently operating on.
void setRuntime(JSRuntime* rt);
bool isCooperativelyScheduled() const { return kind_ == js::ContextKind::Cooperative; }
size_t threadNative() const { return threadNative_; }
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(); }
/* Client opaque pointer. */
void* data;
js::UnprotectedData<void*> data;
void initJitStackLimit();
void resetJitStackLimit();
@ -951,6 +959,15 @@ struct MOZ_RAII AutoResolving {
extern JSContext*
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
DestroyContext(JSContext* cx);

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

@ -984,9 +984,10 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
if (op == JSOP_TRY) {
TryNoteArray* trynotes = script->trynotes();
uint32_t i;
size_t mainOffset = script->mainOffset();
for(i = 0; i < trynotes->length; 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)",
unsigned(loc + note.length + 1),
int(note.length + 1)))

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