merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2016-07-29 11:56:43 +02:00
commit 8c47612fee
140 changed files with 2639 additions and 1467 deletions

View File

@ -63,17 +63,16 @@ add_task(function* test() {
});
}
// make sure we have received a message
yield ContentTask.spawn(receiver.browser, channelName,
function* (name) {
yield content.window.testPromise.then(function() {});
}
);
// Since sender1 sends before sender2, if the title is exactly
// sender2's message, sender1's message must've been blocked
is(receiver.browser.contentDocument.title, sender2.message,
"should only receive messages from the same user context");
yield ContentTask.spawn(receiver.browser, sender2.message,
function* (message) {
yield content.window.testPromise.then(function() {
is(content.document.title, message,
"should only receive messages from the same user context");
});
}
);
gBrowser.removeTab(sender1.tab);
gBrowser.removeTab(sender2.tab);

View File

@ -35,7 +35,6 @@ support-files =
[browser_ext_contextMenus_urlPatterns.js]
[browser_ext_currentWindow.js]
[browser_ext_getViews.js]
[browser_ext_history.js]
[browser_ext_incognito_popup.js]
[browser_ext_lastError.js]
[browser_ext_optionsPage_privileges.js]

View File

@ -1,3 +1,7 @@
{
"extends": "../../../../../testing/xpcshell/xpcshell.eslintrc",
"globals": {
"browser": false,
},
}

View File

@ -2,12 +2,24 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
/* exported createHttpServer */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
"resource://gre/modules/ExtensionManagement.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils",
"resource://testing-common/ExtensionXPCShellUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
"resource://testing-common/httpd.js");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
@ -15,36 +27,29 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
/* exported normalizeManifest */
ExtensionTestUtils.init(this);
let BASE_MANIFEST = {
"applications": {"gecko": {"id": "test@web.ext"}},
"manifest_version": 2,
/**
* Creates a new HttpServer for testing, and begins listening on the
* specified port. Automatically shuts down the server when the test
* unit ends.
*
* @param {integer} [port]
* The port to listen on. If omitted, listen on a random
* port. The latter is the preferred behavior.
*
* @returns {HttpServer}
*/
function createHttpServer(port = -1) {
let server = new HttpServer();
server.start(port);
"name": "name",
"version": "0",
};
do_register_cleanup(() => {
return new Promise(resolve => {
server.stop(resolve);
});
});
function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) {
const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
yield Management.lazyInit();
let errors = [];
let context = {
url: null,
logError: error => {
errors.push(error);
},
preprocessors: {},
};
manifest = Object.assign({}, baseManifest, manifest);
let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context);
normalized.errors = errors;
return normalized;
return server;
}

View File

@ -1,16 +1,5 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebExtension test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
function backgroundScript() {
@ -276,13 +265,13 @@ function backgroundScript() {
return browser.bookmarks.search("Menu Item");
}).then(results => {
browser.test.assertEq(1, results.length, "Expected number of results returned for menu item search");
checkBookmark({title: "Menu Item", url: "http://menu.org/", index: 3, parentId: bookmarkGuids.menuGuid}, results[0]);
checkBookmark({title: "Menu Item", url: "http://menu.org/", index: 0, parentId: bookmarkGuids.menuGuid}, results[0]);
// finds toolbar items
return browser.bookmarks.search("Toolbar Item");
}).then(results => {
browser.test.assertEq(1, results.length, "Expected number of results returned for toolbar item search");
checkBookmark({title: "Toolbar Item", url: "http://toolbar.org/", index: 2, parentId: bookmarkGuids.toolbarGuid}, results[0]);
checkBookmark({title: "Toolbar Item", url: "http://toolbar.org/", index: 0, parentId: bookmarkGuids.toolbarGuid}, results[0]);
// finds folders
return browser.bookmarks.search("Mozilla Folder");
@ -389,7 +378,7 @@ function backgroundScript() {
return browser.bookmarks.move(corporationBookmark.id, {parentId: bookmarkGuids.menuGuid});
}).then(result => {
browser.test.assertEq(bookmarkGuids.menuGuid, result.parentId, "Bookmark has the expected parent");
browser.test.assertEq(childCount + 1, result.index, "Bookmark has the expected index");
browser.test.assertEq(childCount, result.index, "Bookmark has the expected index");
return browser.bookmarks.move(corporationBookmark.id, {index: 1});
}).then(result => {
@ -490,8 +479,3 @@ add_task(function* test_contentscript() {
yield extension.awaitFinish("bookmarks");
yield extension.unload();
});
</script>
</body>
</html>

View File

@ -85,14 +85,14 @@ add_task(function* test_delete() {
}
yield PlacesUtils.history.insertMany(visits);
is(yield PlacesTestUtils.visitsInDB(visits[0].url), 5, "5 visits for uri found in history database");
equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 5, "5 visits for uri found in history database");
let testUrl = visits[2].url;
ok(yield PlacesTestUtils.isPageInDB(testUrl), "expected url found in history database");
ok((yield PlacesTestUtils.isPageInDB(testUrl)), "expected url found in history database");
extension.sendMessage("delete-url", testUrl);
yield extension.awaitMessage("url-deleted");
is(yield PlacesTestUtils.isPageInDB(testUrl), false, "expected url not found in history database");
equal((yield PlacesTestUtils.isPageInDB(testUrl)), false, "expected url not found in history database");
// delete 3 of the 5 visits for url 1
let filter = {
@ -103,10 +103,10 @@ add_task(function* test_delete() {
extension.sendMessage("delete-range", filter);
let removedUrls = yield extension.awaitMessage("range-deleted");
ok(!removedUrls.includes(visits[0].url), `${visits[0].url} not received by onVisitRemoved`);
ok(yield PlacesTestUtils.isPageInDB(visits[0].url), "expected uri found in history database");
is(yield PlacesTestUtils.visitsInDB(visits[0].url), 2, "2 visits for uri found in history database");
ok(yield PlacesTestUtils.isPageInDB(visits[1].url), "expected uri found in history database");
is(yield PlacesTestUtils.visitsInDB(visits[1].url), 1, "1 visit for uri found in history database");
ok((yield PlacesTestUtils.isPageInDB(visits[0].url)), "expected uri found in history database");
equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 2, "2 visits for uri found in history database");
ok((yield PlacesTestUtils.isPageInDB(visits[1].url)), "expected uri found in history database");
equal((yield PlacesTestUtils.visitsInDB(visits[1].url)), 1, "1 visit for uri found in history database");
// delete the rest of the visits for url 1, and the visit for url 2
filter.startTime = visits[0].visits[0].date;
@ -115,18 +115,18 @@ add_task(function* test_delete() {
extension.sendMessage("delete-range", filter);
yield extension.awaitMessage("range-deleted");
is(yield PlacesTestUtils.isPageInDB(visits[0].url), false, "expected uri not found in history database");
is(yield PlacesTestUtils.visitsInDB(visits[0].url), 0, "0 visits for uri found in history database");
is(yield PlacesTestUtils.isPageInDB(visits[1].url), false, "expected uri not found in history database");
is(yield PlacesTestUtils.visitsInDB(visits[1].url), 0, "0 visits for uri found in history database");
equal((yield PlacesTestUtils.isPageInDB(visits[0].url)), false, "expected uri not found in history database");
equal((yield PlacesTestUtils.visitsInDB(visits[0].url)), 0, "0 visits for uri found in history database");
equal((yield PlacesTestUtils.isPageInDB(visits[1].url)), false, "expected uri not found in history database");
equal((yield PlacesTestUtils.visitsInDB(visits[1].url)), 0, "0 visits for uri found in history database");
ok(yield PlacesTestUtils.isPageInDB(visits[3].url), "expected uri found in history database");
ok((yield PlacesTestUtils.isPageInDB(visits[3].url)), "expected uri found in history database");
extension.sendMessage("delete-all");
[historyClearedCount, removedUrls] = yield extension.awaitMessage("history-cleared");
is(PlacesUtils.history.hasHistoryEntries, false, "history is empty");
is(historyClearedCount, 2, "onVisitRemoved called for each clearing of history");
is(removedUrls.length, 3, "onVisitRemoved called the expected number of times");
equal(PlacesUtils.history.hasHistoryEntries, false, "history is empty");
equal(historyClearedCount, 2, "onVisitRemoved called for each clearing of history");
equal(removedUrls.length, 3, "onVisitRemoved called the expected number of times");
for (let i = 1; i < 3; ++i) {
let url = visits[i].url;
ok(removedUrls.includes(url), `${url} received by onVisitRemoved`);
@ -215,9 +215,9 @@ add_task(function* test_search() {
function checkResult(results, url, expectedCount) {
let result = findResult(url, results);
isnot(result, null, `history.search result was found for ${url}`);
is(result.visitCount, expectedCount, `history.search reports ${expectedCount} visit(s)`);
is(result.title, `test visit for ${url}`, "title for search result is correct");
notEqual(result, null, `history.search result was found for ${url}`);
equal(result.visitCount, expectedCount, `history.search reports ${expectedCount} visit(s)`);
equal(result.title, `test visit for ${url}`, "title for search result is correct");
}
yield extension.startup();
@ -229,21 +229,21 @@ add_task(function* test_search() {
extension.sendMessage("check-history");
let results = yield extension.awaitMessage("empty-search");
is(results.length, 3, "history.search with empty text returned 3 results");
equal(results.length, 3, "history.search with empty text returned 3 results");
checkResult(results, SINGLE_VISIT_URL, 1);
checkResult(results, DOUBLE_VISIT_URL, 2);
checkResult(results, MOZILLA_VISIT_URL, 1);
results = yield extension.awaitMessage("text-search");
is(results.length, 1, "history.search with specific text returned 1 result");
equal(results.length, 1, "history.search with specific text returned 1 result");
checkResult(results, MOZILLA_VISIT_URL, 1);
results = yield extension.awaitMessage("max-results-search");
is(results.length, 1, "history.search with maxResults returned 1 result");
equal(results.length, 1, "history.search with maxResults returned 1 result");
checkResult(results, DOUBLE_VISIT_URL, 2);
results = yield extension.awaitMessage("date-range-search");
is(results.length, 2, "history.search with a date range returned 2 result");
equal(results.length, 2, "history.search with a date range returned 2 result");
checkResult(results, DOUBLE_VISIT_URL, 2);
checkResult(results, SINGLE_VISIT_URL, 1);
@ -300,11 +300,11 @@ add_task(function* test_add_url() {
];
function* checkUrl(results) {
ok(yield PlacesTestUtils.isPageInDB(results.details.url), `${results.details.url} found in history database`);
ok((yield PlacesTestUtils.isPageInDB(results.details.url)), `${results.details.url} found in history database`);
ok(PlacesUtils.isValidGuid(results.result.id), "URL was added with a valid id");
is(results.result.title, results.details.title, "URL was added with the correct title");
equal(results.result.title, results.details.title, "URL was added with the correct title");
if (results.details.visitTime) {
is(results.result.lastVisitTime,
equal(results.result.lastVisitTime,
Number(ExtensionUtils.normalizeTime(results.details.visitTime)),
"URL was added with the correct date");
}
@ -458,12 +458,12 @@ add_task(function* test_on_visited() {
function checkOnVisitedData(index, expected) {
let onVisited = onVisitedData[index];
ok(PlacesUtils.isValidGuid(onVisited.id), "onVisited received a valid id");
is(onVisited.url, expected.url, "onVisited received the expected url");
equal(onVisited.url, expected.url, "onVisited received the expected url");
// Title will be blank until bug 1287928 lands
// https://bugzilla.mozilla.org/show_bug.cgi?id=1287928
is(onVisited.title, "", "onVisited received a blank title");
is(onVisited.lastVisitTime, expected.time, "onVisited received the expected time");
is(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount");
equal(onVisited.title, "", "onVisited received a blank title");
equal(onVisited.lastVisitTime, expected.time, "onVisited received the expected time");
equal(onVisited.visitCount, expected.visitCount, "onVisited received the expected visitCount");
}
let expected = {

View File

@ -4,7 +4,7 @@
add_task(function* test_manifest_commands() {
let normalized = yield normalizeManifest({
let normalized = yield ExtensionTestUtils.normalizeManifest({
"commands": {
"toggle-feature": {
"suggested_key": {"default": "Shifty+Y"},

View File

@ -3,4 +3,6 @@ head = head.js
tail =
firefox-appdir = browser
[test_ext_bookmarks.js]
[test_ext_history.js]
[test_ext_manifest_commands.js]

View File

@ -108,37 +108,9 @@ this.ContentLinkHandler = {
}
sizeHistogramTypes.add(sizesType);
if (uri.scheme == 'blob') {
// Blob URLs don't work cross process, work around this by sending as a data uri
let channel = NetUtil.newChannel({
uri: uri,
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE,
loadUsingSystemPrincipal: true
});
let listener = {
encoded: "",
bis: null,
onStartRequest: function(aRequest, aContext) {
this.bis = Components.classes["@mozilla.org/binaryinputstream;1"]
.createInstance(Components.interfaces.nsIBinaryInputStream);
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
let spec = "data:" + channel.contentType + ";base64," + this.encoded;
chromeGlobal.sendAsyncMessage(
"Link:SetIcon",
{url: spec, loadingPrincipal: link.ownerDocument.nodePrincipal});
},
onDataAvailable: function(request, context, inputStream, offset, count) {
this.bis.setInputStream(inputStream);
this.encoded += btoa(this.bis.readBytes(this.bis.available()));
}
}
channel.asyncOpen2(listener);
} else {
chromeGlobal.sendAsyncMessage(
"Link:SetIcon",
{url: uri.spec, loadingPrincipal: link.ownerDocument.nodePrincipal});
}
chromeGlobal.sendAsyncMessage(
"Link:SetIcon",
{url: uri.spec, loadingPrincipal: link.ownerDocument.nodePrincipal});
iconAdded = true;
break;
case "search":

View File

@ -2425,7 +2425,8 @@ nsDocument::FillStyleSet(StyleSetHandle aStyleSet)
}
}
} else {
NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet");
NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed "
"documents. See bug 1290224");
}
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
@ -13350,7 +13351,8 @@ nsIDocument::FlushUserFontSet()
return;
}
} else {
NS_ERROR("stylo: ServoStyleSets cannot handle @font-face rules yet");
NS_WARNING("stylo: ServoStyleSets cannot handle @font-face rules yet. "
"See bug 1290237.");
}
}
@ -13439,6 +13441,10 @@ nsIDocument::UpdateStyleBackendType()
{
MOZ_ASSERT(mStyleBackendType == StyleBackendType(0),
"no need to call UpdateStyleBackendType now");
// Assume Gecko by default.
mStyleBackendType = StyleBackendType::Gecko;
#ifdef MOZ_STYLO
// XXX For now we use a Servo-backed style set only for (X)HTML documents
// in content docshells. This should let us avoid implementing XUL-specific
@ -13447,15 +13453,11 @@ nsIDocument::UpdateStyleBackendType()
// document before we have a pres shell (i.e. before we make the decision
// here about whether to use a Gecko- or Servo-backed style system), so
// we avoid Servo-backed style sets for SVG documents.
NS_ASSERTION(mDocumentContainer, "stylo: calling UpdateStyleBackendType "
"before we have a docshell");
mStyleBackendType =
nsLayoutUtils::SupportsServoStyleBackend(this) &&
mDocumentContainer ?
StyleBackendType::Servo :
StyleBackendType::Gecko;
#else
mStyleBackendType = StyleBackendType::Gecko;
if (!mDocumentContainer) {
NS_WARNING("stylo: No docshell yet, assuming Gecko style system");
} else if (nsLayoutUtils::SupportsServoStyleBackend(this)) {
mStyleBackendType = StyleBackendType::Servo;
}
#endif
}

View File

@ -30,7 +30,8 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray,
mWindow,
mMimeTypes)
mMimeTypes,
mCTPMimeTypes)
nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow)
@ -57,6 +58,7 @@ void
nsMimeTypeArray::Refresh()
{
mMimeTypes.Clear();
mCTPMimeTypes.Clear();
}
nsPIDOMWindowInner*
@ -133,6 +135,10 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
aFound = true;
return mimeType;
}
nsMimeType* hiddenType = FindMimeType(mCTPMimeTypes, lowerName);
if (hiddenType) {
nsPluginArray::NotifyHiddenPluginTouched(hiddenType->GetEnabledPlugin());
}
return nullptr;
}
@ -180,6 +186,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes()
}
pluginArray->GetMimeTypes(mMimeTypes);
pluginArray->GetCTPMimeTypes(mCTPMimeTypes);
}
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef)

View File

@ -48,6 +48,7 @@ protected:
// mMimeTypes contains MIME types handled by plugins or by an OS
// PreferredApplicationHandler.
nsTArray<RefPtr<nsMimeType> > mMimeTypes;
nsTArray<RefPtr<nsMimeType> > mCTPMimeTypes;
};
class nsMimeType final : public nsWrapperCache

View File

@ -114,6 +114,24 @@ nsPluginArray::GetMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes)
aMimeTypes.Sort();
}
void
nsPluginArray::GetCTPMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes)
{
aMimeTypes.Clear();
if (!AllowPlugins()) {
return;
}
EnsurePlugins();
GetPluginMimeTypes(mCTPPlugins, aMimeTypes);
// Alphabetize the enumeration order of non-hidden MIME types to reduce
// fingerprintable entropy based on plugins' installation file times.
aMimeTypes.Sort();
}
nsPluginElement*
nsPluginArray::Item(uint32_t aIndex)
{
@ -236,21 +254,26 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
if (!aFound) {
nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName);
if (hiddenPlugin) {
HiddenPluginEventInit init;
init.mTag = hiddenPlugin->PluginTag();
nsCOMPtr<nsIDocument> doc = hiddenPlugin->GetParentObject()->GetDoc();
RefPtr<HiddenPluginEvent> event =
HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init);
event->SetTarget(doc);
event->SetTrusted(true);
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
bool dummy;
doc->DispatchEvent(event, &dummy);
NotifyHiddenPluginTouched(hiddenPlugin);
}
}
return plugin;
}
void nsPluginArray::NotifyHiddenPluginTouched(nsPluginElement* aHiddenElement)
{
HiddenPluginEventInit init;
init.mTag = aHiddenElement->PluginTag();
nsCOMPtr<nsIDocument> doc = aHiddenElement->GetParentObject()->GetDoc();
RefPtr<HiddenPluginEvent> event =
HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init);
event->SetTarget(doc);
event->SetTrusted(true);
event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
bool dummy;
doc->DispatchEvent(event, &dummy);
}
uint32_t
nsPluginArray::Length()
{

View File

@ -41,6 +41,9 @@ public:
void Invalidate();
void GetMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes);
void GetCTPMimeTypes(nsTArray<RefPtr<nsMimeType>>& aMimeTypes);
static void NotifyHiddenPluginTouched(nsPluginElement* aElement);
// PluginArray WebIDL methods

View File

@ -346,16 +346,10 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride);
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
if (!mBoundVertexArray->mAttribs[index].enabled)
return JS::Int32Value(4);
return JS::Int32Value(mBoundVertexArray->mAttribs[index].size);
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
if (!mBoundVertexArray->mAttribs[index].enabled)
return JS::NumberValue(uint32_t(LOCAL_GL_FLOAT));
return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
return JS::Int32Value(mBoundVertexArray->mAttribs[index].type);
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER:
if (IsWebGL2())

View File

@ -262,6 +262,9 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
bytes = view.DataAllowShared();
byteCount = view.LengthAllowShared();
}
} else if (isSubImage) {
mContext->ErrorInvalidValue("%s: `pixels` must not be null.", funcName);
return;
}
const bool isClientData = true;

View File

@ -0,0 +1,9 @@
<canvas id='i0'></canvas>
<script>
var c=document.getElementById('i0').getContext('2d');
c.lineWidth=194.622602174;
c.miterLimit=270.273509738;
c.transform(0,0,0,0,0,0);
c.globalCompositeOperation='soft-light';
c.strokeText('a',200,273,722);
</script>

View File

@ -0,0 +1,8 @@
<canvas id='i0'></canvas>
<script>
var c=document.getElementById('i0').getContext('2d');
c.bezierCurveTo(157,351,351,44,946,701);
c.quadraticCurveTo(260,-9007199254740991,945,145);
c.translate(-9007199254740991,239);
c.isPointInPath(988,439);
</script>

View File

@ -0,0 +1,8 @@
<canvas id='i0'></canvas>
<script>
var c=document.getElementById('i0').getContext('2d');
var g=c.createLinearGradient(59,9,38.89,-75.51);
c.fillStyle=g;
c.globalAlpha=0.62;
c.fillText('a',0,24,30);
</script>

View File

@ -29,6 +29,9 @@ skip-if(azureCairo) load 1229983-1.html
load 1229932-1.html
load 1244850-1.html
load 1246775-1.html
load 1284356-1.html
load 1284578-1.html
skip-if(d2d) load 1287515-1.html
load 1287652-1.html
load 1288872-1.html

View File

@ -5838,7 +5838,6 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.
[generated/test_2_conformance__textures__misc__tex-image-with-invalid-data.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
[generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
fail-if = (os == 'mac') || (os == 'win')
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
[generated/test_2_conformance__textures__misc__tex-sub-image-2d.html]
skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2'))
@ -6722,7 +6721,6 @@ skip-if = (os == 'android')
skip-if = (os == 'android')
[generated/test_conformance__textures__misc__tex-input-validation.html]
[generated/test_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
[generated/test_conformance__textures__misc__tex-sub-image-2d.html]
[generated/test_conformance__textures__misc__texparameter-test.html]
[generated/test_conformance__textures__misc__texture-active-bind-2.html]

View File

@ -148,8 +148,6 @@ fail-if = (os == 'mac')
fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance2__glsl3__forbidden-operators.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
[generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_2_conformance__rendering__negative-one-index.html]
@ -160,8 +158,6 @@ fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
fail-if = (os == 'mac') || (os == 'win')
[generated/test_conformance__attribs__gl-vertexattribpointer.html]
fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux')
[generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html]
fail-if = (os == 'mac') || (os == 'win')
[generated/test_conformance__ogles__GL__biuDepthRange__biuDepthRange_001_to_002.html]
fail-if = (os == 'android') || (os == 'linux')
[generated/test_conformance__ogles__GL__gl_FragCoord__gl_FragCoord_001_to_003.html]

View File

@ -2365,22 +2365,6 @@ HTMLInputElement::GetValueIfStepped(int32_t aStep,
value += step * Decimal(aStep);
}
// For date inputs, the value can hold a string that is not a day. We do not
// want to round it, as it might result in a step mismatch. Instead we want to
// clamp to the next valid value.
if (mType == NS_FORM_INPUT_DATE &&
NS_floorModulo(Decimal(value - GetStepBase()), GetStepScaleFactor()) != Decimal(0)) {
MOZ_ASSERT(GetStep() > Decimal(0));
Decimal validStep = EuclidLCM<Decimal>(GetStep().floor(),
GetStepScaleFactor().floor());
if (aStep > 0) {
value -= NS_floorModulo(value - GetStepBase(), validStep);
value += validStep;
} else if (aStep < 0) {
value -= NS_floorModulo(value - GetStepBase(), validStep);
}
}
if (value < minimum) {
value = minimum;
deltaFromStep = NS_floorModulo(value - stepBase, step);
@ -6903,6 +6887,11 @@ HTMLInputElement::GetStep() const
step = GetDefaultStep();
}
// For input type=date, we round the step value to have a rounded day.
if (mType == NS_FORM_INPUT_DATE) {
step = std::max(step.round(), Decimal(1));
}
return step * GetStepScaleFactor();
}
@ -7506,16 +7495,6 @@ HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
Decimal step = GetStep();
MOZ_ASSERT(step != kStepAny && step > Decimal(0));
// In case this is a date and the step is not an integer, we don't want to
// display the dates corresponding to the truncated timestamps of valueLow
// and valueHigh because they might suffer from a step mismatch as well.
// Instead we want the timestamps to correspond to a rounded day. That is,
// we want a multiple of the step scale factor (1 day) as well as of step.
if (mType == NS_FORM_INPUT_DATE) {
step = EuclidLCM<Decimal>(step.floor(),
GetStepScaleFactor().floor());
}
Decimal stepBase = GetStepBase();
Decimal valueLow = value - NS_floorModulo(value - stepBase, step);

View File

@ -76,6 +76,7 @@ static constexpr const nsAttrValue::EnumTable* kKindTableInvalidValueDefault = &
/** HTMLTrackElement */
HTMLTrackElement::HTMLTrackElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mLoadResourceDispatched(false)
{
}
@ -182,9 +183,46 @@ HTMLTrackElement::ParseAttribute(int32_t aNamespaceID,
aResult);
}
void
HTMLTrackElement::SetSrc(const nsAString& aSrc, ErrorResult& aError)
{
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
uint16_t oldReadyState = ReadyState();
SetReadyState(TextTrackReadyState::NotLoaded);
if (!mMediaParent) {
return;
}
if (mTrack && (oldReadyState != TextTrackReadyState::NotLoaded)) {
// Remove all the cues in MediaElement.
mMediaParent->RemoveTextTrack(mTrack);
// Recreate mTrack.
CreateTextTrack();
}
// Stop WebVTTListener.
mListener = nullptr;
if (mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
mChannel = nullptr;
}
DispatchLoadResource();
}
void
HTMLTrackElement::DispatchLoadResource()
{
if (!mLoadResourceDispatched) {
RefPtr<Runnable> r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource);
nsContentUtils::RunInStableState(r.forget());
mLoadResourceDispatched = true;
}
}
void
HTMLTrackElement::LoadResource()
{
mLoadResourceDispatched = false;
// Find our 'src' url
nsAutoString src;
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
@ -258,8 +296,7 @@ HTMLTrackElement::BindToTree(nsIDocument* aDocument,
if (!mTrack) {
CreateTextTrack();
}
RefPtr<Runnable> r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource);
nsContentUtils::RunInStableState(r.forget());
DispatchLoadResource();
}
return NS_OK;

View File

@ -46,10 +46,8 @@ public:
{
GetHTMLURIAttr(nsGkAtoms::src, aSrc);
}
void SetSrc(const nsAString& aSrc, ErrorResult& aError)
{
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
}
void SetSrc(const nsAString& aSrc, ErrorResult& aError);
void GetSrclang(DOMString& aSrclang) const
{
@ -134,6 +132,10 @@ protected:
RefPtr<WebVTTListener> mListener;
void CreateTextTrack();
private:
void DispatchLoadResource();
bool mLoadResourceDispatched;
};
} // namespace dom

View File

@ -185,7 +185,7 @@ for (var test of data) {
input.min = '2009-02-01';
input.step = '1.1';
input.value = '2009-02-02';
checkValidity(input, false, apply, { low: "2009-02-01", high: "2009-02-12" });
checkValidity(input, true, apply);
// Without any step attribute the date is valid
input.removeAttribute('step');
@ -203,21 +203,21 @@ for (var test of data) {
input.step = '0.9';
input.value = '1951-01-02';
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-10" });
input.value = '1951-01-10'
is(input.step, '0.9', "check that step value is unchanged");
checkValidity(input, true, apply);
input.step = '0.5';
input.step = '0.4';
input.value = '1951-01-02';
is(input.step, '0.4', "check that step value is unchanged");
checkValidity(input, true, apply);
input.step = '1.5';
input.value = '1951-01-03';
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-04" });
input.value = '1951-01-02';
is(input.step, '1.5', "check that step value is unchanged");
checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-03" });
input.value = '1951-01-08';
checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-10" });
checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-09" });
input.step = '3000';
input.min= '1968-01-01';
@ -236,26 +236,26 @@ for (var test of data) {
input.value = '1992-08-22';
checkValidity(input, true, apply);
input.step = '1.1';
input.step = '2.1';
input.min = '1991-01-01';
input.value = '1991-01-01';
checkValidity(input, true, apply);
input.value = '1991-01-02';
checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-12" });
checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-03" });
input.value = '1991-01-12';
input.value = '1991-01-03';
checkValidity(input, true, apply);
input.step = '1.1';
input.step = '2.1';
input.min = '1969-12-20';
input.value = '1969-12-20';
checkValidity(input, true, apply);
input.value = '1969-12-21';
checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-31" });
checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-22" });
input.value = '1969-12-31';
input.value = '1969-12-22';
checkValidity(input, true, apply);
break;

View File

@ -271,12 +271,12 @@ function checkStepDown()
[ '2012-01-03', '0.5', null, null, null, '2012-01-02', false ],
[ '2012-01-02', '0.5', null, null, null, '2012-01-01', false ],
[ '2012-01-01', '2', null, null, null, '2011-12-30', false ],
[ '2012-01-02', '0.25',null, null, 4, '2012-01-01', false ],
[ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-12', false ],
[ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-01', false ],
[ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-12', false ],
[ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-01', false ],
[ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-01', false ],
[ '2012-01-02', '0.25',null, null, 4, '2011-12-29', false ],
[ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-14', false ],
[ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-10', false ],
[ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-13', false ],
[ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-12', false ],
[ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-04', false ],
// step = 0 isn't allowed (-> step = 1).
[ '2012-01-02', '0', null, null, null, '2012-01-01', false ],
// step < 0 isn't allowed (-> step = 1).
@ -588,14 +588,13 @@ function checkStepUp()
[ '2012-01-01', null, null, null, 1.9, '2012-01-02', false ],
// With step values.
[ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ],
[ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ],
[ '2012-01-01', '2', null, null, null, '2012-01-03', false ],
[ '2012-01-01', '0.25', null, null, 4, '2012-01-02', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-12', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-12', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-12', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-23', false ],
[ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-12', false ],
[ '2012-01-01', '0.25', null, null, 4, '2012-01-05', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-02', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-03', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-11', false ],
[ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-12', false ],
[ '1968-01-01', '1.1', '1968-01-01', null, 8, '1968-01-09', false ],
// step = 0 isn't allowed (-> step = 1).
[ '2012-01-01', '0', null, null, null, '2012-01-02', false ],
// step < 0 isn't allowed (-> step = 1).

View File

@ -856,6 +856,8 @@ tags = webvtt
[test_timeupdate_small_files.html]
[test_trackelementevent.html]
tags = webvtt
[test_trackelementsrc.html]
tags = webvtt
[test_trackevent.html]
tags = webvtt
[test_unseekable.html]

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Bug 1281418 - Change the src attribue for TrackElement.</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true],
["media.webvtt.regions.enabled", true]]}, function() {
var video = document.createElement("video");
video.src = "seek.webm";
video.preload = "metadata";
var trackElement = document.createElement("track");
trackElement.src = "basic.vtt";
trackElement.default = true;
document.getElementById("content").appendChild(video);
video.appendChild(trackElement);
video.addEventListener("loadedmetadata", function metadata() {
if (trackElement.readyState <= 1) {
return setTimeout(metadata, 0);
}
is(video.textTracks.length, 1, "Length should be 1.");
is(video.textTracks[0].cues.length, 6, "Cue length should be 6.");
trackElement.src = "sequential.vtt";
trackElement.track.mode = "showing";
video.play();
});
video.addEventListener("ended", function end() {
is(trackElement.readyState, 2, "readyState should be 2.")
is(video.textTracks.length, 1, "Length should be 1.");
is(video.textTracks[0].cues.length, 3, "Cue length should be 3.");
SimpleTest.finish();
});
});
</script>
</pre>
</body>
</html>

View File

@ -21,7 +21,9 @@ addEventListener('fetch', function(evt) {
evt.respondWith(registration.unregister().then(function() {
return new Response('service worker generated download', {
headers: {
'Content-Disposition': 'attachment; filename="fake_download.bin"'
'Content-Disposition': 'attachment; filename="fake_download.bin"',
// fake encoding header that should have no effect
'Content-Encoding': 'gzip',
}
});
}));

View File

@ -34,9 +34,12 @@ namespace image {
static LazyLogModule sPNGLog("PNGDecoder");
static LazyLogModule sPNGDecoderAccountingLog("PNGDecoderAccounting");
// Limit image dimensions (bug #251381, #591822, and #967656)
#ifndef MOZ_PNG_MAX_DIMENSION
# define MOZ_PNG_MAX_DIMENSION 32767
// limit image dimensions (bug #251381, #591822, #967656, and #1283961)
#ifndef MOZ_PNG_MAX_WIDTH
# define MOZ_PNG_MAX_WIDTH 0x7fffffff // Unlimited
#endif
#ifndef MOZ_PNG_MAX_HEIGHT
# define MOZ_PNG_MAX_HEIGHT 0x7fffffff // Unlimited
#endif
nsPNGDecoder::AnimFrameInfo::AnimFrameInfo()
@ -323,6 +326,7 @@ nsPNGDecoder::InitInternal()
#endif
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
png_set_user_limits(mPNG, MOZ_PNG_MAX_WIDTH, MOZ_PNG_MAX_HEIGHT);
if (mCMSMode != eCMSMode_Off) {
png_set_chunk_malloc_max(mPNG, 4000000L);
}
@ -557,11 +561,6 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_type);
// Are we too big?
if (width > MOZ_PNG_MAX_DIMENSION || height > MOZ_PNG_MAX_DIMENSION) {
png_longjmp(decoder->mPNG, 1);
}
const IntRect frameRect(0, 0, width, height);
// Post our size to the superclass

View File

@ -990,7 +990,7 @@ function ArrayConcat(arg1) {
if (n + len > MAX_NUMERIC_INDEX)
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
if (IsPackedArray(E)) {
if (IsPackedArray(A) && IsPackedArray(E)) {
// Step 5.c.i, 5.c.iv, and 5.c.iv.5.
for (k = 0; k < len; k++) {
// Steps 5.c.iv.1-3.

View File

@ -1792,8 +1792,11 @@ InitDateTimeFormatClass(JSContext* cx, HandleObject Intl, Handle<GlobalObject*>
// is enabled, also add it.
if (cx->compartment()->creationOptions().experimentalDateTimeFormatFormatToPartsEnabled()) {
RootedValue ftp(cx);
if (!GlobalObject::getIntrinsicValue(cx, cx->global(),
cx->names().DateTimeFormatFormatToParts, &ftp))
HandlePropertyName name = cx->names().formatToParts;
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(),
cx->names().DateTimeFormatFormatToParts,
name,
0, &ftp))
{
return nullptr;
}

View File

@ -1559,6 +1559,15 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto, uint8_t* resul
return true;
}
JSNative unicodeGetter;
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().unicode), &unicodeGetter))
return false;
if (unicodeGetter != regexp_unicode) {
*result = false;
return true;
}
// Check if @@match, @@search, and exec are own data properties,
// those values should be tested in selfhosted JS.
bool has = false;

View File

@ -579,6 +579,7 @@ function IsRegExpSplitOptimizable(rx, C) {
// If RegExpPrototypeOptimizable succeeds, `RegExpProto.exec` is guaranteed
// to be a data property.
return RegExpPrototypeOptimizable(RegExpProto) &&
RegExpInstanceOptimizable(rx, RegExpProto) &&
RegExpProto.exec === RegExp_prototype_Exec;
}
@ -603,7 +604,8 @@ function RegExpSplit(string, limit) {
// Steps 6-7.
var unicodeMatching = callFunction(std_String_includes, flags, "u");
var optimizable = IsRegExpSplitOptimizable(rx, C);
var optimizable = IsRegExpSplitOptimizable(rx, C) &&
(limit === undefined || typeof limit == "number");
var splitter;
if (optimizable) {
// Steps 8-9 (skipped).

View File

@ -864,23 +864,7 @@ GCState(JSContext* cx, unsigned argc, Value* vp)
return false;
}
const char* state;
gc::State globalState = cx->runtime()->gc.state();
if (globalState == gc::NO_INCREMENTAL)
state = "none";
else if (globalState == gc::MARK)
state = "mark";
else if (globalState == gc::SWEEP)
state = "sweep";
else if (globalState == gc::FINALIZE)
state = "finalize";
else if (globalState == gc::COMPACT)
state = "compact";
else if (globalState == gc::DECOMMIT)
state = "decommit";
else
MOZ_CRASH("Unobserveable global GC state");
const char* state = StateName(cx->runtime()->gc.state());
JSString* str = JS_NewStringCopyZ(cx, state);
if (!str)
return false;

View File

@ -689,8 +689,8 @@ class GCRuntime
public:
// Internal public interface
State state() const { return incrementalState; }
bool isHeapCompacting() const { return state() == COMPACT; }
bool isForegroundSweeping() const { return state() == SWEEP; }
bool isHeapCompacting() const { return state() == State::Compact; }
bool isForegroundSweeping() const { return state() == State::Sweep; }
bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
void waitBackgroundSweepOrAllocEnd() {
@ -766,7 +766,7 @@ class GCRuntime
void disallowIncrementalGC() { incrementalAllowed = false; }
bool isIncrementalGCEnabled() const { return mode == JSGC_MODE_INCREMENTAL && incrementalAllowed; }
bool isIncrementalGCInProgress() const { return state() != NO_INCREMENTAL; }
bool isIncrementalGCInProgress() const { return state() != State::NotActive; }
bool isGenerationalGCEnabled() const { return generationalDisabled == 0; }
void disableGenerationalGC();

View File

@ -346,8 +346,8 @@ static void
AssertRootMarkingPhase(JSTracer* trc)
{
MOZ_ASSERT_IF(trc->isMarkingTracer(),
trc->runtime()->gc.state() == NO_INCREMENTAL ||
trc->runtime()->gc.state() == MARK_ROOTS);
trc->runtime()->gc.state() == State::NotActive ||
trc->runtime()->gc.state() == State::MarkRoots);
}
@ -1945,7 +1945,7 @@ bool
GCMarker::markDelayedChildren(SliceBudget& budget)
{
GCRuntime& gc = runtime()->gc;
gcstats::AutoPhase ap(gc.stats, gc.state() == MARK, gcstats::PHASE_MARK_DELAYED);
gcstats::AutoPhase ap(gc.stats, gc.state() == State::Mark, gcstats::PHASE_MARK_DELAYED);
MOZ_ASSERT(unmarkedArenaStackTop);
do {
@ -2439,7 +2439,7 @@ CheckIsMarkedThing(T* thingp)
JSRuntime* rt = (*thingp)->runtimeFromAnyThread();
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
CurrentThreadCanAccessRuntime(rt) ||
(rt->isHeapCollecting() && rt->gc.state() == SWEEP));
(rt->isHeapCollecting() && rt->gc.state() == State::Sweep));
#endif
}

View File

@ -253,7 +253,7 @@ struct Statistics
double startTimestamp, size_t startFaults, gc::State initialState)
: budget(budget), reason(reason),
initialState(initialState),
finalState(gc::NO_INCREMENTAL),
finalState(gc::State::NotActive),
resetReason(nullptr),
start(start), startTimestamp(startTimestamp),
startFaults(startFaults)

View File

@ -203,7 +203,7 @@ gc::GCRuntime::startVerifyPreBarriers()
/* Create the root node. */
trc->curnode = MakeNode(trc, nullptr, JS::TraceKind(0));
incrementalState = MARK_ROOTS;
incrementalState = State::MarkRoots;
/* Make all the roots be edges emanating from the root node. */
markRuntime(trc, TraceRuntime, prep.session().lock);
@ -230,7 +230,7 @@ gc::GCRuntime::startVerifyPreBarriers()
}
verifyPreData = trc;
incrementalState = MARK;
incrementalState = State::Mark;
marker.start();
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
@ -244,7 +244,7 @@ gc::GCRuntime::startVerifyPreBarriers()
return;
oom:
incrementalState = NO_INCREMENTAL;
incrementalState = State::NotActive;
js_delete(trc);
verifyPreData = nullptr;
}
@ -342,7 +342,7 @@ gc::GCRuntime::endVerifyPreBarriers()
number++;
verifyPreData = nullptr;
incrementalState = NO_INCREMENTAL;
incrementalState = State::NotActive;
if (!compartmentCreated && IsIncrementalGCSafe(rt)) {
CheckEdgeTracer cetrc(rt);

View File

@ -286,13 +286,6 @@ GetCaseIndependentLetters(char16_t character,
for (size_t i = 0; i < choices_length; i++) {
char16_t c = choices[i];
// The standard requires that non-ASCII characters cannot have ASCII
// character codes in their equivalence class, even though this
// situation occurs multiple times in the unicode tables.
static const unsigned kMaxAsciiCharCode = 127;
if (!unicode && character > kMaxAsciiCharCode && c <= kMaxAsciiCharCode)
continue;
// Skip characters that can't appear in one byte strings.
if (!unicode && ascii_subject && c > kMaxOneByteCharCode)
continue;
@ -332,10 +325,40 @@ GetCaseIndependentLetters(char16_t character,
choices, ArrayLength(choices), letters);
}
char16_t upper = unicode::ToUpperCase(character);
unicode::CodepointsWithSameUpperCase others(character);
char16_t other1 = others.other1();
char16_t other2 = others.other2();
char16_t other3 = others.other3();
// ES 2017 draft 996af87b7072b3c3dd2b1def856c66f456102215 21.2.4.2
// step 3.g.
// The standard requires that non-ASCII characters cannot have ASCII
// character codes in their equivalence class, even though this
// situation occurs multiple times in the unicode tables.
static const unsigned kMaxAsciiCharCode = 127;
if (upper <= kMaxAsciiCharCode) {
if (character > kMaxAsciiCharCode) {
// If Canonicalize(character) == character, all other characters
// should be ignored.
return GetCaseIndependentLetters(character, ascii_subject, unicode,
&character, 1, letters);
}
if (other1 > kMaxAsciiCharCode)
other1 = character;
if (other2 > kMaxAsciiCharCode)
other2 = character;
if (other3 > kMaxAsciiCharCode)
other3 = character;
}
const char16_t choices[] = {
character,
unicode::ToLowerCase(character),
unicode::ToUpperCase(character)
upper,
other1,
other2,
other3
};
return GetCaseIndependentLetters(character, ascii_subject, unicode,
choices, ArrayLength(choices), letters);

View File

@ -17,12 +17,12 @@ var g = newGlobal();
// Start an off thread compilation that will not run until GC has finished
if ("gcstate" in this)
assertEq(gcstate(), "mark");
assertEq(gcstate(), "Mark");
g.offThreadCompileScript('23;', {});
// Wait for the compilation to finish, which must finish the GC first
assertEq(23, g.runOffThreadScript());
if ("gcstate" in this)
assertEq(gcstate(), "none");
assertEq(gcstate(), "NotActive");
print("done");

View File

@ -27,7 +27,7 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState)
var didAbort = false;
startgc(sliceCount, "shrinking");
while (gcstate() !== "none") {
while (gcstate() !== "NotActive") {
var state = gcstate();
if (state == abortState) {
abortgc();
@ -38,7 +38,7 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState)
gcslice(sliceCount);
}
assertEq(gcstate(), "none");
assertEq(gcstate(), "NotActive");
if (abortState)
assertEq(didAbort, true);
@ -47,6 +47,8 @@ function testAbort(zoneCount, objectCount, sliceCount, abortState)
gczeal(0);
testAbort(10, 10000, 10000);
testAbort(10, 10000, 10000, "mark");
testAbort(10, 10000, 10000, "sweep");
testAbort(10, 10000, 10000, "compact");
testAbort(10, 10000, 10000, "Mark");
testAbort(10, 10000, 10000, "Sweep");
testAbort(10, 10000, 10000, "Compact");
// Note: we do not yield automatically before Finalize or Decommit, as they yield internally.
// Thus, we may not witness an incremental state in this phase and cannot test it explicitly.

View File

@ -27,11 +27,11 @@ function testCompacting(zoneCount, objectCount, sliceCount)
}
// Finish any alloc-triggered incremental GC
if (gcstate() !== "none")
if (gcstate() !== "NotActive")
gc();
startgc(sliceCount, "shrinking");
while (gcstate() !== "none") {
while (gcstate() !== "NotActive") {
gcslice(sliceCount);
}

View File

@ -6,26 +6,26 @@ gczeal(0);
// Non-incremental GC.
gc();
assertEq(gcstate(), "none");
assertEq(gcstate(), "NotActive");
// Incremental GC in minimal slice. Note that finalization always uses zero-
// sized slices while background finalization is on-going, so we need to loop.
gcslice(1000000);
while (gcstate() == "finalize") { gcslice(1); }
while (gcstate() == "decommit") { gcslice(1); }
assertEq(gcstate(), "none");
while (gcstate() == "Finalize") { gcslice(1); }
while (gcstate() == "Decommit") { gcslice(1); }
assertEq(gcstate(), "NotActive");
// Incremental GC in multiple slices: if marking takes more than one slice,
// we yield before we start sweeping.
gczeal(0);
gcslice(1);
assertEq(gcstate(), "mark");
assertEq(gcstate(), "Mark");
gcslice(1000000);
assertEq(gcstate(), "mark");
assertEq(gcstate(), "Mark");
gcslice(1000000);
while (gcstate() == "finalize") { gcslice(1); }
while (gcstate() == "decommit") { gcslice(1); }
assertEq(gcstate(), "none");
while (gcstate() == "Finalize") { gcslice(1); }
while (gcstate() == "Decommit") { gcslice(1); }
assertEq(gcstate(), "NotActive");
// Zeal mode 8: Incremental GC in two main slices:
// 1) mark roots
@ -33,11 +33,11 @@ assertEq(gcstate(), "none");
// *) finalize.
gczeal(8, 0);
gcslice(1);
assertEq(gcstate(), "mark");
assertEq(gcstate(), "Mark");
gcslice(1);
while (gcstate() == "finalize") { gcslice(1); }
while (gcstate() == "decommit") { gcslice(1); }
assertEq(gcstate(), "none");
while (gcstate() == "Finalize") { gcslice(1); }
while (gcstate() == "Decommit") { gcslice(1); }
assertEq(gcstate(), "NotActive");
// Zeal mode 9: Incremental GC in two main slices:
// 1) mark roots and marking
@ -45,19 +45,19 @@ assertEq(gcstate(), "none");
// *) finalize.
gczeal(9, 0);
gcslice(1);
assertEq(gcstate(), "mark");
assertEq(gcstate(), "Mark");
gcslice(1);
while (gcstate() == "finalize") { gcslice(1); }
while (gcstate() == "decommit") { gcslice(1); }
assertEq(gcstate(), "none");
while (gcstate() == "Finalize") { gcslice(1); }
while (gcstate() == "Decommit") { gcslice(1); }
assertEq(gcstate(), "NotActive");
// Zeal mode 10: Incremental GC in multiple slices (always yeilds before
// sweeping). This test uses long slices to prove that this zeal mode yields
// in sweeping, where normal IGC (above) does not.
gczeal(10, 0);
gcslice(1000000);
assertEq(gcstate(), "sweep");
assertEq(gcstate(), "Sweep");
gcslice(1000000);
while (gcstate() == "finalize") { gcslice(1); }
while (gcstate() == "decommit") { gcslice(1); }
assertEq(gcstate(), "none");
while (gcstate() == "Finalize") { gcslice(1); }
while (gcstate() == "Decommit") { gcslice(1); }
assertEq(gcstate(), "NotActive");

View File

@ -1502,11 +1502,9 @@ Simulator::exclusiveMonitorClear()
}
int
Simulator::readW(int32_t addr, SimInstruction* instr)
Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f)
{
// The regexp engine emits unaligned loads, so we don't check for them here
// like most of the other methods do.
if ((addr & 3) == 0 || !HasAlignmentFault()) {
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
return *ptr;
}
@ -1527,9 +1525,9 @@ Simulator::readW(int32_t addr, SimInstruction* instr)
}
void
Simulator::writeW(int32_t addr, int value, SimInstruction* instr)
Simulator::writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f)
{
if ((addr & 3) == 0 || !HasAlignmentFault()) {
if ((addr & 3) == 0 || (f == AllowUnaligned && !HasAlignmentFault())) {
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
*ptr = value;
return;
@ -1592,10 +1590,10 @@ Simulator::writeExW(int32_t addr, int value, SimInstruction* instr)
return 1;
int32_t old = compareExchangeRelaxed(ptr, expected, int32_t(value));
return old != expected;
} else {
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
uint16_t
@ -1607,6 +1605,15 @@ Simulator::readHU(int32_t addr, SimInstruction* instr)
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
// See comments in readW.
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
char* ptr = reinterpret_cast<char*>(addr);
uint16_t value;
memcpy(&value, ptr, sizeof(value));
return value;
}
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
return 0;
@ -1619,6 +1626,15 @@ Simulator::readH(int32_t addr, SimInstruction* instr)
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
return *ptr;
}
// See comments in readW.
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
char* ptr = reinterpret_cast<char*>(addr);
int16_t value;
memcpy(&value, ptr, sizeof(value));
return value;
}
printf("Unaligned signed halfword read at 0x%08x\n", addr);
MOZ_CRASH();
return 0;
@ -1630,10 +1646,18 @@ Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr)
if ((addr & 1) == 0 || !HasAlignmentFault()) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
*ptr = value;
} else {
printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
return;
}
// See the comments above in readW.
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
char* ptr = reinterpret_cast<char*>(addr);
memcpy(ptr, &value, sizeof(value));
return;
}
printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
void
@ -1642,10 +1666,18 @@ Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr)
if ((addr & 1) == 0 || !HasAlignmentFault()) {
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
*ptr = value;
} else {
printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
return;
}
// See the comments above in readW.
if (wasm::IsPCInWasmCode(reinterpret_cast<void *>(get_pc()))) {
char* ptr = reinterpret_cast<char*>(addr);
memcpy(ptr, &value, sizeof(value));
return;
}
printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
uint16_t
@ -3194,9 +3226,9 @@ Simulator::decodeType2(SimInstruction* instr)
}
} else {
if (instr->hasL())
set_register(rd, readW(addr, instr));
set_register(rd, readW(addr, instr, AllowUnaligned));
else
writeW(addr, get_register(rd), instr);
writeW(addr, get_register(rd), instr, AllowUnaligned);
}
}
@ -3461,9 +3493,9 @@ Simulator::decodeType3(SimInstruction* instr)
}
} else {
if (instr->hasL())
set_register(rd, readW(addr, instr));
set_register(rd, readW(addr, instr, AllowUnaligned));
else
writeW(addr, get_register(rd), instr);
writeW(addr, get_register(rd), instr, AllowUnaligned);
}
}
@ -4288,8 +4320,10 @@ Simulator::decodeSpecialCondition(SimInstruction* instr)
while (r < regs) {
uint32_t data[2];
get_d_register(Vd + r, data);
writeW(address, data[0], instr);
writeW(address + 4, data[1], instr);
// TODO: We should AllowUnaligned here only if the alignment attribute of
// the instruction calls for default alignment.
writeW(address, data[0], instr, AllowUnaligned);
writeW(address + 4, data[1], instr, AllowUnaligned);
address += 8;
r++;
}
@ -4327,8 +4361,10 @@ Simulator::decodeSpecialCondition(SimInstruction* instr)
int r = 0;
while (r < regs) {
uint32_t data[2];
data[0] = readW(address, instr);
data[1] = readW(address + 4, instr);
// TODO: We should AllowUnaligned here only if the alignment attribute of
// the instruction calls for default alignment.
data[0] = readW(address, instr, AllowUnaligned);
data[1] = readW(address + 4, instr, AllowUnaligned);
set_d_register(Vd + r, data);
address += 8;
r++;

View File

@ -204,6 +204,20 @@ class Simulator
end_sim_pc = -2
};
// ForbidUnaligned means "always fault on unaligned access".
//
// AllowUnaligned means "allow the unaligned access if other conditions are
// met". The "other conditions" vary with the instruction: For all
// instructions the base condition is !HasAlignmentFault(), ie, the chip is
// configured to allow unaligned accesses. For instructions like VLD1
// there is an additional constraint that the alignment attribute in the
// instruction must be set to "default alignment".
enum UnalignedPolicy {
ForbidUnaligned,
AllowUnaligned
};
bool init();
// Checks if the current instruction should be executed based on its
@ -261,8 +275,8 @@ class Simulator
inline uint16_t readExHU(int32_t addr, SimInstruction* instr);
inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr);
inline int readW(int32_t addr, SimInstruction* instr);
inline void writeW(int32_t addr, int value, SimInstruction* instr);
inline int readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f = ForbidUnaligned);
inline void writeW(int32_t addr, int value, SimInstruction* instr, UnalignedPolicy f = ForbidUnaligned);
inline int readExW(int32_t addr, SimInstruction* instr);
inline int writeExW(int32_t addr, int value, SimInstruction* instr);

View File

@ -85,6 +85,7 @@ static constexpr Register ABINonArgReturnReg1 = { Registers::invalid_reg };
static constexpr Register WasmTableCallPtrReg = { Registers::invalid_reg };
static constexpr Register WasmTableCallSigReg = { Registers::invalid_reg };
static constexpr Register WasmTlsReg = { Registers::invalid_reg };
static constexpr uint32_t ABIStackAlignment = 4;
static constexpr uint32_t CodeAlignment = 4;

View File

@ -44,6 +44,7 @@ UNIFIED_SOURCES += [
'testGCExactRooting.cpp',
'testGCFinalizeCallback.cpp',
'testGCHeapPostBarriers.cpp',
'testGCHooks.cpp',
'testGCMarking.cpp',
'testGCOutOfMemory.cpp',
'testGCStoreBufferRemoval.cpp',

View File

@ -103,7 +103,7 @@ BEGIN_TEST(testGCFinalizeCallback)
JS::PrepareForFullGC(cx);
js::SliceBudget budget(js::WorkBudget(1));
cx->gc.startDebugGC(GC_NORMAL, budget);
CHECK(cx->gc.state() == js::gc::MARK);
CHECK(cx->gc.state() == js::gc::State::Mark);
CHECK(cx->gc.isFullGc());
JS::RootedObject global4(cx, createTestGlobal());

View File

@ -0,0 +1,36 @@
/* 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/. */
#include "mozilla/UniquePtr.h"
#include "js/GCAPI.h"
#include "jsapi-tests/tests.h"
static unsigned gSliceCallbackCount = 0;
static void
NonIncrementalGCSliceCallback(JSContext* cx, JS::GCProgress progress, const JS::GCDescription& desc)
{
++gSliceCallbackCount;
MOZ_RELEASE_ASSERT(progress == JS::GC_CYCLE_BEGIN || progress == JS::GC_CYCLE_END);
MOZ_RELEASE_ASSERT(desc.isCompartment_ == false);
MOZ_RELEASE_ASSERT(desc.invocationKind_ == GC_NORMAL);
MOZ_RELEASE_ASSERT(desc.reason_ == JS::gcreason::API);
if (progress == JS::GC_CYCLE_END) {
mozilla::UniquePtr<char16_t> summary(desc.formatSummaryMessage(cx));
mozilla::UniquePtr<char16_t> message(desc.formatSliceMessage(cx));
mozilla::UniquePtr<char16_t> json(desc.formatJSON(cx, 0));
}
}
BEGIN_TEST(testGCSliceCallback)
{
JS::SetGCSliceCallback(cx, NonIncrementalGCSliceCallback);
JS_GC(cx);
JS::SetGCSliceCallback(cx, nullptr);
CHECK(gSliceCallbackCount == 2);
return true;
}
END_TEST(testGCSliceCallback)

View File

@ -53,46 +53,49 @@
* The collector proceeds through the following states, the current state being
* held in JSRuntime::gcIncrementalState:
*
* - MARK_ROOTS - marks the stack and other roots
* - MARK - incrementally marks reachable things
* - SWEEP - sweeps zones in groups and continues marking unswept zones
* - MarkRoots - marks the stack and other roots
* - Mark - incrementally marks reachable things
* - Sweep - sweeps zones in groups and continues marking unswept zones
* - Finalize - performs background finalization, concurrent with mutator
* - Compact - incrementally compacts by zone
* - Decommit - performs background decommit and chunk removal
*
* The MARK_ROOTS activity always takes place in the first slice. The next two
* The MarkRoots activity always takes place in the first slice. The next two
* states can take place over one or more slices.
*
* In other words an incremental collection proceeds like this:
*
* Slice 1: MARK_ROOTS: Roots pushed onto the mark stack.
* MARK: The mark stack is processed by popping an element,
* Slice 1: MarkRoots: Roots pushed onto the mark stack.
* Mark: The mark stack is processed by popping an element,
* marking it, and pushing its children.
*
* ... JS code runs ...
*
* Slice 2: MARK: More mark stack processing.
* Slice 2: Mark: More mark stack processing.
*
* ... JS code runs ...
*
* Slice n-1: MARK: More mark stack processing.
* Slice n-1: Mark: More mark stack processing.
*
* ... JS code runs ...
*
* Slice n: MARK: Mark stack is completely drained.
* SWEEP: Select first group of zones to sweep and sweep them.
* Slice n: Mark: Mark stack is completely drained.
* Sweep: Select first group of zones to sweep and sweep them.
*
* ... JS code runs ...
*
* Slice n+1: SWEEP: Mark objects in unswept zones that were newly
* Slice n+1: Sweep: Mark objects in unswept zones that were newly
* identified as alive (see below). Then sweep more zone
* groups.
*
* ... JS code runs ...
*
* Slice n+2: SWEEP: Mark objects in unswept zones that were newly
* Slice n+2: Sweep: Mark objects in unswept zones that were newly
* identified as alive. Then sweep more zone groups.
*
* ... JS code runs ...
*
* Slice m: SWEEP: Sweeping is finished, and background sweeping
* Slice m: Sweep: Sweeping is finished, and background sweeping
* started on the helper thread.
*
* ... JS code runs, remaining sweeping done on background thread ...
@ -141,7 +144,7 @@
*
* The order of sweeping is restricted by cross compartment pointers - for
* example say that object |a| from zone A points to object |b| in zone B and
* neither object was marked when we transitioned to the SWEEP phase. Imagine we
* neither object was marked when we transitioned to the Sweep phase. Imagine we
* sweep B first and then return to the mutator. It's possible that the mutator
* could cause |a| to become alive through a read barrier (perhaps it was a
* shape that was accessed via a shape table). Then we would need to mark |b|,
@ -822,7 +825,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) :
#ifdef DEBUG
disableStrictProxyCheckingCount(0),
#endif
incrementalState(gc::NO_INCREMENTAL),
incrementalState(gc::State::NotActive),
lastMarkSlice(false),
sweepOnBackgroundThread(false),
foundBlackGrayEdges(false),
@ -4176,7 +4179,7 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
/* Re-do all the marking, but non-incrementally. */
js::gc::State state = gc->incrementalState;
gc->incrementalState = MARK_ROOTS;
gc->incrementalState = State::MarkRoots;
{
gcstats::AutoPhase ap(gc->stats, gcstats::PHASE_MARK);
@ -4196,12 +4199,12 @@ js::gc::MarkingValidator::nonIncrementalMark(AutoLockForExclusiveAccess& lock)
gc->markRuntime(gcmarker, GCRuntime::MarkRuntime, lock);
gc->incrementalState = MARK;
gc->incrementalState = State::Mark;
auto unlimited = SliceBudget::unlimited();
MOZ_RELEASE_ASSERT(gc->marker.drainMarkStack(unlimited));
}
gc->incrementalState = SWEEP;
gc->incrementalState = State::Sweep;
{
gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP);
gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK);
@ -5621,10 +5624,14 @@ void
GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lock)
{
switch (incrementalState) {
case NO_INCREMENTAL:
case State::NotActive:
return;
case MARK: {
case State::MarkRoots:
MOZ_CRASH("resetIncrementalGC did not expect MarkRoots state");
break;
case State::Mark: {
/* Cancel any ongoing marking. */
marker.reset();
marker.stop();
@ -5641,14 +5648,14 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
blocksToFreeAfterSweeping.freeAll();
incrementalState = NO_INCREMENTAL;
incrementalState = State::NotActive;
MOZ_ASSERT(!marker.shouldCheckCompartments());
break;
}
case SWEEP: {
case State::Sweep: {
marker.reset();
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
@ -5673,7 +5680,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
break;
}
case FINALIZE: {
case State::Finalize: {
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
rt->gc.waitBackgroundSweepOrAllocEnd();
@ -5690,7 +5697,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
break;
}
case COMPACT: {
case State::Compact: {
bool wasCompacting = isCompacting;
isCompacting = true;
@ -5704,14 +5711,11 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
break;
}
case DECOMMIT: {
case State::Decommit: {
auto unlimited = SliceBudget::unlimited();
incrementalCollectSlice(unlimited, JS::gcreason::RESET, lock);
break;
}
default:
MOZ_CRASH("Invalid incremental GC state");
}
stats.reset(reason);
@ -5724,7 +5728,7 @@ GCRuntime::resetIncrementalGC(const char* reason, AutoLockForExclusiveAccess& lo
MOZ_ASSERT(!zone->isOnList());
}
MOZ_ASSERT(zonesToMaybeCompact.isEmpty());
MOZ_ASSERT(incrementalState == NO_INCREMENTAL);
MOZ_ASSERT(incrementalState == State::NotActive);
#endif
}
@ -5843,33 +5847,33 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
}
switch (incrementalState) {
case NO_INCREMENTAL:
case State::NotActive:
initialReason = reason;
cleanUpEverything = ShouldCleanUpEverything(reason, invocationKind);
isCompacting = shouldCompact();
lastMarkSlice = false;
incrementalState = MARK_ROOTS;
incrementalState = State::MarkRoots;
MOZ_FALLTHROUGH;
case MARK_ROOTS:
case State::MarkRoots:
if (!beginMarkPhase(reason, lock)) {
incrementalState = NO_INCREMENTAL;
incrementalState = State::NotActive;
return;
}
if (!destroyingRuntime)
pushZealSelectedObjects();
incrementalState = MARK;
incrementalState = State::Mark;
if (isIncremental && useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish))
break;
MOZ_FALLTHROUGH;
case MARK:
case State::Mark:
AutoGCRooter::traceAllWrappers(&marker);
/* If we needed delayed marking for gray roots, then collect until done. */
@ -5884,19 +5888,19 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
MOZ_ASSERT(marker.isDrained());
if (!lastMarkSlice && isIncremental && useZeal &&
((initialState == MARK && !hasZealMode(ZealMode::IncrementalRootsThenFinish)) ||
((initialState == State::Mark && !hasZealMode(ZealMode::IncrementalRootsThenFinish)) ||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish)))
{
/*
* Yield with the aim of starting the sweep in the next
* slice. We will need to mark anything new on the stack
* when we resume, so we stay in MARK state.
* when we resume, so we stay in Mark state.
*/
lastMarkSlice = true;
break;
}
incrementalState = SWEEP;
incrementalState = State::Sweep;
/*
* This runs to completion, but we don't continue if the budget is
@ -5915,13 +5919,13 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
MOZ_FALLTHROUGH;
case SWEEP:
case State::Sweep:
if (sweepPhase(budget, lock) == NotFinished)
break;
endSweepPhase(destroyingRuntime, lock);
incrementalState = FINALIZE;
incrementalState = State::Finalize;
/* Yield before compacting since it is not incremental. */
if (isCompacting && isIncremental)
@ -5929,7 +5933,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
MOZ_FALLTHROUGH;
case FINALIZE:
case State::Finalize:
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
@ -5955,11 +5959,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
}
MOZ_ASSERT(!startedCompacting);
incrementalState = COMPACT;
incrementalState = State::Compact;
MOZ_FALLTHROUGH;
case COMPACT:
case State::Compact:
if (isCompacting) {
if (!startedCompacting)
beginCompactPhase();
@ -5971,11 +5975,11 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
}
startDecommit();
incrementalState = DECOMMIT;
incrementalState = State::Decommit;
MOZ_FALLTHROUGH;
case DECOMMIT:
case State::Decommit:
{
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
@ -5987,11 +5991,8 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
}
finishCollection(reason);
incrementalState = NO_INCREMENTAL;
incrementalState = State::NotActive;
break;
default:
MOZ_CRASH("unexpected GC incrementalState");
}
}
@ -6154,7 +6155,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
}
/* The GC was reset, so we need a do-over. */
if (prevState != NO_INCREMENTAL && !isIncrementalGCInProgress())
if (prevState != State::NotActive && !isIncrementalGCInProgress())
return true;
TraceMajorGCStart();
@ -6361,7 +6362,7 @@ GCRuntime::finishGC(JS::gcreason::Reason reason)
// compacting phase if we need to finish an ongoing incremental GC
// non-incrementally to avoid janking the browser.
if (!IsOOMReason(initialReason)) {
if (incrementalState == COMPACT) {
if (incrementalState == State::Compact) {
abortGC();
return;
}
@ -6799,8 +6800,8 @@ GCRuntime::runDebugGC()
* or compact phases.
*/
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
if ((initialState == MARK && incrementalState == SWEEP) ||
(initialState == SWEEP && incrementalState == COMPACT))
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
(initialState == State::Sweep && incrementalState == State::Compact))
{
incrementalLimit = zealFrequency / 2;
}
@ -7313,7 +7314,7 @@ JS::IsIncrementalGCInProgress(JSContext* cx)
JS_PUBLIC_API(bool)
JS::IsIncrementalBarrierNeeded(JSContext* cx)
{
return cx->gc.state() == gc::MARK && !cx->isHeapBusy();
return cx->gc.state() == gc::State::Mark && !cx->isHeapBusy();
}
struct IncrementalReferenceBarrierFunctor {
@ -7596,18 +7597,12 @@ NewMemoryInfoObject(JSContext* cx)
const char*
StateName(State state)
{
static const char* names[] = {
"None",
"MarkRoots",
"Mark",
"Sweep",
"Finalize",
"Compact",
"Decommit"
};
MOZ_ASSERT(ArrayLength(names) == NUM_STATES);
MOZ_ASSERT(state < NUM_STATES);
return names[state];
switch(state) {
#define MAKE_CASE(name) case State::name: return #name;
GCSTATES(MAKE_CASE)
#undef MAKE_CASE
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("invalide gc::State enum value");
}
void

View File

@ -43,16 +43,18 @@ namespace gc {
struct FinalizePhase;
enum State {
NO_INCREMENTAL,
MARK_ROOTS,
MARK,
SWEEP,
FINALIZE,
COMPACT,
DECOMMIT,
NUM_STATES
#define GCSTATES(D) \
D(NotActive) \
D(MarkRoots) \
D(Mark) \
D(Sweep) \
D(Finalize) \
D(Compact) \
D(Decommit)
enum class State {
#define MAKE_STATE(name) name,
GCSTATES(MAKE_STATE)
#undef MAKE_STATE
};
/*

View File

@ -528,6 +528,7 @@ dnl Android libstdc++, placed here so it can use MOZ_ARCH
dnl computed above.
dnl ========================================================
MOZ_ANDROID_CPU_ARCH
MOZ_ANDROID_STLPORT
dnl ========================================================

View File

@ -0,0 +1,25 @@
var BUGNUMBER = 1287520;
var summary = 'Array.prototype.concat should check HasProperty everytime for non-dense array';
print(BUGNUMBER + ": " + summary);
var a = [1, 2, 3];
a.constructor = {
[Symbol.species]: function(...args) {
var p = new Proxy(new Array(...args), {
defineProperty(target, propertyKey, receiver) {
if (propertyKey === "0") delete a[1];
return Reflect.defineProperty(target, propertyKey, receiver);
}
});
return p;
}
};
var p = a.concat();
assertEq(0 in p, true);
assertEq(1 in p, false);
assertEq(2 in p, true);
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,71 @@
var BUGNUMBER = 1280046;
var summary = "ignoreCase match should perform Canonicalize both on input and pattern.";
print(BUGNUMBER + ": " + summary);
// Each element [code1, upper, code2] satisfies the following condition:
// ToUpperCase(code1) == upper
// ToUpperCase(code2) == upper
var pairs =
[
// U+00B5: MICRO SIGN
// U+039C: GREEK CAPITAL LETTER MU
// U+03BC: GREEK SMALL LETTER MU
["\u00B5", "\u039C", "\u03BC"],
// U+0345: COMBINING GREEK YPOGEGRAMMENI
// U+0399: GREEK CAPITAL LETTER IOTA
// U+03B9: GREEK SMALL LETTER IOTA
["\u0345", "\u0399", "\u03B9"],
// U+03C2: GREEK SMALL LETTER FINAL SIGMA
// U+03A3: GREEK CAPITAL LETTER SIGMA
// U+03C3: GREEK SMALL LETTER SIGMA
["\u03C2", "\u03A3", "\u03C3"],
// U+03D0: GREEK BETA SYMBOL
// U+0392: GREEK CAPITAL LETTER BETA
// U+03B2: GREEK SMALL LETTER BETA
["\u03D0", "\u0392", "\u03B2"],
// U+03D1: GREEK THETA SYMBOL
// U+0398: GREEK CAPITAL LETTER THETA
// U+03B8: GREEK SMALL LETTER THETA
["\u03D1", "\u0398", "\u03B8"],
// U+03D5: GREEK PHI SYMBOL
// U+03A6: GREEK CAPITAL LETTER PHI
// U+03C6: GREEK SMALL LETTER PHI
["\u03D5", "\u03A6", "\u03C6"],
// U+03D6: GREEK PI SYMBOL
// U+03A0: GREEK CAPITAL LETTER PI
// U+03C0: GREEK SMALL LETTER PI
["\u03D6", "\u03A0", "\u03C0"],
// U+03F0: GREEK KAPPA SYMBOL
// U+039A: GREEK CAPITAL LETTER KAPPA
// U+03BA: GREEK SMALL LETTER KAPPA
["\u03F0", "\u039A", "\u03BA"],
// U+03F1: GREEK RHO SYMBOL
// U+03A1: GREEK CAPITAL LETTER RHO
// U+03C1: GREEK SMALL LETTER RHO
["\u03F1", "\u03A1", "\u03C1"],
// U+03F5: GREEK LUNATE EPSILON SYMBOL
// U+0395: GREEK CAPITAL LETTER EPSILON
// U+03B5: GREEK SMALL LETTER EPSILON
["\u03F5", "\u0395", "\u03B5"],
// U+1E9B: LATIN SMALL LETTER LONG S WITH DOT ABOVE
// U+1E60: LATIN CAPITAL LETTER S WITH DOT ABOVE
// U+1E61: LATIN SMALL LETTER S WITH DOT ABOVE
["\u1E9B", "\u1E60", "\u1E61"],
// U+1FBE: GREEK PROSGEGRAMMENI
// U+0399: GREEK CAPITAL LETTER IOTA
// U+03B9: GREEK SMALL LETTER IOTA
["\u1FBE", "\u0399", "\u03B9"],
];
for (var [code1, upper, code2] of pairs) {
assertEq(new RegExp(code1, "i").test(code2), true);
assertEq(new RegExp(code1, "i").test(upper), true);
assertEq(new RegExp(upper, "i").test(code1), true);
assertEq(new RegExp(upper, "i").test(code2), true);
assertEq(new RegExp(code2, "i").test(code1), true);
assertEq(new RegExp(code2, "i").test(upper), true);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,18 @@
var BUGNUMBER = 1287524;
var summary = 'RegExp.prototype[@@replace] should not use optimized path if RegExp.prototype.unicode is modified.';
print(BUGNUMBER + ": " + summary);
Object.defineProperty(RegExp.prototype, "unicode", {
get() {
RegExp.prototype.exec = () => null;
}
});
var rx = RegExp("a", "g");
var s = "abba";
var r = rx[Symbol.replace](s, "c");
assertEq(r, "abba");
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,14 @@
var BUGNUMBER = 1287525;
var summary = "RegExp.prototype[@@split] shouldn't use optimized path if limit is not number.";
print(BUGNUMBER + ": " + summary);
var rx = /a/;
var r = rx[Symbol.split]("abba", {valueOf() {
RegExp.prototype.exec = () => null;
return 100;
}});
assertEq(r.length, 1);
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -0,0 +1,19 @@
var BUGNUMBER = 1287525;
var summary = 'String.prototype.split should call ToUint32(limit) before ToString(separator).';
print(BUGNUMBER + ": " + summary);
var accessed = false;
var rx = /a/;
Object.defineProperty(rx, Symbol.match, {
get() {
accessed = true;
}
});
rx[Symbol.split]("abba");
assertEq(accessed, true);
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -2829,12 +2829,12 @@ Debugger::markIncomingCrossCompartmentEdges(JSTracer* trc)
{
JSRuntime* rt = trc->runtime();
gc::State state = rt->gc.state();
MOZ_ASSERT(state == gc::MARK_ROOTS || state == gc::COMPACT);
MOZ_ASSERT(state == gc::State::MarkRoots || state == gc::State::Compact);
for (Debugger* dbg : rt->debuggerList) {
Zone* zone = MaybeForwarded(dbg->object.get())->zone();
if ((state == gc::MARK_ROOTS && !zone->isCollecting()) ||
(state == gc::COMPACT && !zone->isGCCompacting()))
if ((state == gc::State::MarkRoots && !zone->isCollecting()) ||
(state == gc::State::Compact && !zone->isGCCompacting()))
{
dbg->markCrossCompartmentEdges(trc);
}

View File

@ -326,6 +326,7 @@ class RegExpCompartment
* The shape of RegExp.prototype object that satisfies following:
* * RegExp.prototype.global getter is not modified
* * RegExp.prototype.sticky getter is not modified
* * RegExp.prototype.unicode getter is not modified
* * RegExp.prototype.exec is an own data property
* * RegExp.prototype[@@match] is an own data property
* * RegExp.prototype[@@search] is an own data property

View File

@ -1380,8 +1380,15 @@ JSStructuredCloneWriter::transferOwnership()
}
MOZ_ASSERT(point <= out.rawBuffer() + out.count());
MOZ_ASSERT_IF(point < out.rawBuffer() + out.count(),
uint32_t(LittleEndian::readUint64(point) >> 32) < SCTAG_TRANSFER_MAP_HEADER);
#if DEBUG
// Make sure there aren't any more transfer map entries after the expected
// number we read out.
if (point < out.rawBuffer() + out.count()) {
uint32_t tag, data;
SCInput::getPair(point, &tag, &data);
MOZ_ASSERT(tag < SCTAG_TRANSFER_MAP_HEADER || tag >= SCTAG_TRANSFER_MAP_END_OF_BUILTIN_TYPES);
}
#endif
return true;
}

View File

@ -772,6 +772,322 @@ const uint8_t unicode::index2[] = {
5, 5, 5, 0, 0, 0,
};
const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {
{0, 0, 0},
{32, 0, 0},
{32, 232, 0},
{32, 300, 0},
{0, 200, 0},
{0, 268, 0},
{0, 775, 0},
{1, 0, 0},
{65336, 0, 0},
{65415, 0, 0},
{65268, 0, 0},
{210, 0, 0},
{206, 0, 0},
{205, 0, 0},
{79, 0, 0},
{202, 0, 0},
{203, 0, 0},
{207, 0, 0},
{211, 0, 0},
{209, 0, 0},
{213, 0, 0},
{214, 0, 0},
{218, 0, 0},
{217, 0, 0},
{219, 0, 0},
{1, 2, 0},
{0, 1, 0},
{65535, 0, 0},
{65439, 0, 0},
{65480, 0, 0},
{65406, 0, 0},
{10795, 0, 0},
{65373, 0, 0},
{10792, 0, 0},
{65341, 0, 0},
{69, 0, 0},
{71, 0, 0},
{0, 116, 7289},
{38, 0, 0},
{37, 0, 0},
{64, 0, 0},
{63, 0, 0},
{32, 62, 0},
{32, 96, 0},
{32, 57, 0},
{65452, 32, 7205},
{32, 86, 0},
{64793, 32, 0},
{32, 54, 0},
{32, 80, 0},
{31, 32, 0},
{32, 47, 0},
{0, 30, 0},
{0, 64, 0},
{0, 25, 0},
{65420, 0, 7173},
{0, 54, 0},
{64761, 0, 0},
{0, 22, 0},
{0, 48, 0},
{0, 15, 0},
{8, 0, 0},
{65506, 0, 0},
{65511, 0, 0},
{65521, 0, 0},
{65514, 0, 0},
{65482, 0, 0},
{65488, 0, 0},
{65472, 0, 0},
{65529, 0, 0},
{80, 0, 0},
{15, 0, 0},
{48, 0, 0},
{7264, 0, 0},
{1, 59, 0},
{0, 58, 0},
{65478, 0, 0},
{65528, 0, 0},
{65462, 0, 0},
{65527, 0, 0},
{58247, 58363, 0},
{65450, 0, 0},
{65436, 0, 0},
{65424, 0, 0},
{65408, 0, 0},
{65410, 0, 0},
{28, 0, 0},
{16, 0, 0},
{26, 0, 0},
{54793, 0, 0},
{61722, 0, 0},
{54809, 0, 0},
{54756, 0, 0},
{54787, 0, 0},
{54753, 0, 0},
{54754, 0, 0},
{54721, 0, 0},
{30204, 0, 0},
{23256, 0, 0},
{23228, 0, 0},
};
const uint8_t unicode::codepoints_with_same_upper_index1[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, 14,
15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, 23, 21, 24, 25,
26, 27, 0, 0, 0, 0, 28, 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 34, 21, 35,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36,
37, 0, 38, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0,
};
const uint8_t unicode::codepoints_with_same_upper_index2[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8,
7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7,
0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 9, 7,
0, 7, 0, 7, 0, 10, 0, 11, 7, 0, 7, 0, 12, 7, 0, 13, 13, 7,
0, 0, 14, 15, 16, 7, 0, 13, 17, 0, 18, 19, 7, 0, 0, 0, 18, 20,
0, 21, 7, 0, 7, 0, 7, 0, 22, 7, 0, 22, 0, 0, 7, 0, 22, 7,
0, 23, 23, 7, 0, 7, 0, 24, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0,
0, 0, 25, 26, 27, 25, 26, 27, 25, 26, 27, 7, 0, 7, 0, 7, 0, 7,
0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 25, 26, 27, 7, 0, 28, 29,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 30, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 31, 7, 0, 32, 33, 0,
0, 7, 0, 34, 35, 36, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 39, 39, 39, 0, 40, 0, 41, 41,
0, 1, 42, 1, 1, 43, 1, 1, 44, 45, 46, 1, 47, 1, 1, 1, 48, 49,
0, 50, 1, 1, 51, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 52, 0,
0, 53, 0, 0, 54, 55, 56, 0, 57, 0, 0, 0, 58, 59, 26, 27, 0, 0,
60, 0, 0, 0, 0, 0, 0, 0, 0, 61, 62, 63, 0, 0, 0, 64, 65, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 66, 67, 0, 0, 0, 68, 0, 7, 0, 69, 7, 0,
0, 30, 30, 30, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 71, 7,
0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
72, 72, 72, 72, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 0, 73, 0, 0, 0, 0, 0, 73, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
74, 75, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
0, 0, 0, 0, 0, 76, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77,
77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77,
0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0,
0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 77, 0, 77, 0, 77, 0, 77, 0, 0, 0, 0, 0, 0,
0, 0, 77, 77, 77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77,
77, 77, 77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77,
77, 77, 77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 77, 77, 77, 77,
77, 77, 0, 0, 0, 0, 0, 0, 0, 0, 77, 77, 78, 78, 79, 0, 80, 0,
0, 0, 0, 0, 0, 0, 0, 0, 81, 81, 81, 81, 79, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 77, 77, 82, 82, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 77, 77, 83, 83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 84, 84, 85, 85, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 87,
87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 89, 90, 91, 0,
0, 7, 0, 7, 0, 7, 0, 92, 93, 94, 95, 0, 7, 0, 0, 7, 0, 0,
0, 0, 0, 0, 0, 0, 96, 96, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7,
0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7,
0, 97, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0, 98,
0, 0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 99, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0,
};
const FoldingInfo unicode::js_foldinfo[] = {
{0, 0, 0, 0},
{32, 0, 0, 0},

View File

@ -279,6 +279,76 @@ ToLowerCaseNonBMPTrail(char16_t lead, char16_t trail)
return trail;
}
/*
* For a codepoint C, CodepointsWithSameUpperCaseInfo stores three offsets
* from C to up to three codepoints with same uppercase (no codepoint in
* UnicodeData.txt has more than three such codepoints).
*
* To illustrate, consider the codepoint U+0399 GREEK CAPITAL LETTER IOTA, the
* uppercased form of these three codepoints:
*
* U+03B9 GREEK SMALL LETTER IOTA
* U+1FBE GREEK PROSGEGRAMMENI
* U+0345 COMBINING GREEK YPOGEGRAMMENI
*
* For the CodepointsWithSameUpperCaseInfo corresponding to this codepoint,
* delta{1,2,3} are 16-bit modular deltas from 0x0399 to each respective
* codepoint:
* uint16_t(0x03B9 - 0x0399),
* uint16_t(0x1FBE - 0x0399),
* uint16_t(0x0345 - 0x0399)
* in an unimportant order.
*
* If there are fewer than three other codepoints, some fields are zero.
* Consider the codepoint U+03B9 above, the other two codepoints U+1FBE and
* U+0345 have same uppercase (U+0399 is not). For the
* CodepointsWithSameUpperCaseInfo corresponding to this codepoint,
* delta{1,2,3} are:
* uint16_t(0x1FBE - 0x03B9),
* uint16_t(0x0345 - 0x03B9),
* uint16_t(0)
* in an unimportant order.
*
* Because multiple codepoints map to a single CodepointsWithSameUpperCaseInfo,
* a CodepointsWithSameUpperCaseInfo and its delta{1,2,3} have no meaning
* standing alone: they have meaning only with respect to a codepoint mapping
* to that CodepointsWithSameUpperCaseInfo.
*/
class CodepointsWithSameUpperCaseInfo
{
public:
uint16_t delta1;
uint16_t delta2;
uint16_t delta3;
};
extern const uint8_t codepoints_with_same_upper_index1[];
extern const uint8_t codepoints_with_same_upper_index2[];
extern const CodepointsWithSameUpperCaseInfo js_codepoints_with_same_upper_info[];
class CodepointsWithSameUpperCase
{
const CodepointsWithSameUpperCaseInfo& info_;
const char16_t code_;
static const CodepointsWithSameUpperCaseInfo& computeInfo(char16_t code) {
const size_t shift = 6;
size_t index = codepoints_with_same_upper_index1[code >> shift];
index = codepoints_with_same_upper_index2[(index << shift) + (code & ((1 << shift) - 1))];
return js_codepoints_with_same_upper_info[index];
}
public:
explicit CodepointsWithSameUpperCase(char16_t code)
: info_(computeInfo(code)),
code_(code)
{}
char16_t other1() const { return uint16_t(code_) + info_.delta1; }
char16_t other2() const { return uint16_t(code_) + info_.delta2; }
char16_t other3() const { return uint16_t(code_) + info_.delta3; }
};
class FoldingInfo {
public:
uint16_t folding;

View File

@ -145,6 +145,11 @@ def generate_unicode_stuff(unicode_data, case_folding,
table = [dummy]
cache = {dummy: 0}
index = [0] * (MAX + 1)
same_upper_map = {}
same_upper_dummy = (0, 0, 0)
same_upper_table = [same_upper_dummy]
same_upper_cache = {same_upper_dummy: 0}
same_upper_index = [0] * (MAX + 1)
folding_map = {}
rev_folding_map = {}
folding_dummy = (0, 0, 0, 0)
@ -172,6 +177,11 @@ def generate_unicode_stuff(unicode_data, case_folding,
if uppercase:
upper = int(uppercase, 16)
if upper not in same_upper_map:
same_upper_map[upper] = [code]
else:
same_upper_map[upper].append(code)
else:
upper = code
@ -216,6 +226,36 @@ def generate_unicode_stuff(unicode_data, case_folding,
table.append(item)
index[code] = i
for code in range(0, MAX + 1):
entry = test_table.get(code)
if not entry:
continue
(upper, lower, name, alias) = entry
if upper not in same_upper_map:
continue
same_upper_ds = [v - code for v in same_upper_map[upper]]
assert len(same_upper_ds) <= 3
assert all([v > -65535 and v < 65535 for v in same_upper_ds])
same_upper = [v & 0xffff for v in same_upper_ds]
same_upper_0 = same_upper[0] if len(same_upper) >= 1 else 0
same_upper_1 = same_upper[1] if len(same_upper) >= 2 else 0
same_upper_2 = same_upper[2] if len(same_upper) >= 3 else 0
item = (same_upper_0, same_upper_1, same_upper_2)
i = same_upper_cache.get(item)
if i is None:
assert item not in same_upper_table
same_upper_cache[item] = i = len(same_upper_table)
same_upper_table.append(item)
same_upper_index[code] = i
for row in read_case_folding(case_folding):
code = row[0]
mapping = row[2]
@ -310,7 +350,7 @@ def generate_unicode_stuff(unicode_data, case_folding,
entry = test_table.get(code)
if entry:
upper, lower, name, alias = entry
(upper, lower, name, alias) = entry
test_mapping.write(' [' + hex(upper) + ', ' + hex(lower) + '], /* ' +
name + (' (' + alias + ')' if alias else '') + ' */\n')
else:
@ -389,6 +429,11 @@ if (typeof reportCompare === "function")
# Don't forget to update CharInfo in Unicode.cpp if you need to change this
assert shift == 5
same_upper_index1, same_upper_index2, same_upper_shift = splitbins(same_upper_index)
# Don't forget to update CharInfo in Unicode.cpp if you need to change this
assert same_upper_shift == 6
folding_index1, folding_index2, folding_shift = splitbins(folding_index)
# Don't forget to update CharInfo in Unicode.cpp if you need to change this
@ -403,6 +448,15 @@ if (typeof reportCompare === "function")
assert test == table[idx]
# verify correctness
for char in same_upper_index:
test = same_upper_table[same_upper_index[char]]
idx = same_upper_index1[char >> same_upper_shift]
idx = same_upper_index2[(idx << same_upper_shift) + (char & ((1 << same_upper_shift) - 1))]
assert test == same_upper_table[idx]
# verify correctness
for char in folding_index:
test = folding_table[folding_index[char]]
@ -497,6 +551,19 @@ if (typeof reportCompare === "function")
dump(index2, 'index2', data_file)
data_file.write('\n')
data_file.write('const CodepointsWithSameUpperCaseInfo unicode::js_codepoints_with_same_upper_info[] = {\n')
for d in same_upper_table:
data_file.write(' {')
data_file.write(', '.join((str(e) for e in d)))
data_file.write('},\n')
data_file.write('};\n')
data_file.write('\n')
dump(same_upper_index1, 'codepoints_with_same_upper_index1', data_file)
data_file.write('\n')
dump(same_upper_index2, 'codepoints_with_same_upper_index2', data_file)
data_file.write('\n')
data_file.write('const FoldingInfo unicode::js_foldinfo[] = {\n')
for d in folding_table:
data_file.write(' {')

View File

@ -50,14 +50,14 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
void
ServoRestyleManager::PostRestyleEventForLazyConstruction()
{
NS_ERROR("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented");
NS_WARNING("stylo: ServoRestyleManager::PostRestyleEventForLazyConstruction not implemented");
}
void
ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint)
{
NS_ERROR("stylo: ServoRestyleManager::RebuildAllStyleData not implemented");
NS_WARNING("stylo: ServoRestyleManager::RebuildAllStyleData not implemented");
}
void
@ -166,7 +166,7 @@ ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
// TODO: Handle all other nsRestyleHint values.
if (aHint & ~(eRestyle_Self | eRestyle_Subtree | eRestyle_LaterSiblings)) {
NS_ERROR(nsPrintfCString("stylo: Unhandled restyle hint %s",
NS_WARNING(nsPrintfCString("stylo: Unhandled restyle hint %s",
RestyleManagerBase::RestyleHintToString(aHint).get()).get());
}
}
@ -226,14 +226,14 @@ void
ServoRestyleManager::RestyleForInsertOrChange(Element* aContainer,
nsIContent* aChild)
{
NS_ERROR("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented");
NS_WARNING("stylo: ServoRestyleManager::RestyleForInsertOrChange not implemented");
}
void
ServoRestyleManager::RestyleForAppend(Element* aContainer,
nsIContent* aFirstNewContent)
{
NS_ERROR("stylo: ServoRestyleManager::RestyleForAppend not implemented");
NS_WARNING("stylo: ServoRestyleManager::RestyleForAppend not implemented");
}
void
@ -241,7 +241,7 @@ ServoRestyleManager::RestyleForRemove(Element* aContainer,
nsIContent* aOldChild,
nsIContent* aFollowingSibling)
{
NS_ERROR("stylo: ServoRestyleManager::RestyleForRemove not implemented");
NS_WARNING("stylo: ServoRestyleManager::RestyleForRemove not implemented");
}
nsresult
@ -296,18 +296,10 @@ ServoRestyleManager::AttributeWillChange(Element* aElement,
snapshot->AddAttrs(aElement);
}
void
ServoRestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
nsIAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue)
{
NS_ERROR("stylo: ServoRestyleManager::AttributeChanged not implemented");
}
nsresult
ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
{
NS_ERROR("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
NS_WARNING("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
return NS_OK;
}

View File

@ -62,9 +62,12 @@ public:
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aNewValue);
// XXXbholley: We should assert that the element is already snapshotted.
void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID,
nsIAtom* aAttribute, int32_t aModType,
const nsAttrValue* aOldValue);
const nsAttrValue* aOldValue) {}
nsresult ReparentStyleContext(nsIFrame* aFrame);
bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); }

View File

@ -2691,7 +2691,7 @@ nsCSSFrameConstructor::ConstructRootFrame()
// ServoStyleSets yet.
styleSet->AsGecko()->SetBindingManager(mDocument->BindingManager());
} else {
NS_ERROR("stylo: cannot get ServoStyleSheets from XBL bindings yet");
NS_WARNING("stylo: cannot get ServoStyleSheets from XBL bindings yet. See bug 1290276.");
}
// --------- BUILD VIEWPORT -----------

View File

@ -2347,7 +2347,8 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument)
}
}
} else {
NS_ERROR("stylo: nsStyleSheetService doesn't handle ServoStyleSheets yet");
NS_WARNING("stylo: Not yet checking nsStyleSheetService for Servo-backed "
"documents. See bug 1290224");
}
// Caller will handle calling EndUpdate, per contract.

View File

@ -1867,8 +1867,8 @@ nsPresContext::MediaFeatureValuesChanged(nsRestyleHint aRestyleHint,
aRestyleHint |= eRestyle_Subtree;
}
} else {
NS_ERROR("stylo: ServoStyleSets don't support responding to medium "
"changes yet");
NS_WARNING("stylo: ServoStyleSets don't support responding to medium "
"changes yet. See bug 1290228.");
}
}

View File

@ -4232,8 +4232,8 @@ PresShell::DocumentStatesChanged(nsIDocument* aDocument,
// XXXheycam ServoStyleSets don't support document state selectors,
// but these are only used in chrome documents, which we are not
// aiming to support yet.
NS_ERROR("stylo: ServoStyleSets cannot respond to document state "
"changes yet");
NS_WARNING("stylo: ServoStyleSets cannot respond to document state "
"changes yet (only matters for chrome documents). See bug 1290285.");
return;
}

View File

@ -1294,7 +1294,7 @@ Loader::PrepareSheet(StyleSheetHandle aSheet,
// XXXheycam Need to set media, title, etc. on ServoStyleSheets.
if (aSheet->IsServo()) {
NS_ERROR("stylo: should set metadata on ServoStyleSheets");
NS_WARNING("stylo: should set metadata on ServoStyleSheets. See bug 1290209.");
return;
}
@ -1976,7 +1976,7 @@ Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
}
#endif
} else {
NS_ERROR("stylo: not caching ServoStyleSheet");
NS_WARNING("stylo: Stylesheet caching not yet supported - see bug 1290218.");
}
}

View File

@ -378,7 +378,7 @@ nsRestyleHint
ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
EventStates aStateMask)
{
NS_ERROR("stylo: HasStateDependentStyle not implemented");
NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
return nsRestyleHint(0);
}
@ -388,7 +388,7 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
dom::Element* aPseudoElement,
EventStates aStateMask)
{
NS_ERROR("stylo: HasStateDependentStyle not implemented");
NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
return nsRestyleHint(0);
}

View File

@ -199,7 +199,12 @@ function nextPopupTest(panel)
if ("last" in popupTests[gTestId])
document.getElementById("popupresizer").removeAttribute("flex");
panel.openPopup();
// Prevent event loop starvation as a result of popup events being
// synchronous. See bug 1131576.
SimpleTest.executeSoon(() => {
// Non-chrome shells require focus to open a popup.
SimpleTest.waitForFocus(() => { panel.openPopup() });
});
}
}

View File

@ -5,9 +5,12 @@
#ifndef PNGLCONF_H
#define PNGLCONF_H
/* limit image dimensions (bug #251381, #591822, and #967656) */
#ifndef MOZ_PNG_MAX_DIMENSION
# define MOZ_PNG_MAX_DIMENSION 32767
/* Limit image dimensions (bug #251381, #591822, #967656, and #1283961) */
#ifndef MOZ_PNG_MAX_WIDTH
# define MOZ_PNG_MAX_WIDTH 0x7fffffffL /* Unlimited */
#endif
#ifndef MOZ_PNG_MAX_HEIGHT
# define MOZ_PNG_MAX_HEIGHT 0x7fffffffL /* Unlimited */
#endif
#define PNG_API_RULE 0
@ -23,8 +26,8 @@
#define PNG_sRGB_PROFILE_CHECKS -1
#define PNG_USER_CHUNK_CACHE_MAX 128
#define PNG_USER_CHUNK_MALLOC_MAX 4000000L
#define PNG_USER_HEIGHT_MAX MOZ_PNG_MAX_DIMENSION
#define PNG_USER_WIDTH_MAX MOZ_PNG_MAX_DIMENSION
#define PNG_USER_HEIGHT_MAX MOZ_PNG_MAX_WIDTH
#define PNG_USER_WIDTH_MAX MOZ_PNG_MAX_HEIGHT
#define PNG_WEIGHT_SHIFT 8
#define PNG_ZBUF_SIZE 8192
#define PNG_Z_DEFAULT_COMPRESSION (-1)

View File

@ -1290,6 +1290,13 @@ NS_IMETHODIMP nsHttpChannelAuthProvider::OnAuthCancelled(nsISupports *aContext,
// there are still some challenges to process, do so
nsresult rv;
// Get rid of current continuationState to avoid reusing it in
// next challenges since it is no longer relevant.
if (mProxyAuth) {
NS_IF_RELEASE(mProxyAuthContinuationState);
} else {
NS_IF_RELEASE(mAuthContinuationState);
}
nsAutoCString creds;
rv = GetCredentials(mRemainingChallenges.get(), mProxyAuth, creds);
if (NS_SUCCEEDED(rv)) {

View File

@ -47,12 +47,17 @@ class Introspection(MachCommandBase):
build_vars = util.get_build_vars(make_dir, self)
if what.endswith('.c'):
cc = 'CC'
name = 'COMPILE_CFLAGS'
else:
cc = 'CXX'
name = 'COMPILE_CXXFLAGS'
if name not in build_vars:
return
# Drop the first flag since that is the pathname of the compiler.
flags = (shell_split(build_vars[cc]) + shell_split(build_vars[name]))[1:]
print(' '.join(shell_quote(arg)
for arg in util.sanitize_cflags(shell_split(build_vars[name]))))
for arg in util.sanitize_cflags(flags)))

View File

@ -674,6 +674,11 @@ public:
return Allow();
#endif
#ifdef __NR_fadvise64_64
case __NR_fadvise64_64:
return Allow();
#endif
case __NR_fallocate:
return Allow();

View File

@ -458,10 +458,6 @@ static const char contentSandboxRules[] =
" (iokit-user-client-class \"NVDVDContextTesla\")\n"
" (iokit-user-client-class \"Gen6DVDContext\"))\n"
"\n"
"; bug 1190032\n"
" (allow file*\n"
" (home-regex \"/Library/Caches/TemporaryItems/plugtmp.*\"))\n"
"\n"
"; bug 1201935\n"
" (allow file-read*\n"
" (home-subpath \"/Library/Caches/TemporaryItems\"))\n"

View File

@ -1,7 +1,7 @@
$inherits:
from: 'tasks/builds/firefox_docker_base.yml'
task:
workerType: spidermonkey
workerType: dbg-linux64
routes:
- 'index.buildbot.branches.{{project}}.sm-plain'

View File

@ -14,3 +14,4 @@ task:
extra:
treeherder:
symbol: msan
tier: 3

View File

@ -14,3 +14,4 @@ task:
extra:
treeherder:
symbol: tsan
tier: 3

View File

@ -29,6 +29,7 @@ task:
/build/tooltool.py fetch -m manifest.tt &&
tar xvfz eslint.tar.gz &&
rm eslint.tar.gz &&
ln -s ../eslint-plugin-mozilla node_modules &&
cd ../../.. &&
tools/lint/eslint/node_modules/.bin/eslint --quiet --plugin html --ext [.js,.jsm,.jsx,.xml,.html] -f tools/lint/eslint-formatter .

View File

@ -1,8 +1,5 @@
[form-validation-reportValidity.html]
type: testharness
expected: TIMEOUT
disabled:
if debug and (os == "mac"): https://bugzilla.mozilla.org/show_bug.cgi?id=1273105
[[INPUT in TEXT status\] suffering from being too long]
expected: FAIL

View File

@ -56,6 +56,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/ExtensionContent.jsm");
Cu.import("resource://gre/modules/ExtensionManagement.jsm");
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
@ -326,7 +327,7 @@ class ProxyContext extends ExtensionContext {
function findPathInObject(obj, path) {
for (let elt of path) {
obj = obj[elt];
obj = obj[elt] || undefined;
}
return obj;
}

View File

@ -0,0 +1,285 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["ExtensionTestUtils"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Components.utils.import("resource://gre/modules/Task.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
"resource://gre/modules/Schemas.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "uuidGenerator",
"@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
/* exported ExtensionTestUtils */
let BASE_MANIFEST = Object.freeze({
"applications": Object.freeze({
"gecko": Object.freeze({
"id": "test@web.ext",
}),
}),
"manifest_version": 2,
"name": "name",
"version": "0",
});
class ExtensionWrapper {
constructor(extension, testScope) {
this.extension = extension;
this.testScope = testScope;
this.state = "uninitialized";
this.testResolve = null;
this.testDone = new Promise(resolve => { this.testResolve = resolve; });
this.messageHandler = new Map();
this.messageAwaiter = new Map();
this.messageQueue = new Set();
this.testScope.do_register_cleanup(() => {
if (this.messageQueue.size) {
let names = Array.from(this.messageQueue, ([msg]) => msg);
this.testScope.equal(JSON.stringify(names), "[]", "message queue is empty");
}
if (this.messageAwaiter.size) {
let names = Array.from(this.messageAwaiter.keys());
this.testScope.equal(JSON.stringify(names), "[]", "no tasks awaiting on messages");
}
});
/* eslint-disable mozilla/balanced-listeners */
extension.on("test-eq", (kind, pass, msg, expected, actual) => {
this.testScope.ok(pass, `${msg} - Expected: ${expected}, Actual: ${actual}`);
});
extension.on("test-log", (kind, pass, msg) => {
this.testScope.do_print(msg);
});
extension.on("test-result", (kind, pass, msg) => {
this.testScope.ok(pass, msg);
});
extension.on("test-done", (kind, pass, msg, expected, actual) => {
this.testScope.ok(pass, msg);
this.testResolve(msg);
});
extension.on("test-message", (kind, msg, ...args) => {
let handler = this.messageHandler.get(msg);
if (handler) {
handler(...args);
} else {
this.messageQueue.add([msg, ...args]);
this.checkMessages();
}
});
/* eslint-enable mozilla/balanced-listeners */
this.testScope.do_register_cleanup(() => {
if (this.state == "pending" || this.state == "running") {
this.testScope.equal(this.state, "unloaded", "Extension left running at test shutdown");
return this.unload();
} else if (extension.state == "unloading") {
this.testScope.equal(this.state, "unloaded", "Extension not fully unloaded at test shutdown");
}
});
this.testScope.do_print(`Extension loaded`);
}
startup() {
if (this.state != "uninitialized") {
throw new Error("Extension already started");
}
this.state = "pending";
return this.extension.startup().then(
result => {
this.state = "running";
return result;
},
error => {
this.state = "failed";
return Promise.reject(error);
});
}
unload() {
if (this.state != "running") {
throw new Error("Extension not running");
}
this.state = "unloading";
this.extension.shutdown();
this.state = "unloaded";
return Promise.resolve();
}
sendMessage(...args) {
this.extension.testMessage(...args);
}
awaitFinish(msg) {
return this.testDone.then(actual => {
if (msg) {
this.testScope.equal(actual, msg, "test result correct");
}
return actual;
});
}
checkMessages() {
for (let message of this.messageQueue) {
let [msg, ...args] = message;
let listener = this.messageAwaiter.get(msg);
if (listener) {
this.messageQueue.delete(message);
this.messageAwaiter.delete(msg);
listener.resolve(...args);
return;
}
}
}
checkDuplicateListeners(msg) {
if (this.messageHandler.has(msg) || this.messageAwaiter.has(msg)) {
throw new Error("only one message handler allowed");
}
}
awaitMessage(msg) {
return new Promise(resolve => {
this.checkDuplicateListeners(msg);
this.messageAwaiter.set(msg, {resolve});
this.checkMessages();
});
}
onMessage(msg, callback) {
this.checkDuplicateListeners(msg);
this.messageHandler.set(msg, callback);
}
}
var ExtensionTestUtils = {
BASE_MANIFEST,
normalizeManifest: Task.async(function* (manifest, baseManifest = BASE_MANIFEST) {
const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
yield Management.lazyInit();
let errors = [];
let context = {
url: null,
logError: error => {
errors.push(error);
},
preprocessors: {},
};
manifest = Object.assign({}, baseManifest, manifest);
let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context);
normalized.errors = errors;
return normalized;
}),
currentScope: null,
profileDir: null,
init(scope) {
this.currentScope = scope;
this.profileDir = scope.do_get_profile();
// We need to load at least one frame script into every message
// manager to ensure that the scriptable wrapper for its global gets
// created before we try to access it externally. If we don't, we
// fail sanity checks on debug builds the first time we try to
// create a wrapper, because we should never have a global without a
// cached wrapper.
Services.mm.loadFrameScript("data:text/javascript,//", true);
let tmpD = this.profileDir.clone();
tmpD.append("tmp");
tmpD.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let dirProvider = {
getFile(prop, persistent) {
persistent.value = false;
if (prop == "TmpD") {
return tmpD.clone();
}
return null;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
};
Services.dirsvc.registerProvider(dirProvider);
scope.do_register_cleanup(() => {
tmpD.remove(true);
Services.dirsvc.unregisterProvider(dirProvider);
this.currentScope = null;
});
},
addonManagerStarted: false,
startAddonManager() {
if (this.addonManagerStarted) {
return;
}
this.addonManagerStarted = true;
let appInfo = {};
Cu.import("resource://testing-common/AppInfo.jsm", appInfo);
appInfo.updateAppInfo({
ID: "xpcshell@tests.mozilla.org",
name: "XPCShell",
version: "48",
platformVersion: "48",
});
let manager = Cc["@mozilla.org/addons/integration;1"].getService(Ci.nsIObserver)
.QueryInterface(Ci.nsITimerCallback);
manager.observe(null, "addons-startup", null);
},
loadExtension(data, id = uuidGenerator.generateUUID().number) {
let extension = Extension.generate(id, data);
return new ExtensionWrapper(extension, this.currentScope);
},
};

View File

@ -19,6 +19,10 @@ EXTRA_COMPONENTS += [
'extensions-toolkit.manifest',
]
TESTING_JS_MODULES += [
'ExtensionXPCShellUtils.jsm',
]
DIRS += ['schemas']
JAR_MANIFESTS += ['jar.mn']

View File

@ -2,18 +2,12 @@
support-files =
chrome_head.js
head.js
file_download.html
file_download.txt
interruptible.sjs
file_sample.html
[test_chrome_ext_background_debug_global.html]
skip-if = (os == 'android') # android doesn't have devtools
[test_chrome_ext_background_page.html]
skip-if = (toolkit == 'android') # android doesn't have devtools
[test_chrome_ext_downloads_download.html]
[test_chrome_ext_downloads_misc.html]
[test_chrome_ext_downloads_search.html]
[test_chrome_ext_eventpage_warning.html]
[test_chrome_ext_native_messaging.html]
skip-if = os == "android" # native messaging is not supported on android

View File

@ -1,38 +0,0 @@
const TEST_DATA = "This is 31 bytes of sample data";
const TOTAL_LEN = TEST_DATA.length;
const PARTIAL_LEN = 15;
// A handler to let us systematically test pausing/resuming/canceling
// of downloads. This target represents a small text file but a simple
// GET will stall after sending part of the data, to give the test code
// a chance to pause or do other operations on an in-progress download.
// A resumed download (ie, a GET with a Range: header) will allow the
// download to complete.
function handleRequest(request, response) {
response.setHeader("Content-Type", "text/plain", false);
if (request.hasHeader("Range")) {
let start, end;
let matches = request.getHeader("Range")
.match(/^\s*bytes=(\d+)?-(\d+)?\s*$/);
if (matches != null) {
start = matches[1] ? parseInt(matches[1], 10) : 0;
end = matches[2] ? pareInt(matchs[2], 10) : (TOTAL_LEN - 1);
}
if (end == undefined || end >= TOTAL_LEN) {
response.setStatusLine(request.httpVersion, 416, "Requested Range Not Satisfiable");
response.setHeader("Content-Range", `*/${TOTAL_LEN}`, false);
response.finish();
return;
}
response.setStatusLine(request.httpVersion, 206, "Partial Content");
response.setHeader("Content-Range", `${start}-${end}/${TOTAL_LEN}`, false);
response.write(TEST_DATA.slice(start, end + 1));
} else {
response.processAsync();
response.setHeader("Content-Length", `${TOTAL_LEN}`, false);
response.write(TEST_DATA.slice(0, PARTIAL_LEN));
}
}

View File

@ -34,12 +34,9 @@ support-files =
file_privilege_escalation.html
file_ext_test_api_injection.js
file_permission_xhr.html
file_download.txt
[test_ext_extension.html]
[test_ext_inIncognitoContext_window.html]
skip-if = os == 'android' # Android does not currently support windows.
[test_ext_simple.html]
[test_ext_geturl.html]
[test_ext_background_canvas.html]
[test_ext_content_security_policy.html]
@ -50,13 +47,9 @@ skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
[test_ext_contentscript_devtools_metadata.html]
[test_ext_contentscript_exporthelpers.html]
[test_ext_contentscript_css.html]
[test_ext_downloads.html]
[test_ext_exclude_include_globs.html]
[test_ext_i18n_css.html]
[test_ext_generate.html]
[test_ext_idle.html]
[test_ext_localStorage.html]
[test_ext_onmessage_removelistener.html]
[test_ext_notifications.html]
[test_ext_permission_xhr.html]
skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
@ -67,9 +60,7 @@ skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined
[test_ext_runtime_connect2.html]
skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
[test_ext_runtime_disconnect.html]
[test_ext_runtime_getPlatformInfo.html]
[test_ext_runtime_id.html]
[test_ext_runtime_sendMessage.html]
[test_ext_sandbox_var.html]
[test_ext_sendmessage_reply.html]
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
@ -77,21 +68,12 @@ skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
[test_ext_sendmessage_doublereply.html]
skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
[test_ext_storage.html]
[test_ext_storage_content.html]
[test_ext_storage_tab.html]
skip-if = os == 'android' # Android does not currently support tabs.
[test_ext_background_runtime_connect_params.html]
[test_ext_cookies.html]
[test_ext_bookmarks.html]
skip-if = (os == 'android' || buildapp == 'b2g') # unimplemented api. Bug 1258975 on android.
[test_ext_alarms.html]
[test_ext_background_window_properties.html]
[test_ext_background_sub_windows.html]
[test_ext_background_api_injection.html]
[test_ext_background_generated_url.html]
[test_ext_background_generated_reload.html]
[test_ext_background_generated_load_events.html]
[test_ext_i18n.html]
skip-if = (os == 'android') # Bug 1258975 on android.
[test_ext_web_accessible_resources.html]

View File

@ -1,47 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test load events in _generated_background_page.html</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
"use strict";
/* eslint-disable mozilla/balanced-listeners */
add_task(function* test_DOMContentLoaded_in_generated_background_page() {
function backgroundScript() {
function reportListener(event) {
browser.test.sendMessage("eventname", event.type);
}
document.addEventListener("DOMContentLoaded", reportListener);
window.addEventListener("load", reportListener);
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
background: {
scripts: ["bg.js"],
},
web_accessible_resources: ["_generated_background_page.html"],
},
files: {
"bg.js": `(${backgroundScript})();`,
},
});
yield extension.startup();
is("DOMContentLoaded", yield extension.awaitMessage("eventname"));
is("load", yield extension.awaitMessage("eventname"));
yield extension.unload();
});
</script>
</body>
</html>

View File

@ -1,50 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test reload of _generated_background_page.html</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>
"use strict";
add_task(function* test_reload_generated_background_page() {
function backgroundScript() {
if (location.hash !== "#firstrun") {
browser.test.sendMessage("first run");
location.hash = "#firstrun";
browser.test.assertEq("#firstrun", location.hash);
location.reload();
} else {
browser.test.notifyPass("second run");
}
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
background: {
scripts: ["bg.js"],
},
},
files: {
"bg.js": `(${backgroundScript})();`,
},
});
yield extension.startup();
info("Waiting for first message");
yield extension.awaitMessage("first run");
info("Waiting for second message");
yield extension.awaitFinish("second run");
info("Received both messages");
yield extension.unload();
});
</script>
</body>
</html>

View File

@ -1,3 +1,7 @@
{
"extends": "../../../../../testing/xpcshell/xpcshell.eslintrc",
"globals": {
"browser": false,
},
}

View File

@ -2,12 +2,24 @@
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
/* exported createHttpServer */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionManagement",
"resource://gre/modules/ExtensionManagement.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionTestUtils",
"resource://testing-common/ExtensionXPCShellUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "HttpServer",
"resource://testing-common/httpd.js");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
@ -15,37 +27,28 @@ XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
/* exported normalizeManifest */
ExtensionTestUtils.init(this);
let BASE_MANIFEST = {
"applications": {"gecko": {"id": "test@web.ext"}},
/**
* Creates a new HttpServer for testing, and begins listening on the
* specified port. Automatically shuts down the server when the test
* unit ends.
*
* @param {integer} [port]
* The port to listen on. If omitted, listen on a random
* port. The latter is the preferred behavior.
*
* @returns {HttpServer}
*/
function createHttpServer(port = -1) {
let server = new HttpServer();
server.start(port);
"manifest_version": 2,
do_register_cleanup(() => {
return new Promise(resolve => {
server.stop(resolve);
});
});
"name": "name",
"version": "0",
};
function* normalizeManifest(manifest, baseManifest = BASE_MANIFEST) {
const {Management} = Cu.import("resource://gre/modules/Extension.jsm", {});
yield Management.lazyInit();
let errors = [];
let context = {
url: null,
logError: error => {
errors.push(error);
},
preprocessors: {},
};
manifest = Object.assign({}, baseManifest, manifest);
let normalized = Schemas.normalize(manifest, "manifest.WebExtensionManifest", context);
normalized.errors = errors;
return normalized;
return server;
}

View File

@ -1,16 +1,5 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebExtension test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_alarm_without_permissions() {
@ -68,37 +57,6 @@ add_task(function* test_alarm_fires() {
});
add_task(function* test_cleared_alarm_does_not_fire() {
function backgroundScript() {
let ALARM_NAME = "test_ext_alarms";
browser.alarms.onAlarm.addListener(alarm => {
browser.test.fail("cleared alarm does not fire");
browser.test.notifyFail("alarm-cleared");
});
browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000});
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
browser.test.assertTrue(wasCleared, "alarm was cleared");
setTimeout(() => {
browser.test.notifyPass("alarm-cleared");
}, 2000);
});
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${backgroundScript})()`,
manifest: {
permissions: ["alarms"],
},
});
yield extension.startup();
yield extension.awaitFinish("alarm-cleared");
yield extension.unload();
});
add_task(function* test_alarm_fires_with_when() {
function backgroundScript() {
let ALARM_NAME = "test_ext_alarms";
@ -191,47 +149,6 @@ add_task(function* test_alarm_get_and_clear_single_argument() {
});
add_task(function* test_periodic_alarm_fires() {
function backgroundScript() {
const ALARM_NAME = "test_ext_alarms";
let count = 0;
let timer;
browser.alarms.onAlarm.addListener(alarm => {
browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name");
if (count++ === 3) {
clearTimeout(timer);
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
browser.test.assertTrue(wasCleared, "alarm was cleared");
browser.test.notifyPass("alarm-periodic");
});
}
});
browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02});
timer = setTimeout(() => {
browser.test.fail("alarm fired expected number of times");
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
browser.test.assertTrue(wasCleared, "alarm was cleared");
});
browser.test.notifyFail("alarm-periodic");
}, 30000);
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${backgroundScript})()`,
manifest: {
permissions: ["alarms"],
},
});
yield extension.startup();
yield extension.awaitFinish("alarm-periodic");
yield extension.unload();
});
add_task(function* test_get_get_all_clear_all_alarms() {
function backgroundScript() {
const ALARM_NAME = "test_alarm";
@ -302,49 +219,3 @@ add_task(function* test_get_get_all_clear_all_alarms() {
]);
yield extension.unload();
});
add_task(function* test_duplicate_alarm_name_replaces_alarm() {
function backgroundScript() {
let count = 0;
browser.alarms.onAlarm.addListener(alarm => {
if (alarm.name === "master alarm") {
browser.alarms.create("child alarm", {delayInMinutes: 0.05});
browser.alarms.getAll().then(results => {
browser.test.assertEq(2, results.length, "exactly two alarms exist");
browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name");
browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name");
}).then(() => {
if (count++ === 3) {
browser.alarms.clear("master alarm").then(wasCleared => {
return browser.alarms.clear("child alarm");
}).then(wasCleared => {
browser.test.notifyPass("alarm-duplicate");
});
}
});
} else {
browser.test.fail("duplicate named alarm replaced existing alarm");
browser.test.notifyFail("alarm-duplicate");
}
});
browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025});
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${backgroundScript})()`,
manifest: {
permissions: ["alarms"],
},
});
yield extension.startup();
yield extension.awaitFinish("alarm-duplicate");
yield extension.unload();
});
</script>
</body>
</html>

View File

@ -0,0 +1,33 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_cleared_alarm_does_not_fire() {
function backgroundScript() {
let ALARM_NAME = "test_ext_alarms";
browser.alarms.onAlarm.addListener(alarm => {
browser.test.fail("cleared alarm does not fire");
browser.test.notifyFail("alarm-cleared");
});
browser.alarms.create(ALARM_NAME, {when: Date.now() + 1000});
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
browser.test.assertTrue(wasCleared, "alarm was cleared");
setTimeout(() => {
browser.test.notifyPass("alarm-cleared");
}, 2000);
});
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${backgroundScript})()`,
manifest: {
permissions: ["alarms"],
},
});
yield extension.startup();
yield extension.awaitFinish("alarm-cleared");
yield extension.unload();
});

View File

@ -0,0 +1,43 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_periodic_alarm_fires() {
function backgroundScript() {
const ALARM_NAME = "test_ext_alarms";
let count = 0;
let timer;
browser.alarms.onAlarm.addListener(alarm => {
browser.test.assertEq(alarm.name, ALARM_NAME, "alarm has the expected name");
if (count++ === 3) {
clearTimeout(timer);
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
browser.test.assertTrue(wasCleared, "alarm was cleared");
browser.test.notifyPass("alarm-periodic");
});
}
});
browser.alarms.create(ALARM_NAME, {periodInMinutes: 0.02});
timer = setTimeout(() => {
browser.test.fail("alarm fired expected number of times");
browser.alarms.clear(ALARM_NAME).then(wasCleared => {
browser.test.assertTrue(wasCleared, "alarm was cleared");
});
browser.test.notifyFail("alarm-periodic");
}, 30000);
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${backgroundScript})()`,
manifest: {
permissions: ["alarms"],
},
});
yield extension.startup();
yield extension.awaitFinish("alarm-periodic");
yield extension.unload();
});

View File

@ -0,0 +1,45 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(function* test_duplicate_alarm_name_replaces_alarm() {
function backgroundScript() {
let count = 0;
browser.alarms.onAlarm.addListener(alarm => {
if (alarm.name === "master alarm") {
browser.alarms.create("child alarm", {delayInMinutes: 0.05});
browser.alarms.getAll().then(results => {
browser.test.assertEq(2, results.length, "exactly two alarms exist");
browser.test.assertEq("master alarm", results[0].name, "first alarm has the expected name");
browser.test.assertEq("child alarm", results[1].name, "second alarm has the expected name");
}).then(() => {
if (count++ === 3) {
browser.alarms.clear("master alarm").then(wasCleared => {
return browser.alarms.clear("child alarm");
}).then(wasCleared => {
browser.test.notifyPass("alarm-duplicate");
});
}
});
} else {
browser.test.fail("duplicate named alarm replaced existing alarm");
browser.test.notifyFail("alarm-duplicate");
}
});
browser.alarms.create("master alarm", {delayInMinutes: 0.025, periodInMinutes: 0.025});
}
let extension = ExtensionTestUtils.loadExtension({
background: `(${backgroundScript})()`,
manifest: {
permissions: ["alarms"],
},
});
yield extension.startup();
yield extension.awaitFinish("alarm-duplicate");
yield extension.unload();
});

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