Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2016-05-26 21:45:18 -04:00
commit 287f684182
185 changed files with 3440 additions and 1156 deletions

View File

@ -248,16 +248,6 @@ toolbar[customizing] > .overflow-button {
-moz-appearance: -moz-mac-fullscreen-button;
}
/* Because these buttons don't move, they should always be aligned the same,
* left and right were deprecated, so we have to do work to get it to mean that: */
#titlebar-buttonbox-container:-moz-locale-dir(ltr) {
-moz-box-align: start;
}
#titlebar-buttonbox-container:-moz-locale-dir(rtl) {
-moz-box-align: end;
}
/* Fullscreen and caption buttons don't move with RTL on OS X so override the automatic ordering. */
#titlebar-secondary-buttonbox:-moz-locale-dir(ltr),
#titlebar-buttonbox-container:-moz-locale-dir(rtl),

View File

@ -388,7 +388,8 @@ function GetCookiesResource(aProfileFolder) {
row.getResultByName("secure"),
row.getResultByName("httponly"),
false,
parseInt(expiresUtc));
parseInt(expiresUtc),
{});
} catch (e) {
Cu.reportError(e);
}

View File

@ -646,7 +646,8 @@ Cookies.prototype = {
Number(flags) & 0x1, // secure
false, // httpOnly
false, // session
expireTime);
expireTime,
{});
}
}
};

View File

@ -34,7 +34,7 @@ add_task(function* () {
"Migrated the expected number of encrypted cookies");
// Now check the cookie details.
let enumerator = Services.cookies.getCookiesFromHost(COOKIE.host);
let enumerator = Services.cookies.getCookiesFromHost(COOKIE.host, {});
Assert.ok(enumerator.hasMoreElements(), "Cookies available");
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);

View File

@ -98,7 +98,7 @@ add_task(function* () {
"Migrated the expected number of cookies");
// Now check the cookie details.
let enumerator = Services.cookies.getCookiesFromHost(COOKIE.host);
let enumerator = Services.cookies.getCookiesFromHost(COOKIE.host, {});
Assert.ok(enumerator.hasMoreElements());
let foundCookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);

View File

@ -125,7 +125,7 @@ var SessionCookiesInternal = {
if (!Services.cookies.cookieExists(cookieObj)) {
Services.cookies.add(cookie.host, cookie.path || "", cookie.name || "",
cookie.value, !!cookie.secure, !!cookie.httponly,
/* isSession = */ true, expiry);
/* isSession = */ true, expiry, cookie.originAttributes || {});
}
}
},
@ -417,6 +417,10 @@ var CookieStore = {
jscookie.expiry = cookie.expiry;
}
if (cookie.originAttributes) {
jscookie.originAttributes = cookie.originAttributes;
}
this._ensureMap(cookie).set(cookie.name, jscookie);
},

View File

@ -106,6 +106,7 @@ skip-if = buildapp == 'mulet'
skip-if = e10s # Bug 1271024
[browser_replace_load.js]
[browser_restore_redirect.js]
[browser_restore_cookies_noOriginAttributes.js]
[browser_scrollPositions.js]
[browser_scrollPositionsReaderMode.js]
[browser_sessionHistory.js]

View File

@ -0,0 +1,172 @@
/*
* Bug 1267910 - The regression test case for session cookies.
*/
"use strict";
const TEST_HOST = "www.example.com";
const COOKIE =
{
name: "test1",
value: "yes1",
path: "/browser/browser/components/sessionstore/test/"
};
const SESSION_DATA = `
{
"version": ["sessionrestore", 1],
"windows": [{
"tabs": [{
"entries": [],
"lastAccessed": 1463893009797,
"hidden": false,
"attributes": {},
"image": null
}, {
"entries": [{
"url": "http://www.example.com/browser/browser/components/sessionstore/test/browser_1267910_page.html",
\"charset": "UTF-8",
"ID": 0,
"docshellID": 2,
"originalURI": "http://www.example.com/browser/browser/components/sessionstore/test/browser_1267910_page.html",
\"docIdentifier": 0,
"persist": true
}],
"lastAccessed": 1463893009321,
"hidden": false,
"attributes": {},
"userContextId": 0,
"index": 1,
"image": "http://www.example.com/favicon.ico"
}],
"selected": 1,
"_closedTabs": [],
"busy": false,
"width": 1024,
"height": 768,
"screenX": 4,
"screenY": 23,
"sizemode": "normal",
"cookies": [{
"host": "www.example.com",
"value": "yes1",
"path": "/browser/browser/components/sessionstore/test/",
"name": "test1"
}]
}],
"selectedWindow": 1,
"_closedWindows": [],
"session": {
"lastUpdate": 1463893009801,
"startTime": 1463893007134,
"recentCrashes": 0
},
"global": {}
}`;
const SESSION_DATA_OA = `
{
"version": ["sessionrestore", 1],
"windows": [{
"tabs": [{
"entries": [],
"lastAccessed": 1463893009797,
"hidden": false,
"attributes": {},
"image": null
}, {
"entries": [{
"url": "http://www.example.com/browser/browser/components/sessionstore/test/browser_1267910_page.html",
\"charset": "UTF-8",
"ID": 0,
"docshellID": 2,
"originalURI": "http://www.example.com/browser/browser/components/sessionstore/test/browser_1267910_page.html",
\"docIdentifier": 0,
"persist": true
}],
"lastAccessed": 1463893009321,
"hidden": false,
"attributes": {},
"userContextId": 0,
"index": 1,
"image": "http://www.example.com/favicon.ico"
}],
"selected": 1,
"_closedTabs": [],
"busy": false,
"width": 1024,
"height": 768,
"screenX": 4,
"screenY": 23,
"sizemode": "normal",
"cookies": [{
"host": "www.example.com",
"value": "yes1",
"path": "/browser/browser/components/sessionstore/test/",
"name": "test1",
"originAttributes": {
"addonId": "",
"appId": 0,
"inIsolatedMozBrowser": false,
"signedPkg": "",
"userContextId": 0
}
}]
}],
"selectedWindow": 1,
"_closedWindows": [],
"session": {
"lastUpdate": 1463893009801,
"startTime": 1463893007134,
"recentCrashes": 0
},
"global": {}
}`;
add_task(function* run_test() {
// Wait until initialization is complete.
yield SessionStore.promiseInitialized;
// Clear cookies.
Services.cookies.removeAll();
// Open a new window.
let win = yield promiseNewWindowLoaded();
// Restore window with session cookies that have no originAttributes.
ss.setWindowState(win, SESSION_DATA, true);
let enumerator = Services.cookies.getCookiesFromHost(TEST_HOST, {});
let cookie;
let cookieCount = 0;
while (enumerator.hasMoreElements()) {
cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
cookieCount++;
}
// Check that the cookie is restored successfully.
is(cookieCount, 1, "expected one cookie");
is(cookie.name, COOKIE.name, "cookie name successfully restored");
is(cookie.value, COOKIE.value, "cookie value successfully restored");
is(cookie.path, COOKIE.path, "cookie path successfully restored");
// Clear cookies.
Services.cookies.removeAll();
// Restore window with session cookies that have originAttributes within.
ss.setWindowState(win, SESSION_DATA_OA, true);
enumerator = Services.cookies.getCookiesFromHost(TEST_HOST, {});
cookieCount = 0;
while (enumerator.hasMoreElements()) {
cookie = enumerator.getNext().QueryInterface(Ci.nsICookie);
cookieCount++;
}
// Check that the cookie is restored successfully.
is(cookieCount, 1, "expected one cookie");
is(cookie.name, COOKIE.name, "cookie name successfully restored");
is(cookie.value, COOKIE.value, "cookie value successfully restored");
is(cookie.path, COOKIE.path, "cookie path successfully restored");
// Close our window.
yield BrowserTestUtils.closeWindow(win);
});

View File

@ -161,7 +161,7 @@ var pktApi = (function() {
function getCookiesFromPocket() {
var cookieManager = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
var pocketCookies = cookieManager.getCookiesFromHost(pocketSiteHost);
var pocketCookies = cookieManager.getCookiesFromHost(pocketSiteHost, {});
var cookies = {};
while (pocketCookies.hasMoreElements()) {
var cookie = pocketCookies.getNext().QueryInterface(Ci.nsICookie2);

View File

@ -66,13 +66,17 @@ p {
}
.list-row > ul > li {
float: inline-start;
float: left;
width: 220px;
line-height: 1.5em;
margin-inline-start: 1em;
margin-bottom: 0;
}
.list-row > ul > li:dir(rtl) {
float: right;
}
.title {
background-image: url("chrome://browser/skin/privatebrowsing/private-browsing.svg");
background-size: 64px;
@ -161,7 +165,7 @@ a.button {
}
.toggle + .toggle-btn::before {
float: inline-start;
float: left;
left: 9px;
visibility: hidden;
background-size: 16px;
@ -177,6 +181,7 @@ a.button {
}
.toggle + .toggle-btn:dir(rtl)::before {
float: right;
left: auto;
right: 9px;
}

View File

@ -465,8 +465,10 @@ StorageActors.createActor({
populateStoresForHost(host) {
this.hostVsStores.set(host, new Map());
let doc = this.storageActor.document;
let cookies = this.getCookiesFromHost(host);
let cookies = this.getCookiesFromHost(host, doc.nodePrincipal
.originAttributes);
for (let cookie of cookies) {
if (this.isCookieAtHost(cookie, host)) {
@ -570,15 +572,22 @@ StorageActors.createActor({
* See editCookie() for format details.
*/
editItem: Task.async(function* (data) {
let doc = this.storageActor.document;
data.originAttributes = doc.nodePrincipal
.originAttributes;
this.editCookie(data);
}),
removeItem: Task.async(function* (host, name) {
this.removeCookie(host, name);
let doc = this.storageActor.document;
this.removeCookie(host, name, doc.nodePrincipal
.originAttributes);
}),
removeAll: Task.async(function* (host, domain) {
this.removeAllCookies(host, domain);
let doc = this.storageActor.document;
this.removeAllCookies(host, domain, doc.nodePrincipal
.originAttributes);
}),
maybeSetupChildProcess() {
@ -648,13 +657,13 @@ StorageActors.createActor({
});
var cookieHelpers = {
getCookiesFromHost(host) {
getCookiesFromHost(host, originAttributes) {
// Local files have no host.
if (host.startsWith("file:///")) {
host = "";
}
let cookies = Services.cookies.getCookiesFromHost(host);
let cookies = Services.cookies.getCookiesFromHost(host, originAttributes);
let store = [];
while (cookies.hasMoreElements()) {
@ -698,7 +707,7 @@ var cookieHelpers = {
let origPath = field === "path" ? oldValue : data.items.path;
let cookie = null;
let enumerator = Services.cookies.getCookiesFromHost(origHost);
let enumerator = Services.cookies.getCookiesFromHost(origHost, data.originAttributes || {});
while (enumerator.hasMoreElements()) {
let nsiCookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
if (nsiCookie.name === origName && nsiCookie.host === origHost) {
@ -769,7 +778,8 @@ var cookieHelpers = {
cookie.isSecure,
cookie.isHttpOnly,
cookie.isSession,
cookie.isSession ? MAX_COOKIE_EXPIRY : cookie.expires
cookie.isSession ? MAX_COOKIE_EXPIRY : cookie.expires,
cookie.originAttributes
);
},
@ -784,7 +794,7 @@ var cookieHelpers = {
return cookieHost == host;
}
let enumerator = Services.cookies.getCookiesFromHost(host);
let enumerator = Services.cookies.getCookiesFromHost(host, opts.originAttributes || {});
while (enumerator.hasMoreElements()) {
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
if (hostMatches(cookie.host, host) &&
@ -801,14 +811,14 @@ var cookieHelpers = {
}
},
removeCookie(host, name) {
removeCookie(host, name, originAttributes) {
if (name !== undefined) {
this._removeCookies(host, { name });
this._removeCookies(host, { name, originAttributes });
}
},
removeAllCookies(host, domain) {
this._removeCookies(host, { domain });
removeAllCookies(host, domain, originAttributes) {
this._removeCookies(host, { domain, originAttributes });
},
addCookieObservers() {
@ -861,7 +871,8 @@ var cookieHelpers = {
switch (msg.json.method) {
case "getCookiesFromHost": {
let host = msg.data.args[0];
let cookies = cookieHelpers.getCookiesFromHost(host);
let originAttributes = msg.data.args[1];
let cookies = cookieHelpers.getCookiesFromHost(host, originAttributes);
return JSON.stringify(cookies);
}
case "addCookieObservers": {
@ -877,12 +888,14 @@ var cookieHelpers = {
case "removeCookie": {
let host = msg.data.args[0];
let name = msg.data.args[1];
return cookieHelpers.removeCookie(host, name);
let originAttributes = msg.data.args[2];
return cookieHelpers.removeCookie(host, name, originAttributes);
}
case "removeAllCookies": {
let host = msg.data.args[0];
let domain = msg.data.args[1];
return cookieHelpers.removeAllCookies(host, domain);
let originAttributes = msg.data.args[2];
return cookieHelpers.removeAllCookies(host, domain, originAttributes);
}
default:
console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method);

View File

@ -85,8 +85,11 @@ exports.items = [
"see bug 1221488");
}
let host = new URL(context.environment.target.url).host;
let contentWindow = context.environment.window;
host = sanitizeHost(host);
let enm = cookieMgr.getCookiesFromHost(host);
let enm = cookieMgr.getCookiesFromHost(host, contentWindow.document.
nodePrincipal.
originAttributes);
let cookies = [];
while (enm.hasMoreElements()) {
@ -127,8 +130,11 @@ exports.items = [
"see bug 1221488");
}
let host = new URL(context.environment.target.url).host;
let contentWindow = context.environment.window;
host = sanitizeHost(host);
let enm = cookieMgr.getCookiesFromHost(host);
let enm = cookieMgr.getCookiesFromHost(host, contentWindow.document.
nodePrincipal.
originAttributes);
while (enm.hasMoreElements()) {
let cookie = enm.getNext().QueryInterface(Ci.nsICookie);
@ -270,7 +276,7 @@ exports.items = [
let host = new URL(context.environment.target.url).host;
host = sanitizeHost(host);
let time = Date.parse(args.expires) / 1000;
let contentWindow = context.environment.window;
cookieMgr.add(args.domain ? "." + args.domain : host,
args.path ? args.path : "/",
args.name,
@ -278,7 +284,10 @@ exports.items = [
args.secure,
args.httpOnly,
args.session,
time);
time,
contentWindow.document.
nodePrincipal.
originAttributes);
}
}
];

View File

@ -30,8 +30,8 @@ StepTiming(uint32_t aSteps,
nsTimingFunction::Type aType)
{
MOZ_ASSERT(0.0 <= aPortion && aPortion <= 1.0, "out of range");
MOZ_ASSERT(aType != nsTimingFunction::Type::StepStart ||
aType != nsTimingFunction::Type::StepEnd, "invalid type");
MOZ_ASSERT(aType == nsTimingFunction::Type::StepStart ||
aType == nsTimingFunction::Type::StepEnd, "invalid type");
if (aPortion == 1.0) {
return 1.0;

View File

@ -319,6 +319,11 @@ public:
nsIntRegion fillPaintNeededRegion;
nsIntRegion strokePaintNeededRegion;
if (aCtx->CurrentState().updateFilterOnWriteOnly) {
aCtx->UpdateFilter();
aCtx->CurrentState().updateFilterOnWriteOnly = false;
}
FilterSupport::ComputeSourceNeededRegions(
aCtx->CurrentState().filter, mPostFilterBounds,
sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion);
@ -405,6 +410,12 @@ public:
mCtx->CurrentState().filterAdditionalImages,
mPostFilterBounds.TopLeft() - mOffset,
DrawOptions(1.0f, mCompositionOp));
const gfx::FilterDescription& filter = mCtx->CurrentState().filter;
MOZ_ASSERT(!filter.mPrimitives.IsEmpty());
if (filter.mPrimitives.LastElement().IsTainted() && mCtx->mCanvasElement) {
mCtx->mCanvasElement->SetWriteOnly();
}
}
DrawTarget* DT()
@ -2468,6 +2479,9 @@ CanvasRenderingContext2D::SetFilter(const nsAString& aFilter, ErrorResult& aErro
UpdateFilter();
}
}
if (mCanvasElement && !mCanvasElement->IsWriteOnly()) {
CurrentState().updateFilterOnWriteOnly = true;
}
}
class CanvasUserSpaceMetrics : public UserSpaceMetricsWithSize

View File

@ -912,6 +912,7 @@ protected:
lineCap(mozilla::gfx::CapStyle::BUTT),
lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
filterString(MOZ_UTF16("none")),
updateFilterOnWriteOnly(false),
imageSmoothingEnabled(true),
fontExplicitLanguage(false)
{ }
@ -944,6 +945,7 @@ protected:
filterChainObserver(aOther.filterChainObserver),
filter(aOther.filter),
filterAdditionalImages(aOther.filterAdditionalImages),
updateFilterOnWriteOnly(aOther.updateFilterOnWriteOnly),
imageSmoothingEnabled(aOther.imageSmoothingEnabled),
fontExplicitLanguage(aOther.fontExplicitLanguage)
{ }
@ -1021,6 +1023,7 @@ protected:
RefPtr<nsSVGFilterChainObserver> filterChainObserver;
mozilla::gfx::FilterDescription filter;
nsTArray<RefPtr<mozilla::gfx::SourceSurface>> filterAdditionalImages;
bool updateFilterOnWriteOnly;
bool imageSmoothingEnabled;
bool fontExplicitLanguage;

View File

@ -256,6 +256,14 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # bug 1040965
[test_createPattern_broken.html]
[test_setlinedash.html]
[test_filter.html]
skip-if = (e10s && debug && os == 'win')
[test_filter_tainted.html]
skip-if = (e10s && debug && os == 'win')
[test_filter_tainted_source_graphics.html]
skip-if = (e10s && debug && os == 'win')
[test_filter_tainted_displacement_map.html]
skip-if = (e10s && debug && os == 'win')
[test_filter_tainted_displacement_map_source_graphics.html]
[test_offscreencanvas_toblob.html]
subsuite = gpu
tags = offscreencanvas

View File

@ -0,0 +1,45 @@
<!DOCTYPE HTML>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body onload="runTest()">
<svg style="display: block; width: 0; height: 0">
<defs>
<filter id="tainted">
<feImage xlink:href="http://example.com/tests/dom/canvas/test/crossorigin/image.png" />
</filter>
</defs>
</svg>
<script>
function runTest() {
SpecialPowers.pushPrefEnv({ 'set': [['canvas.filters.enabled', true]] }, function () {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.filter = 'url(#tainted)';
ctx.rect(0, 0, 16, 16);
ctx.fill();
var expected_error = 'SecurityError';
var data;
try {
data = ctx.getImageData(0, 0, 16, 16);
actual_error = "";
} catch (e) {
actual_error = e.name;
}
is(actual_error, expected_error, 'Canvas should have been tainted and throw a SecurityError');
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body onload="runTest()" style="margin: 0; padding: 0">
<svg style="display: block; width: 0; height: 0">
<defs>
<filter id="tainted">
<feImage xlink:href="http://example.com/tests/dom/canvas/test/image_red-16x16.png"/>
</filter>
</defs>
</svg>
<canvas id="c" width="16" height="16"></canvas>
<script>
function isPixel(ctx, x,y, r,g,b,a, pos, color, d) {
var pixel = ctx.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
ok(r - d <= pr && pr <= r + d &&
g - d <= pg && pg <= g + d &&
b - d <= pb && pb <= b + d &&
a - d <= pa && pa <= a + d,
'pixel ' + pos + ' is ' + pr + ',' + pg + ',' + pb + ',' + pa + '; expected ' + color + ' +/- ' + d);
}
function runTest() {
SpecialPowers.pushPrefEnv({ 'set': [['canvas.filters.enabled', true]] }, function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.filter = 'url(#tainted)';
ctx.rect(0, 0, 16, 16);
ctx.fill();
var canvas2 = document.createElement('canvas');
var ctx2 = SpecialPowers.wrap(canvas2.getContext('2d'));
ctx2.drawWindow(window, 0, 0, 16, 16, 'rgb(255,255,255)', 0);
isPixel(ctx2, 8,8, 255,0,0,255, '8,8', "255,0,0,255", 5);
var expected_error = 'SecurityError';
var data;
try {
data = ctx.getImageData(0, 0, 16, 16);
actual_error = "";
} catch (e) {
actual_error = e.name;
}
is(actual_error, expected_error, 'canvas should have been tainted and throw a SecurityError');
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -0,0 +1,64 @@
<!DOCTYPE HTML>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body onload="runTest()" style="margin: 0; padding: 0">
<svg style="display: block; width: 0; height: 0">
<defs>
<filter id="tainted">
<feImage xlink:href='image_red-16x16.png' result='img'/>
<feImage xlink:href='http://example.com/tests/dom/canvas/test/image_green-16x16.png' result='map'/>
<feDisplacementMap in="img" in2="map" scale="20"/>
</filter>
</defs>
</svg>
<canvas id="c" width="16" height="16"></canvas>
<script>
function isPixel(ctx, x,y, r,g,b,a, pos, color, d) {
var pixel = ctx.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
ok(r - d <= pr && pr <= r + d &&
g - d <= pg && pg <= g + d &&
b - d <= pb && pb <= b + d &&
a - d <= pa && pa <= a + d,
'pixel ' + pos + ' is ' + pr + ',' + pg + ',' + pb + ',' + pa + '; expected ' + color + ' +/- ' + d);
}
function runTest() {
SpecialPowers.pushPrefEnv({ 'set': [['canvas.filters.enabled', true]] }, function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
ctx.filter = 'url(#tainted)';
ctx.rect(0, 0, 16, 16);
ctx.fill();
var canvas2 = document.createElement('canvas');
var ctx2 = SpecialPowers.wrap(canvas2.getContext('2d'));
ctx2.drawWindow(window, 0, 0, 16, 16, 'rgb(255,255,255)', 0);
isPixel(ctx2, 8,8, 255,0,0,255, '8,8', "255,0,0,255", 5);
var expected_error = 'SecurityError';
var data;
try {
data = ctx.getImageData(0, 0, 16, 16);
actual_error = "";
} catch (e) {
actual_error = e.name;
}
is(actual_error, expected_error, 'canvas should have been tainted and throw a SecurityError');
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -0,0 +1,73 @@
<!DOCTYPE HTML>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body onload="runTest()" style="margin: 0; padding: 0">
<svg style="display: block; width: 0; height: 0">
<defs>
<filter id="tainted1">
<feImage xlink:href='image_red-16x16.png' result='img'/>
<feDisplacementMap in="img" in2="SourceGraphic" scale="20"/>
</filter>
<filter id="tainted2">
<feImage xlink:href='http://example.com/tests/dom/canvas/test/image_red-16x16.png' result='img'/>
<feDisplacementMap in="SourceGraphic" in2="img" scale="20"/>
</filter>
</defs>
</svg>
<canvas id="c" width="16" height="16"></canvas>
<img id="i" src="http://example.com/tests/dom/canvas/test/image_green-16x16.png"/>
<script>
function isPixel(ctx, x,y, r,g,b,a, pos, color, d) {
var pixel = ctx.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
ok(r - d <= pr && pr <= r + d &&
g - d <= pg && pg <= g + d &&
b - d <= pb && pb <= b + d &&
a - d <= pa && pa <= a + d,
'pixel ' + pos + ' is ' + pr + ',' + pg + ',' + pb + ',' + pa + '; expected ' + color + ' +/- ' + d);
}
function runTest() {
SpecialPowers.pushPrefEnv({ 'set': [['canvas.filters.enabled', true]] }, function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.getElementById('i');
ctx.filter = 'url(#tainted1)';
ctx.drawImage(img, 0, 0);
var canvas2 = document.createElement('canvas');
var ctx2 = SpecialPowers.wrap(canvas2.getContext('2d'));
ctx2.drawWindow(window, 0, 0, 16, 16, 'rgb(255, 255, 255)', 0);
isPixel(ctx2, 8,8, 255,0,0,255, '8,8', "255,0,0,255", 5);
ctx.filter = 'url(#tainted2)';
ctx.drawImage(img, 0, 0);
ctx2.drawWindow(window, 0, 0, 16, 16, 'rgb(255, 255, 255)', 0);
isPixel(ctx2, 8,8, 0,255,0,255, '8,8', "0,255,0,255", 5);
var expected_error = 'SecurityError';
var data;
try {
data = ctx.getImageData(0, 0, 16, 16);
actual_error = "";
} catch (e) {
actual_error = e.name;
}
is(actual_error, expected_error, 'canvas should have been tainted and throw a SecurityError');
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body onload="runTest()" style="margin: 0; padding: 0">
<svg style="display: block; width: 0; height: 0">
<defs>
<filter id="tainted">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0
1 1 1 1 0
0 0 0 0 0
0 0 0 1 0"/>
</filter>
</defs>
</svg>
<canvas id="c" width="16" height="16"></canvas>
<img id="i" src="http://example.com/tests/dom/canvas/test/image_red-16x16.png"/>
<script>
function isPixel(ctx, x,y, r,g,b,a, pos, color, d) {
var pixel = ctx.getImageData(x, y, 1, 1);
var pr = pixel.data[0],
pg = pixel.data[1],
pb = pixel.data[2],
pa = pixel.data[3];
ok(r - d <= pr && pr <= r + d &&
g - d <= pg && pg <= g + d &&
b - d <= pb && pb <= b + d &&
a - d <= pa && pa <= a + d,
'pixel ' + pos + ' is ' + pr + ',' + pg + ',' + pb + ',' + pa + '; expected ' + color + ' +/- ' + d);
}
function runTest() {
SpecialPowers.pushPrefEnv({ 'set': [['canvas.filters.enabled', true]] }, function () {
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.getElementById('i');
ctx.filter = 'url(#tainted)';
ctx.drawImage(img, 0, 0);
var canvas2 = document.createElement('canvas');
var ctx2 = SpecialPowers.wrap(canvas2.getContext('2d'));
ctx2.drawWindow(window, 0, 0, 16, 16, 'rgb(255,255,255)', 0);
isPixel(ctx2, 8,8, 0,255,0,255, '8,8', "0,255,0,255", 5);
var expected_error = 'SecurityError';
var data;
try {
data = ctx.getImageData(0, 0, 16, 16);
actual_error = "";
} catch (e) {
actual_error = e.name;
}
is(actual_error, expected_error, 'canvas should have been tainted and throw a SecurityError');
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -146,11 +146,10 @@ this.ManifestProcessor = { // jshint ignore:line
trim: true
};
const value = extractor.extractValue(spec);
if (this.orientationTypes.has(value)) {
return value;
if (value && typeof value === "string" && this.orientationTypes.has(value.toLowerCase())) {
return value.toLowerCase();
}
// The spec special-cases orientation to return the empty string.
return '';
return undefined;
}
function processDisplayMember() {
@ -162,8 +161,8 @@ this.ManifestProcessor = { // jshint ignore:line
trim: true
};
const value = extractor.extractValue(spec);
if (displayModes.has(value)) {
return value;
if (value && typeof value === "string" && displayModes.has(value.toLowerCase())) {
return value.toLowerCase();
}
return this.defaultDisplayMode;
}

View File

@ -25,15 +25,24 @@ typeTests.forEach((type) => {
is(result.display, 'browser', expected);
});
/*Test valid modes*/
var validModes = ['fullscreen', 'standalone', 'minimal-ui', 'browser']
/*Test valid modes - case insensitive*/
var validModes = [
'fullscreen',
'standalone',
'minimal-ui',
'browser',
'FullScreen',
'standAlone',
'minimal-UI',
'BROWSER',
]
validModes.forEach((mode) => {
var expected = `Expect display mode to be ${mode}.`;
var expected = `Expect display mode to be ${mode.toLowerCase()}.`;
data.jsonText = JSON.stringify({
display: mode
});
var result = processor.process(data);
is(result.display, mode, expected);
is(result.display, mode.toLowerCase(), expected);
});
//trim tests
@ -44,11 +53,19 @@ validModes.forEach((display) => {
display: expandedDisplay
});
var result = processor.process(data);
is(result.display, display, expected);
is(result.display, display.toLowerCase(), expected);
});
//Unknown modes
var invalidModes = ['foo', `fooo${whiteSpace}`, '', 'fullscreen,standalone', 'standalone fullscreen', 'FULLSCreEN'];
var invalidModes = [
'foo',
`fooo${whiteSpace}`,
'',
'fullscreen,standalone',
'standalone fullscreen',
'FULLSCreENS',
];
invalidModes.forEach((invalidMode) => {
var expected = `Expect default display mode "browser" to be returned: '${invalidMode}'`;
data.jsonText = JSON.stringify({

View File

@ -22,10 +22,9 @@ typeTests.forEach((type) => {
orientation: type
});
var result = processor.process(data);
is(result.orientation, '', expected);
is(result.orientation, undefined, expected);
});
var validOrientations = [
'any',
'natural',
@ -34,22 +33,28 @@ var validOrientations = [
'portrait-primary',
'portrait-secondary',
'landscape-primary',
'landscape-secondary'
'landscape-secondary',
'aNy',
'NaTuRal',
'LANDsCAPE',
'PORTRAIT',
'portrait-PRIMARY',
'portrait-SECONDARY',
'LANDSCAPE-primary',
'LANDSCAPE-secondary',
];
validOrientations.forEach((orientation) => {
var expected = `Expect orientation to be returned: ${orientation}.`;
data.jsonText = JSON.stringify({
orientation: orientation
});
data.jsonText = JSON.stringify({ orientation });
var result = processor.process(data);
is(result.orientation, orientation, expected);
is(result.orientation, orientation.toLowerCase(), expected);
});
var invalidOrientations = [
'all',
'ANY',
'NaTuRal',
'ANYMany',
'NaTuRalle',
'portrait-primary portrait-secondary',
'portrait-primary,portrait-secondary',
'any-natural',
@ -58,15 +63,13 @@ var invalidOrientations = [
'secondary-portrait',
'landscape-landscape',
'secondary-primary'
]
];
invalidOrientations.forEach((orientation) => {
var expected = `Expect orientation to be empty string: ${orientation}.`;
data.jsonText = JSON.stringify({
orientation: orientation
});
data.jsonText = JSON.stringify({ orientation });
var result = processor.process(data);
is(result.orientation, "", expected);
is(result.orientation, undefined, expected);
});
//Trim tests
@ -77,7 +80,7 @@ validOrientations.forEach((orientation) => {
orientation: expandedOrientation
});
var result = processor.process(data);
is(result.orientation, orientation, expected);
is(result.orientation, orientation.toLowerCase(), expected);
});
</script>
</head>

View File

@ -520,6 +520,13 @@ struct TrackBound
* for those objects in arbitrary order and the MediaStreamGraph has to be able
* to handle this.
*/
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount() and conflicts with MediaStream::GetCurrentTime.
#ifdef GetCurrentTime
#undef GetCurrentTime
#endif
class MediaStream : public mozilla::LinkedListElement<MediaStream>
{
public:

View File

@ -1,12 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "PlatformDecoderModule.h"
mozilla::LogModule* GetPDMLog() {
static mozilla::LazyLogModule log("PlatformDecoderModule");
return log;
}

View File

@ -30,6 +30,8 @@ class MediaDataDecoderCallback;
class TaskQueue;
class CDMProxy;
static LazyLogModule sPDMLog("PlatformDecoderModule");
// The PlatformDecoderModule interface is used by the MediaFormatReader to
// abstract access to decoders provided by various
// platforms.

View File

@ -15,8 +15,7 @@
#include <stdint.h>
#include <inttypes.h> // For PRId64
extern mozilla::LogModule* GetPDMLog();
#define OPUS_DEBUG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, \
#define OPUS_DEBUG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
("OpusDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
namespace mozilla {

View File

@ -15,8 +15,7 @@
#include <algorithm>
#undef LOG
extern mozilla::LogModule* GetPDMLog();
#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("VPXDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("VPXDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
namespace mozilla {

View File

@ -13,8 +13,7 @@
#include "nsAutoPtr.h"
#undef LOG
extern mozilla::LogModule* GetPDMLog();
#define LOG(type, msg) MOZ_LOG(GetPDMLog(), type, msg)
#define LOG(type, msg) MOZ_LOG(sPDMLog, type, msg)
namespace mozilla {

View File

@ -13,8 +13,7 @@
#include "mozilla/SyncRunnable.h"
#include "mozilla/UniquePtr.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
#define FourCC2Str(n) ((char[5]){(char)(n >> 24), (char)(n >> 16), (char)(n >> 8), (char)(n), 0})
namespace mozilla {

View File

@ -14,8 +14,7 @@
#include "nsCocoaFeatures.h"
#endif
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -28,8 +28,7 @@
#include "MacIOSurfaceImage.h"
#endif
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
//#define LOG_MEDIA_SHA1
namespace mozilla {

View File

@ -9,8 +9,7 @@
#include "AppleVDALinker.h"
#include "nsDebug.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -20,8 +20,7 @@
#include "VideoUtils.h"
#include "gfxPlatform.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -10,8 +10,7 @@
#include "mozilla/ArrayUtils.h"
#include "nsDebug.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -9,7 +9,6 @@
#include "mozilla/Logging.h"
extern mozilla::LogModule* GetPDMLog();
#define FFMPEG_LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define FFMPEG_LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
#endif // __FFmpegLog_h__

View File

@ -27,8 +27,7 @@
#include <android/log.h>
#define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__)
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
using namespace android;
typedef android::MediaCodecProxy MediaCodecProxy;

View File

@ -20,8 +20,7 @@
#include <utils/AndroidThreads.h>
#endif
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
using namespace android;

View File

@ -32,8 +32,7 @@
#include <android/log.h>
#define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__)
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
using namespace mozilla::layers;
using namespace android;
typedef android::MediaCodecProxy MediaCodecProxy;

View File

@ -24,7 +24,6 @@ UNIFIED_SOURCES += [
'agnostic/VPXDecoder.cpp',
'agnostic/WAVDecoder.cpp',
'PDMFactory.cpp',
'PlatformDecoderModule.cpp',
'wrappers/FuzzingWrapper.cpp',
'wrappers/H264Converter.cpp'
]

View File

@ -21,13 +21,12 @@
#include "MediaInfo.h"
#include "OmxDataDecoder.h"
extern mozilla::LogModule* GetPDMLog();
#ifdef LOG
#undef LOG
#endif
#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("GonkOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("GonkOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define CHECK_ERR(err) \
if (err != OK) { \

View File

@ -12,19 +12,18 @@
#include "OmxPlatformLayer.h"
extern mozilla::LogModule* GetPDMLog();
#ifdef LOG
#undef LOG
#undef LOGL
#endif
#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("OmxDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("OmxDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define LOGL(arg, ...) \
{ \
void* p = self; \
MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, \
MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, \
("OmxDataDecoder(%p)::%s: " arg, p, __func__, ##__VA_ARGS__)); \
}

View File

@ -13,13 +13,12 @@
#include "GonkOmxPlatformLayer.h"
#endif
extern mozilla::LogModule* GetPDMLog();
#ifdef LOG
#undef LOG
#endif
#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("OmxPlatformLayer -- %s: " arg, __func__, ##__VA_ARGS__))
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("OmxPlatformLayer -- %s: " arg, __func__, ##__VA_ARGS__))
#define RETURN_IF_ERR(err) \
if (err != OMX_ErrorNone) { \

View File

@ -11,13 +11,12 @@
#include "OmxDataDecoder.h"
#include "OmxPlatformLayer.h"
extern mozilla::LogModule* GetPDMLog();
#ifdef LOG
#undef LOG
#endif
#define LOG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, ("OmxPromiseLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("OmxPromiseLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
namespace mozilla {

View File

@ -9,8 +9,7 @@
#include "WMFUtils.h"
#include "mozilla/Logging.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -13,8 +13,7 @@
#include "mozilla/Telemetry.h"
#include "mozilla/Logging.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -13,8 +13,7 @@
#include "mozilla/Logging.h"
#include "mozilla/SyncRunnable.h"
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
namespace mozilla {

View File

@ -30,8 +30,7 @@
#include "MediaTelemetryConstants.h"
#include "GMPUtils.h" // For SplitAt. TODO: Move SplitAt to a central place.
extern mozilla::LogModule* GetPDMLog();
#define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
using mozilla::layers::Image;
using mozilla::layers::IMFYCbCrImage;

View File

@ -77,6 +77,103 @@ UnwrapPromise(JS::Handle<JSObject*> aPromise, ErrorResult& aRv)
}
return promise;
}
#endif // SPIDERMONKEY_PROMISE
#ifdef SPIDERMONKEY_PROMISE
/* static */ void
PromiseDebugging::GetState(GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
PromiseDebuggingStateHolder& aState,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
if (!obj || !JS::IsPromiseObject(obj)) {
aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
"Argument of PromiseDebugging.getState"));
return;
}
switch (JS::GetPromiseState(obj)) {
case JS::PromiseState::Pending:
aState.mState = PromiseDebuggingState::Pending;
break;
case JS::PromiseState::Fulfilled:
aState.mState = PromiseDebuggingState::Fulfilled;
aState.mValue = JS::GetPromiseResult(obj);
break;
case JS::PromiseState::Rejected:
aState.mState = PromiseDebuggingState::Rejected;
aState.mReason = JS::GetPromiseResult(obj);
break;
}
}
/* static */ void
PromiseDebugging::GetPromiseID(GlobalObject& aGlobal,
JS::Handle<JSObject*> aPromise,
nsString& aID,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
if (!obj || !JS::IsPromiseObject(obj)) {
aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
"Argument of PromiseDebugging.getState"));
return;
}
uint64_t promiseID = JS::GetPromiseID(obj);
aID = sIDPrefix;
aID.AppendInt(promiseID);
}
/* static */ void
PromiseDebugging::GetAllocationStack(GlobalObject& aGlobal,
JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
if (!obj || !JS::IsPromiseObject(obj)) {
aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
"Argument of PromiseDebugging.getAllocationStack"));
return;
}
aStack.set(JS::GetPromiseAllocationSite(obj));
}
/* static */ void
PromiseDebugging::GetRejectionStack(GlobalObject& aGlobal,
JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
if (!obj || !JS::IsPromiseObject(obj)) {
aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
"Argument of PromiseDebugging.getRejectionStack"));
return;
}
aStack.set(JS::GetPromiseResolutionSite(obj));
}
/* static */ void
PromiseDebugging::GetFullfillmentStack(GlobalObject& aGlobal,
JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv)
{
JSContext* cx = aGlobal.Context();
JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
if (!obj || !JS::IsPromiseObject(obj)) {
aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING(
"Argument of PromiseDebugging.getFulfillmentStack"));
return;
}
aStack.set(JS::GetPromiseResolutionSite(obj));
}
#else
/* static */ void
PromiseDebugging::GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,

View File

@ -32,11 +32,13 @@ public:
static void Init();
static void Shutdown();
#ifndef SPIDERMONKEY_PROMISE
static void GetState(GlobalObject&, JS::Handle<JSObject*> aPromise,
PromiseDebuggingStateHolder& aState,
ErrorResult& aRv);
static void GetPromiseID(GlobalObject&, JS::Handle<JSObject*>, nsString&,
ErrorResult&);
static void GetAllocationStack(GlobalObject&, JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv);
@ -47,6 +49,8 @@ public:
JS::Handle<JSObject*> aPromise,
JS::MutableHandle<JSObject*> aStack,
ErrorResult& aRv);
#ifndef SPIDERMONKEY_PROMISE
static void GetDependentPromises(GlobalObject&,
JS::Handle<JSObject*> aPromise,
nsTArray<RefPtr<Promise>>& aPromises,
@ -56,9 +60,6 @@ public:
ErrorResult& aRv);
static double GetTimeToSettle(GlobalObject&, JS::Handle<JSObject*> aPromise,
ErrorResult& aRv);
static void GetPromiseID(GlobalObject&, JS::Handle<JSObject*>, nsString&,
ErrorResult&);
#endif // SPIDERMONKEY_PROMISE
// Mechanism for watching uncaught instances of Promise.

View File

@ -222,7 +222,7 @@ partial interface Document {
// https://fullscreen.spec.whatwg.org/#api
partial interface Document {
// Note: Per spec the 'S' in these two is lowercase, but the "Moz"
// versions hve it uppercase.
// versions have it uppercase.
[LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
readonly attribute boolean fullscreen;
[BinaryName="fullscreen", Deprecated="PrefixedFullscreenAPI"]

View File

@ -52,7 +52,6 @@ callback interface UncaughtRejectionObserver {
[ChromeOnly, Exposed=(Window,System)]
interface PromiseDebugging {
#ifndef SPIDERMONKEY_PROMISE
/**
* The various functions on this interface all expect to take promises but
* don't want the WebIDL behavior of assimilating random passed-in objects
@ -68,6 +67,13 @@ interface PromiseDebugging {
[Throws]
static PromiseDebuggingStateHolder getState(object p);
/**
* Return an identifier for a promise. This identifier is guaranteed
* to be unique to the current process.
*/
[Throws]
static DOMString getPromiseID(object p);
/**
* Return the stack to the promise's allocation point. This can
* return null if the promise was not created from script.
@ -91,13 +97,7 @@ interface PromiseDebugging {
[Throws]
static object? getFullfillmentStack(object p);
/**
* Return an identifier for a promise. This identifier is guaranteed
* to be unique to this instance of Firefox.
*/
[Throws]
static DOMString getPromiseID(object p);
#ifndef SPIDERMONKEY_PROMISE
/**
* Get the promises directly depending on a given promise. These are:
*

View File

@ -1019,7 +1019,7 @@ nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent)
nsAutoString eventType;
aEvent->GetType(eventType);
if (eventType.EqualsLiteral("dragover")) {
bool canDropLink;
bool canDropLink = false;
handler->CanDropLink(dragEvent, false, &canDropLink);
if (canDropLink) {
aEvent->PreventDefault();

View File

@ -86,7 +86,7 @@ addMessageListener("init", ({ domain }) => {
info(count + " cookies");
cs.removeAll();
cs.add(domain, "", "oh", "hai", false, false, true, Math.pow(2, 62));
cs.add(domain, "", "oh", "hai", false, false, true, Math.pow(2, 62), {});
is(cs.countCookiesFromHost(domain), 1, "number of cookies for domain " + domain);
gObs = new obs();

View File

@ -13,7 +13,7 @@ function run_test() {
// test that variants of 'baz.com' get normalized appropriately, but that
// malformed hosts are rejected
cm.add("baz.com", "/", "foo", "bar", false, false, true, expiry);
cm.add("baz.com", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("baz.com"), 1);
do_check_eq(cm.countCookiesFromHost("BAZ.com"), 1);
do_check_eq(cm.countCookiesFromHost(".baz.com"), 1);
@ -34,7 +34,7 @@ function run_test() {
do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
// Test that 'baz.com' and 'baz.com.' are treated differently
cm.add("baz.com.", "/", "foo", "bar", false, false, true, expiry);
cm.add("baz.com.", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
do_check_eq(cm.countCookiesFromHost("BAZ.com"), 0);
do_check_eq(cm.countCookiesFromHost(".baz.com"), 0);
@ -47,7 +47,7 @@ function run_test() {
// test that domain cookies are illegal for IP addresses, aliases such as
// 'localhost', and eTLD's such as 'co.uk'
cm.add("192.168.0.1", "/", "foo", "bar", false, false, true, expiry);
cm.add("192.168.0.1", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("192.168.0.1"), 1);
do_check_eq(cm.countCookiesFromHost("192.168.0.1."), 0);
do_check_throws(function() {
@ -57,7 +57,7 @@ function run_test() {
cm.countCookiesFromHost(".192.168.0.1.");
}, Cr.NS_ERROR_ILLEGAL_VALUE);
cm.add("localhost", "/", "foo", "bar", false, false, true, expiry);
cm.add("localhost", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("localhost"), 1);
do_check_eq(cm.countCookiesFromHost("localhost."), 0);
do_check_throws(function() {
@ -67,7 +67,7 @@ function run_test() {
cm.countCookiesFromHost(".localhost.");
}, Cr.NS_ERROR_ILLEGAL_VALUE);
cm.add("co.uk", "/", "foo", "bar", false, false, true, expiry);
cm.add("co.uk", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("co.uk"), 1);
do_check_eq(cm.countCookiesFromHost("co.uk."), 0);
do_check_throws(function() {
@ -105,26 +105,26 @@ function run_test() {
cm.countCookiesFromHost("..");
}, Cr.NS_ERROR_ILLEGAL_VALUE);
var e = cm.getCookiesFromHost("");
var e = cm.getCookiesFromHost("", {});
do_check_false(e.hasMoreElements());
do_check_throws(function() {
cm.getCookiesFromHost(".");
cm.getCookiesFromHost(".", {});
}, Cr.NS_ERROR_ILLEGAL_VALUE);
do_check_throws(function() {
cm.getCookiesFromHost("..");
cm.getCookiesFromHost("..", {});
}, Cr.NS_ERROR_ILLEGAL_VALUE);
e = cm.getCookiesFromHost("baz.com");
e = cm.getCookiesFromHost("baz.com", {});
do_check_true(e.hasMoreElements());
do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).name, "foo");
do_check_false(e.hasMoreElements());
e = cm.getCookiesFromHost("");
e = cm.getCookiesFromHost("", {});
do_check_false(e.hasMoreElements());
do_check_throws(function() {
cm.getCookiesFromHost(".");
cm.getCookiesFromHost(".", {});
}, Cr.NS_ERROR_ILLEGAL_VALUE);
do_check_throws(function() {
cm.getCookiesFromHost("..");
cm.getCookiesFromHost("..", {});
}, Cr.NS_ERROR_ILLEGAL_VALUE);
cm.removeAll();
@ -151,26 +151,26 @@ function run_test() {
cm.countCookiesFromHost(".");
}, Cr.NS_ERROR_ILLEGAL_VALUE);
e = cm.getCookiesFromHost("baz.com");
e = cm.getCookiesFromHost("baz.com", {});
do_check_false(e.hasMoreElements());
e = cm.getCookiesFromHost("");
e = cm.getCookiesFromHost("", {});
do_check_true(e.hasMoreElements());
e.getNext();
do_check_true(e.hasMoreElements());
e.getNext();
do_check_false(e.hasMoreElements());
do_check_throws(function() {
cm.getCookiesFromHost(".");
cm.getCookiesFromHost(".", {});
}, Cr.NS_ERROR_ILLEGAL_VALUE);
cm.removeAll();
// test that an empty host to add() or remove() works,
// but a host of '.' doesn't
cm.add("", "/", "foo2", "bar", false, false, true, expiry);
cm.add("", "/", "foo2", "bar", false, false, true, expiry, {});
do_check_eq(getCookieCount(), 1);
do_check_throws(function() {
cm.add(".", "/", "foo3", "bar", false, false, true, expiry);
cm.add(".", "/", "foo3", "bar", false, false, true, expiry, {});
}, Cr.NS_ERROR_ILLEGAL_VALUE);
do_check_eq(getCookieCount(), 1);
@ -216,13 +216,13 @@ function testDomainCookie(uriString, domain) {
var uri = NetUtil.newURI(uriString);
cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null);
var e = cm.getCookiesFromHost(domain);
var e = cm.getCookiesFromHost(domain, {});
do_check_true(e.hasMoreElements());
do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).host, domain);
cm.removeAll();
cs.setCookieString(uri, null, "foo=bar; domain=." + domain, null);
e = cm.getCookiesFromHost(domain);
e = cm.getCookiesFromHost(domain, {});
do_check_true(e.hasMoreElements());
do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).host, domain);
cm.removeAll();

View File

@ -10,7 +10,7 @@ function run_test() {
// Test our handling of host names with a single character at the beginning
// followed by a dot.
cm.add("e.mail.com", "/", "foo", "bar", false, false, true, expiry);
cm.add("e.mail.com", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("e.mail.com"), 1);
do_check_eq(cs.getCookieString(NetUtil.newURI("http://e.mail.com"), null), "foo=bar");
}

View File

@ -10,7 +10,7 @@ function run_test() {
// Test our handling of host names with a single character consisting only
// of a single character
cm.add("a", "/", "foo", "bar", false, false, true, expiry);
cm.add("a", "/", "foo", "bar", false, false, true, expiry, {});
do_check_eq(cm.countCookiesFromHost("a"), 1);
do_check_eq(cs.getCookieString(NetUtil.newURI("http://a"), null), "foo=bar");
}

View File

@ -158,7 +158,7 @@ function run_test_1(generator)
// Attempt to insert a cookie with the same (name, host, path) triplet.
Services.cookiemgr.add(cookie.host, cookie.path, cookie.name, "hallo",
cookie.isSecure, cookie.isHttpOnly, cookie.isSession, cookie.expiry);
cookie.isSecure, cookie.isHttpOnly, cookie.isSession, cookie.expiry, {});
// Check that the cookie service accepted the new cookie.
do_check_eq(Services.cookiemgr.countCookiesFromHost(cookie.host), 1);
@ -189,7 +189,7 @@ function run_test_1(generator)
do_load_profile();
do_check_eq(Services.cookiemgr.countCookiesFromHost("foo.com"), 1);
let enumerator = Services.cookiemgr.getCookiesFromHost(cookie.host);
let enumerator = Services.cookiemgr.getCookiesFromHost(cookie.host, {});
do_check_true(enumerator.hasMoreElements());
let dbcookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
do_check_eq(dbcookie.value, "hallo");

View File

@ -54,7 +54,7 @@ function do_run_test() {
}, Cr.NS_ERROR_NOT_AVAILABLE);
do_check_throws(function() {
Services.cookiemgr.add("foo.com", "", "oh4", "hai", false, false, false, 0);
Services.cookiemgr.add("foo.com", "", "oh4", "hai", false, false, false, 0, {});
}, Cr.NS_ERROR_NOT_AVAILABLE);
do_check_throws(function() {
@ -76,7 +76,7 @@ function do_run_test() {
}, Cr.NS_ERROR_NOT_AVAILABLE);
do_check_throws(function() {
Services.cookies.getCookiesFromHost("foo.com");
Services.cookies.getCookiesFromHost("foo.com", {});
}, Cr.NS_ERROR_NOT_AVAILABLE);
// Wait for the database to finish closing.

View File

@ -68,16 +68,16 @@ function do_run_test()
let shortExpiry = Math.floor(Date.now() / 1000 + 2);
setCookies("captchart.com", 49, futureExpiry);
Services.cookiemgr.add("captchart.com", "", "test100", "eviction",
false, false, false, shortExpiry);
false, false, false, shortExpiry, {});
do_timeout(2100, continue_test);
yield;
do_check_eq(countCookies("captchart.com", "captchart.com"), 50);
Services.cookiemgr.add("captchart.com", "", "test200", "eviction",
false, false, false, futureExpiry);
false, false, false, futureExpiry, {});
do_check_eq(countCookies("captchart.com", "captchart.com"), 50);
enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com");
enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com", {});
while (enumerator.hasMoreElements()) {
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
do_check_true(cookie.expiry == futureExpiry);
@ -92,7 +92,7 @@ setCookies(aHost, aNumber, aExpiry)
{
for (let i = 0; i < aNumber; ++i)
Services.cookiemgr.add(aHost, "", "test" + i, "eviction",
false, false, false, aExpiry);
false, false, false, aExpiry, {});
}
// count how many cookies are within domain 'aBaseDomain', using three
@ -123,7 +123,7 @@ countCookies(aBaseDomain, aHost)
cookies.length);
do_check_eq(Services.cookiemgr.countCookiesFromHost(aHost), cookies.length);
enumerator = Services.cookiemgr.getCookiesFromHost(aHost);
enumerator = Services.cookiemgr.getCookiesFromHost(aHost, {});
while (enumerator.hasMoreElements()) {
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);

View File

@ -199,7 +199,7 @@ function set_cookies(begin, end, expiry)
for (let i = begin; i < end; ++i) {
let host = "eviction." + i + ".tests";
Services.cookiemgr.add(host, "", "test", "eviction", false, false, false,
expiry);
expiry, {});
if (i == begin)
beginTime = get_creationTime(i);
@ -219,7 +219,7 @@ function set_cookies(begin, end, expiry)
function get_creationTime(i)
{
let host = "eviction." + i + ".tests";
let enumerator = Services.cookiemgr.getCookiesFromHost(host);
let enumerator = Services.cookiemgr.getCookiesFromHost(host, {});
do_check_true(enumerator.hasMoreElements());
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
return cookie.creationTime;

View File

@ -88,7 +88,7 @@ function do_run_test() {
// 3) Only one cookie remains, and it's the one with the highest expiration
// time.
do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 1);
let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com");
let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com", {});
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
do_check_eq(cookie.expiry, futureExpiry + 44);

View File

@ -88,7 +88,7 @@ function do_run_test() {
// 3) Only one cookie remains, and it's the one with the highest expiration
// time.
do_check_eq(Services.cookiemgr.countCookiesFromHost("baz.com"), 1);
let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com");
let enumerator = Services.cookiemgr.getCookiesFromHost("baz.com", {});
let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
do_check_eq(cookie.expiry, futureExpiry + 44);
@ -116,7 +116,7 @@ function do_run_test() {
// Test the expected set of cookies.
do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 20);
enumerator = Services.cookiemgr.getCookiesFromHost("cat.com");
enumerator = Services.cookiemgr.getCookiesFromHost("cat.com", {});
cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
do_check_eq(cookie.creationTime, 0);

View File

@ -72,7 +72,6 @@ template <typename Next>
class DownscalingFilter final : public SurfaceFilter
{
public:
uint8_t* AdvanceRow() override { MOZ_CRASH(); return nullptr; }
Maybe<SurfaceInvalidRect> TakeInvalidRect() override { return Nothing(); }
template <typename... Rest>
@ -83,6 +82,7 @@ public:
protected:
uint8_t* DoResetToFirstRow() override { MOZ_CRASH(); return nullptr; }
uint8_t* DoAdvanceRow() override { MOZ_CRASH(); return nullptr; }
};
#else
@ -215,7 +215,19 @@ public:
return invalidRect;
}
uint8_t* AdvanceRow() override
protected:
uint8_t* DoResetToFirstRow() override
{
mNext.ResetToFirstRow();
mInputRow = 0;
mOutputRow = 0;
mRowsInWindow = 0;
return GetRowPointer();
}
uint8_t* DoAdvanceRow() override
{
if (mInputRow >= mInputSize.height) {
NS_WARNING("Advancing DownscalingFilter past the end of the input");
@ -260,18 +272,6 @@ public:
: nullptr;
}
protected:
uint8_t* DoResetToFirstRow() override
{
mNext.ResetToFirstRow();
mInputRow = 0;
mOutputRow = 0;
mRowsInWindow = 0;
return GetRowPointer();
}
private:
uint8_t* GetRowPointer() const { return mRowBuffer.get(); }

View File

@ -119,7 +119,17 @@ public:
return mNext.TakeInvalidRect();
}
uint8_t* AdvanceRow() override
protected:
uint8_t* DoResetToFirstRow() override
{
mNext.ResetToFirstRow();
mPass = 0;
mInputRow = 0;
mOutputRow = InterlaceOffset(mPass);
return GetRowPointer(mOutputRow);
}
uint8_t* DoAdvanceRow() override
{
if (mPass >= 4) {
return nullptr; // We already finished all passes.
@ -147,9 +157,6 @@ public:
while (nextOutputRow >= InputSize().height) {
// Copy any remaining rows from the buffer.
if (!advancedPass) {
DuplicateRows(HaeberliOutputUntilRow(mPass, mProgressiveDisplay,
InputSize(), mOutputRow),
InputSize().height);
OutputRows(HaeberliOutputUntilRow(mPass, mProgressiveDisplay,
InputSize(), mOutputRow),
InputSize().height);
@ -211,16 +218,6 @@ public:
return GetRowPointer(nextHaeberliOutputRow);
}
protected:
uint8_t* DoResetToFirstRow() override
{
mNext.ResetToFirstRow();
mPass = 0;
mInputRow = 0;
mOutputRow = InterlaceOffset(mPass);;
return GetRowPointer(mOutputRow);
}
private:
static uint32_t InterlaceOffset(uint32_t aPass)
{
@ -413,7 +410,53 @@ public:
return mNext.TakeInvalidRect();
}
uint8_t* AdvanceRow() override
protected:
uint8_t* DoResetToFirstRow() override
{
uint8_t* rowPtr = mNext.ResetToFirstRow();
if (rowPtr == nullptr) {
mRow = mFrameRect.YMost();
return nullptr;
}
mRow = mUnclampedFrameRect.y;
// Advance the next pipeline stage to the beginning of the frame rect,
// outputting blank rows.
if (mFrameRect.y > 0) {
int32_t rowsToWrite = mFrameRect.y;
mNext.template WriteRows<uint32_t>([&](uint32_t* aRow, uint32_t aLength)
-> Maybe<WriteState> {
memset(aRow, 0, aLength * sizeof(uint32_t));
rowsToWrite--;
return rowsToWrite > 0 ? Nothing()
: Some(WriteState::NEED_MORE_DATA);
});
}
// We're at the beginning of the frame rect now, so return if we're either
// ready for input or we're already done.
rowPtr = mBuffer ? mBuffer.get() : mNext.CurrentRowPointer();
if (!mFrameRect.IsEmpty() || rowPtr == nullptr) {
// Note that the pointer we're returning is for the next row we're
// actually going to write to, but we may discard writes before that point
// if mRow < mFrameRect.y.
return AdjustRowPointer(rowPtr);
}
// We've finished the region specified by the frame rect, but the frame rect
// is empty, so we need to output the rest of the image immediately. Advance
// to the end of the next pipeline stage's buffer, outputting blank rows.
mNext.template WriteRows<uint32_t>([](uint32_t* aRow, uint32_t aLength) {
memset(aRow, 0, aLength * sizeof(uint32_t));
return Nothing();
});
mRow = mFrameRect.YMost();
return nullptr; // We're done.
}
uint8_t* DoAdvanceRow() override
{
uint8_t* rowPtr = nullptr;
@ -469,59 +512,12 @@ public:
// We've finished the region specified by the frame rect. Advance to the end
// of the next pipeline stage's buffer, outputting blank rows.
mNext.template WriteRows<uint32_t>([&](uint32_t* aRow, uint32_t aLength) {
memset(rowPtr, 0, aLength * sizeof(uint32_t));
return Nothing();
});
return nullptr; // We're done.
}
protected:
uint8_t* DoResetToFirstRow() override
{
uint8_t* rowPtr = mNext.ResetToFirstRow();
if (rowPtr == nullptr) {
mRow = InputSize().height;
return nullptr;
}
mRow = mUnclampedFrameRect.y;
// Advance the next pipeline stage to the beginning of the frame rect,
// outputting blank rows.
if (mFrameRect.y > 0) {
int32_t rowsToWrite = mFrameRect.y;
mNext.template WriteRows<uint32_t>([&](uint32_t* aRow, uint32_t aLength)
-> Maybe<WriteState> {
memset(aRow, 0, aLength * sizeof(uint32_t));
rowsToWrite--;
return rowsToWrite > 0 ? Nothing()
: Some(WriteState::NEED_MORE_DATA);
});
}
// We're at the beginning of the frame rect now, so return if we're either
// ready for input or we're already done.
rowPtr = mBuffer ? mBuffer.get() : mNext.CurrentRowPointer();
if (!mFrameRect.IsEmpty() || rowPtr == nullptr) {
// Note that the pointer we're returning is for the next row we're
// actually going to write to, but we may discard writes before that point
// if mRow < mFrameRect.y.
return AdjustRowPointer(rowPtr);
}
// We've finished the region specified by the frame rect, but the frame rect
// is empty, so we need to output the rest of the image immediately. Advance
// to the end of the next pipeline stage's buffer, outputting blank rows.
int32_t rowsWritten = 0;
mNext.template WriteRows<uint32_t>([&](uint32_t* aRow, uint32_t aLength) {
rowsWritten++;
mNext.template WriteRows<uint32_t>([](uint32_t* aRow, uint32_t aLength) {
memset(aRow, 0, aLength * sizeof(uint32_t));
return Nothing();
});
mRow = InputSize().height;
mRow = mFrameRect.YMost();
return nullptr; // We're done.
}

View File

@ -70,7 +70,7 @@ AbstractSurfaceSink::DoResetToFirstRow()
}
uint8_t*
AbstractSurfaceSink::AdvanceRow()
AbstractSurfaceSink::DoAdvanceRow()
{
if (mRow >= uint32_t(InputSize().height)) {
return nullptr;

View File

@ -119,6 +119,20 @@ public:
return mRowPointer;
}
/**
* Called by WritePixels() and WriteRows() to advance this filter to the next
* row.
*
* @return a pointer to the buffer for the next row, or nullptr to indicate
* that we've finished the entire surface.
*/
uint8_t* AdvanceRow()
{
mCol = 0;
mRowPointer = DoAdvanceRow();
return mRowPointer;
}
/// @return a pointer to the buffer for the current row.
uint8_t* CurrentRowPointer() const { return mRowPointer; }
@ -191,9 +205,7 @@ public:
}
}
// We've finished the row.
mRowPointer = AdvanceRow();
mCol = 0;
AdvanceRow(); // We've finished the row.
}
// We've finished the entire surface.
@ -244,8 +256,7 @@ public:
Maybe<WriteState> result = aFunc(rowPtr, mInputSize.width);
if (result != Some(WriteState::FAILURE)) {
mCol = 0;
mRowPointer = AdvanceRow(); // We've finished the row.
AdvanceRow(); // We've finished the row.
}
if (IsSurfaceFinished()) {
@ -275,15 +286,6 @@ public:
/// @return true if this SurfaceFilter can be used with paletted surfaces.
virtual bool IsValidPalettedPipe() const { return false; }
/**
* Called by WritePixels() and WriteRows() to advance this filter to the next
* row.
*
* @return a pointer to the buffer for the next row, or nullptr to indicate
* that we've finished the entire surface.
*/
virtual uint8_t* AdvanceRow() = 0;
/**
* @return a SurfaceInvalidRect representing the region of the surface that
* has been written to since the last time TakeInvalidRect() was
@ -301,6 +303,14 @@ protected:
*/
virtual uint8_t* DoResetToFirstRow() = 0;
/**
* Called by AdvanceRow() to actually advance this filter to the next row.
*
* @return a pointer to the buffer for the next row, or nullptr to indicate
* that we've finished the entire surface.
*/
virtual uint8_t* DoAdvanceRow() = 0;
//////////////////////////////////////////////////////////////////////////////
// Methods For Internal Use By Subclasses
@ -360,10 +370,10 @@ public:
nsresult Configure(const NullSurfaceConfig& aConfig);
Maybe<SurfaceInvalidRect> TakeInvalidRect() override { return Nothing(); }
uint8_t* AdvanceRow() override { return nullptr; }
protected:
uint8_t* DoResetToFirstRow() override { return nullptr; }
uint8_t* DoAdvanceRow() override { return nullptr; }
private:
static UniquePtr<NullSurfaceSink> sSingleton; /// The singleton instance.
@ -478,10 +488,10 @@ public:
{ }
Maybe<SurfaceInvalidRect> TakeInvalidRect() override final;
uint8_t* AdvanceRow() override final;
protected:
uint8_t* DoResetToFirstRow() override final;
uint8_t* DoAdvanceRow() override final;
virtual uint8_t* GetRowPointer() const = 0;
gfx::IntRect mInvalidRect; /// The region of the surface that has been written

View File

@ -115,34 +115,30 @@ public:
if (downscale) {
if (removeFrameRect) {
if (deinterlace) {
pipe = MakePipe(aFrameRect.Size(), deinterlacingConfig,
removeFrameRectConfig, downscalingConfig,
surfaceConfig);
} else { // (deinterlace is false)
pipe = MakePipe(aFrameRect.Size(), removeFrameRectConfig,
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig,
downscalingConfig, surfaceConfig);
} else { // (deinterlace is false)
pipe = MakePipe(removeFrameRectConfig, downscalingConfig, surfaceConfig);
}
} else { // (removeFrameRect is false)
if (deinterlace) {
pipe = MakePipe(aInputSize, deinterlacingConfig,
downscalingConfig, surfaceConfig);
pipe = MakePipe(deinterlacingConfig, downscalingConfig, surfaceConfig);
} else { // (deinterlace is false)
pipe = MakePipe(aInputSize, downscalingConfig, surfaceConfig);
pipe = MakePipe(downscalingConfig, surfaceConfig);
}
}
} else { // (downscale is false)
if (removeFrameRect) {
if (deinterlace) {
pipe = MakePipe(aFrameRect.Size(), deinterlacingConfig,
removeFrameRectConfig, surfaceConfig);
pipe = MakePipe(deinterlacingConfig, removeFrameRectConfig, surfaceConfig);
} else { // (deinterlace is false)
pipe = MakePipe(aFrameRect.Size(), removeFrameRectConfig, surfaceConfig);
pipe = MakePipe(removeFrameRectConfig, surfaceConfig);
}
} else { // (removeFrameRect is false)
if (deinterlace) {
pipe = MakePipe(aInputSize, deinterlacingConfig, surfaceConfig);
pipe = MakePipe(deinterlacingConfig, surfaceConfig);
} else { // (deinterlace is false)
pipe = MakePipe(aInputSize, surfaceConfig);
pipe = MakePipe(surfaceConfig);
}
}
}
@ -195,10 +191,9 @@ public:
Maybe<SurfacePipe> pipe;
if (deinterlace) {
pipe = MakePipe(aFrameRect.Size(), deinterlacingConfig,
palettedSurfaceConfig);
pipe = MakePipe(deinterlacingConfig, palettedSurfaceConfig);
} else {
pipe = MakePipe(aFrameRect.Size(), palettedSurfaceConfig);
pipe = MakePipe(palettedSurfaceConfig);
}
return pipe;
@ -207,7 +202,7 @@ public:
private:
template <typename... Configs>
static Maybe<SurfacePipe>
MakePipe(const nsIntSize& aInputSize, Configs... aConfigs)
MakePipe(Configs... aConfigs)
{
auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
nsresult rv = pipe->Configure(aConfigs...);

View File

@ -76,11 +76,11 @@ nsIconDecoder::ReadHeader(const char* aData)
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
IntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize();
IntRect targetFrameRect(IntPoint(0, 0), targetSize);
IntRect frameRect(IntPoint(0, 0), GetSize());
Maybe<SurfacePipe> pipe =
SurfacePipeFactory::CreateSurfacePipe(this, 0, GetSize(), targetSize,
targetFrameRect, SurfaceFormat::B8G8R8A8,
frameRect, SurfaceFormat::B8G8R8A8,
SurfacePipeFlags());
if (!pipe) {
return Transition::TerminateFailure();

View File

@ -195,6 +195,112 @@ TEST(ImageDeinterlacingFilter, PalettedWriteRows)
});
}
TEST(ImageDeinterlacingFilter, WritePixelsNonProgressiveOutput51_52)
{
WithDeinterlacingFilter(IntSize(51, 52), /* aProgressiveDisplay = */ false,
[](Decoder* aDecoder, SurfaceFilter* aFilter) {
// Fill the image. The output should be green for even rows and red for odd
// rows but we need to write the rows in the order that the deinterlacer
// expects them.
uint32_t count = 0;
auto result = aFilter->WritePixels<uint32_t>([&]() {
uint32_t row = count / 51; // Integer division.
++count;
// Note that we use a switch statement here, even though it's quite
// verbose, because it's useful to have the mappings between input and
// output rows available when debugging these tests.
switch (row) {
// First pass. Output rows are positioned at 8n + 0.
case 0: // Output row 0.
case 1: // Output row 8.
case 2: // Output row 16.
case 3: // Output row 24.
case 4: // Output row 32.
case 5: // Output row 40.
case 6: // Output row 48.
return AsVariant(BGRAColor::Green().AsPixel());
// Second pass. Rows are positioned at 8n + 4.
case 7: // Output row 4.
case 8: // Output row 12.
case 9: // Output row 20.
case 10: // Output row 28.
case 11: // Output row 36.
case 12: // Output row 44.
return AsVariant(BGRAColor::Green().AsPixel());
// Third pass. Rows are positioned at 4n + 2.
case 13: // Output row 2.
case 14: // Output row 6.
case 15: // Output row 10.
case 16: // Output row 14.
case 17: // Output row 18.
case 18: // Output row 22.
case 19: // Output row 26.
case 20: // Output row 30.
case 21: // Output row 34.
case 22: // Output row 38.
case 23: // Output row 42.
case 24: // Output row 46.
case 25: // Output row 50.
return AsVariant(BGRAColor::Green().AsPixel());
// Fourth pass. Rows are positioned at 2n + 1.
case 26: // Output row 1.
case 27: // Output row 3.
case 28: // Output row 5.
case 29: // Output row 7.
case 30: // Output row 9.
case 31: // Output row 11.
case 32: // Output row 13.
case 33: // Output row 15.
case 34: // Output row 17.
case 35: // Output row 19.
case 36: // Output row 21.
case 37: // Output row 23.
case 38: // Output row 25.
case 39: // Output row 27.
case 40: // Output row 29.
case 41: // Output row 31.
case 42: // Output row 33.
case 43: // Output row 35.
case 44: // Output row 37.
case 45: // Output row 39.
case 46: // Output row 41.
case 47: // Output row 43.
case 48: // Output row 45.
case 49: // Output row 47.
case 50: // Output row 49.
case 51: // Output row 51.
return AsVariant(BGRAColor::Red().AsPixel());
default:
MOZ_ASSERT_UNREACHABLE("Unexpected row");
return AsVariant(BGRAColor::Transparent().AsPixel());
}
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(51u * 52u, count);
AssertCorrectPipelineFinalState(aFilter,
IntRect(0, 0, 51, 52),
IntRect(0, 0, 51, 52));
// Check that the generated image is correct. As mentioned above, we expect
// even rows to be green and odd rows to be red.
RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
RefPtr<SourceSurface> surface = currentFrame->GetSurface();
for (uint32_t row = 0; row < 52; ++row) {
EXPECT_TRUE(RowsAreSolidColor(surface, row, 1,
row % 2 == 0 ? BGRAColor::Green()
: BGRAColor::Red()));
}
});
}
TEST(ImageDeinterlacingFilter, WritePixelsOutput20_20)
{
WithDeinterlacingFilter(IntSize(20, 20), /* aProgressiveDisplay = */ true,
@ -207,6 +313,10 @@ TEST(ImageDeinterlacingFilter, WritePixelsOutput20_20)
uint32_t row = count / 20; // Integer division.
++count;
// Note that we use a switch statement here, even though it's quite
// verbose, because it's useful to have the mappings between input and
// output rows available when debugging these tests.
switch (row) {
// First pass. Output rows are positioned at 8n + 0.
case 0: // Output row 0.
@ -276,6 +386,7 @@ TEST(ImageDeinterlacingFilter, WriteRowsOutput7_7)
uint32_t row = 0;
auto result = aFilter->WriteRows<uint32_t>([&](uint32_t* aRow, uint32_t aLength) {
uint32_t color = 0;
switch (row) {
// First pass. Output rows are positioned at 8n + 0.
case 0: // Output row 0.

View File

@ -124,8 +124,20 @@ TEST(ImageSurfacePipeIntegration, DeinterlaceDownscaleWriteRows)
SurfaceFormat::B8G8R8A8, false });
}
TEST(ImageSurfacePipeIntegration, RemoveFrameRectDownscaleWritePixels)
TEST(ImageSurfacePipeIntegration, RemoveFrameRectBottomRightDownscaleWritePixels)
{
// This test case uses a frame rect that extends beyond the borders of the
// image to the bottom and to the right. It looks roughly like this (with the
// box made of '#'s representing the frame rect):
//
// +------------+
// + +
// + +------------+
// + +############+
// +------+############+
// +############+
// +------------+
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(decoder != nullptr);
@ -168,7 +180,7 @@ TEST(ImageSurfacePipeIntegration, RemoveFrameRectDownscaleWritePixels)
SurfaceFormat::B8G8R8A8, false });
}
TEST(ImageSurfacePipeIntegration, RemoveFrameRectDownscaleWriteRows)
TEST(ImageSurfacePipeIntegration, RemoveFrameRectBottomRightDownscaleWriteRows)
{
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(decoder != nullptr);
@ -193,6 +205,63 @@ TEST(ImageSurfacePipeIntegration, RemoveFrameRectDownscaleWriteRows)
SurfaceFormat::B8G8R8A8, false });
}
TEST(ImageSurfacePipeIntegration, RemoveFrameRectTopLeftDownscaleWritePixels)
{
// This test case uses a frame rect that extends beyond the borders of the
// image to the top and to the left. It looks roughly like this (with the
// box made of '#'s representing the frame rect):
//
// +------------+
// +############+
// +############+------+
// +############+ +
// +------------+ +
// + +
// +------------+
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(decoder != nullptr);
auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
CheckWritePixels(aDecoder, aFilter,
/* aOutputRect = */ Some(IntRect(0, 0, 20, 20)),
/* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
/* aInputWriteRect = */ Some(IntRect(0, 0, 100, 100)),
/* aOutputWriteRect = */ Some(IntRect(0, 0, 10, 10)),
/* aFuzz = */ 0x21);
};
WithFilterPipeline(decoder, test,
RemoveFrameRectConfig { IntRect(-50, -50, 100, 100) },
DownscalingConfig { IntSize(100, 100),
SurfaceFormat::B8G8R8A8 },
SurfaceConfig { decoder, 0, IntSize(20, 20),
SurfaceFormat::B8G8R8A8, false });
}
TEST(ImageSurfacePipeIntegration, RemoveFrameRectTopLeftDownscaleWriteRows)
{
RefPtr<Decoder> decoder = CreateTrivialDecoder();
ASSERT_TRUE(decoder != nullptr);
auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
CheckWriteRows(aDecoder, aFilter,
/* aOutputRect = */ Some(IntRect(0, 0, 20, 20)),
/* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
/* aInputWriteRect = */ Some(IntRect(0, 0, 100, 100)),
/* aOutputWriteRect = */ Some(IntRect(0, 0, 10, 10)),
/* aFuzz = */ 0x21);
};
WithFilterPipeline(decoder, test,
RemoveFrameRectConfig { IntRect(-50, -50, 100, 100) },
DownscalingConfig { IntSize(100, 100),
SurfaceFormat::B8G8R8A8 },
SurfaceConfig { decoder, 0, IntSize(20, 20),
SurfaceFormat::B8G8R8A8, false });
}
TEST(ImageSurfacePipeIntegration, DeinterlaceRemoveFrameRectWritePixels)
{
RefPtr<Decoder> decoder = CreateTrivialDecoder();

View File

@ -492,22 +492,24 @@ GeckoChildProcessHost::DissociateActor()
int32_t GeckoChildProcessHost::mChildCounter = 0;
void
GeckoChildProcessHost::SetChildLogName(const char* varName, const char* origLogName)
GeckoChildProcessHost::SetChildLogName(const char* varName, const char* origLogName,
nsACString &buffer)
{
// We currently have no portable way to launch child with environment
// different than parent. So temporarily change NSPR_LOG_FILE so child
// inherits value we want it to have. (NSPR only looks at NSPR_LOG_FILE at
// startup, so it's 'safe' to play with the parent's environment this way.)
nsAutoCString setChildLogName(varName);
setChildLogName.Append(origLogName);
buffer.Assign(varName);
buffer.Append(origLogName);
// Append child-specific postfix to name
setChildLogName.AppendLiteral(".child-");
setChildLogName.AppendInt(mChildCounter);
buffer.AppendLiteral(".child-");
buffer.AppendInt(mChildCounter);
// Passing temporary to PR_SetEnv is ok here because env gets copied
// by exec, etc., to permanent storage in child when process launched.
PR_SetEnv(setChildLogName.get());
// Passing temporary to PR_SetEnv is ok here if we keep the temporary
// for the time we launch the sub-process. It's copied to the new
// environment.
PR_SetEnv(buffer.BeginReading());
}
bool
@ -528,19 +530,24 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, b
static nsAutoCString restoreOrigNSPRLogName;
static nsAutoCString restoreOrigMozLogName;
// Must keep these on the same stack where from we call PerformAsyncLaunchInternal
// so that PR_DuplicateEnvironment() still sees a valid memory.
nsAutoCString nsprLogName;
nsAutoCString mozLogName;
if (origNSPRLogName) {
if (restoreOrigNSPRLogName.IsEmpty()) {
restoreOrigNSPRLogName.AssignLiteral("NSPR_LOG_FILE=");
restoreOrigNSPRLogName.Append(origNSPRLogName);
}
SetChildLogName("NSPR_LOG_FILE=", origNSPRLogName);
SetChildLogName("NSPR_LOG_FILE=", origNSPRLogName, nsprLogName);
}
if (origMozLogName) {
if (restoreOrigMozLogName.IsEmpty()) {
restoreOrigMozLogName.AssignLiteral("MOZ_LOG_FILE=");
restoreOrigMozLogName.Append(origMozLogName);
}
SetChildLogName("MOZ_LOG_FILE=", origMozLogName);
SetChildLogName("MOZ_LOG_FILE=", origMozLogName, mozLogName);
}
bool retval = PerformAsyncLaunchInternal(aExtraOpts, arch);

View File

@ -200,7 +200,10 @@ private:
static void GetPathToBinary(FilePath& exePath);
void SetChildLogName(const char* varName, const char* origLogName);
// The buffer is passed to preserve its lifetime until we are done
// with launching the sub-process.
void SetChildLogName(const char* varName, const char* origLogName,
nsACString &buffer);
// In between launching the subprocess and handing off its IPC
// channel, there's a small window of time in which *we* might still

View File

@ -1730,11 +1730,12 @@ ParseFloatLiteral(WasmParseContext& c, WasmToken token, Float* result)
// Call into JS' strtod. Tokenization has already required that the
// string is well-behaved.
LifoAlloc::Mark mark = c.lifo.mark();
char* buffer = c.lifo.newArray<char>(end - begin + 1);
char* buffer = c.lifo.newArray<char>(end - cur + 1);
if (!buffer)
return false;
for (ptrdiff_t i = 0; i < end - cur; ++i)
buffer[i] = char(cur[i]);
buffer[end - cur] = '\0';
char* strtod_end;
int err;
Float d = (Float)js_strtod_harder(c.dtoaState, buffer, &strtod_end, &err);

View File

@ -14,6 +14,7 @@
#include "gc/Heap.h"
#include "js/Date.h"
#include "js/Debug.h"
#include "vm/SelfHosting.h"
#include "jsobjinlines.h"
@ -40,7 +41,39 @@ static const JSPropertySpec promise_static_properties[] = {
JS_PS_END
};
// ES6, 25.4.3.1. steps 3-11.
static Value
Now()
{
return JS::TimeValue(JS::TimeClip(static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_MSEC));
}
static bool
CreateResolvingFunctions(JSContext* cx, HandleValue promise,
MutableHandleValue resolveVal,
MutableHandleValue rejectVal)
{
FixedInvokeArgs<1> args(cx);
args[0].set(promise);
RootedValue rval(cx);
if (!CallSelfHostedFunction(cx, cx->names().CreateResolvingFunctions, UndefinedHandleValue,
args, &rval))
{
return false;
}
RootedArrayObject resolvingFunctions(cx, &args.rval().toObject().as<ArrayObject>());
resolveVal.set(resolvingFunctions->getDenseElement(0));
rejectVal.set(resolvingFunctions->getDenseElement(1));
MOZ_ASSERT(IsCallable(resolveVal));
MOZ_ASSERT(IsCallable(rejectVal));
return true;
}
// ES2016, February 12 draft, 25.4.3.1. steps 3-11.
PromiseObject*
PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
{
@ -73,33 +106,38 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
ac.emplace(cx, usedProto);
promise = &NewObjectWithClassProto(cx, &class_, usedProto)->as<PromiseObject>();
// Step 4.
if (!promise)
return nullptr;
// Step 5.
// Step 4.
promise->setFixedSlot(PROMISE_STATE_SLOT, Int32Value(PROMISE_STATE_PENDING));
// Step 6.
// Step 5.
RootedArrayObject reactions(cx, NewDenseEmptyArray(cx));
if (!reactions)
return nullptr;
promise->setFixedSlot(PROMISE_FULFILL_REACTIONS_SLOT, ObjectValue(*reactions));
// Step 7.
// Step 6.
reactions = NewDenseEmptyArray(cx);
if (!reactions)
return nullptr;
promise->setFixedSlot(PROMISE_REJECT_REACTIONS_SLOT, ObjectValue(*reactions));
// Step 7.
promise->setFixedSlot(PROMISE_IS_HANDLED_SLOT,
Int32Value(PROMISE_IS_HANDLED_STATE_UNHANDLED));
// Store an allocation stack so we can later figure out what the
// control flow was for some unexpected results. Frightfully expensive,
// but oh well.
RootedObject stack(cx);
if (!JS::CaptureCurrentStack(cx, &stack, 0))
return nullptr;
promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectValue(*stack));
Value now = JS::TimeValue(JS::TimeClip(static_cast<double>(PRMJ_Now()) /
PRMJ_USEC_PER_MSEC));
promise->setFixedSlot(PROMISE_ALLOCATION_TIME_SLOT, now);
if (cx->runtime()->options().asyncStack() || cx->compartment()->isDebuggee()) {
if (!JS::CaptureCurrentStack(cx, &stack, 0))
return nullptr;
}
promise->setFixedSlot(PROMISE_ALLOCATION_SITE_SLOT, ObjectOrNullValue(stack));
promise->setFixedSlot(PROMISE_ALLOCATION_TIME_SLOT, Now());
}
RootedValue promiseVal(cx, ObjectValue(*promise));
@ -110,30 +148,10 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
// The resolving functions are created in the compartment active when the
// (maybe wrapped) Promise constructor was called. They contain checks and
// can unwrap the Promise if required.
RootedValue resolvingFunctionsVal(cx);
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), cx->names().CreateResolvingFunctions,
&resolvingFunctionsVal))
{
RootedValue resolveVal(cx);
RootedValue rejectVal(cx);
if (!CreateResolvingFunctions(cx, promiseVal, &resolveVal, &rejectVal))
return nullptr;
}
RootedArrayObject resolvingFunctions(cx);
{
FixedInvokeArgs<1> args(cx);
args[0].set(promiseVal);
RootedValue rval(cx);
if (!Call(cx, resolvingFunctionsVal, UndefinedHandleValue, args, &rval))
return nullptr;
resolvingFunctions = &rval.toObject().as<ArrayObject>();
}
RootedValue resolveVal(cx, resolvingFunctions->getDenseElement(0));
MOZ_ASSERT(IsCallable(resolveVal));
RootedValue rejectVal(cx, resolvingFunctions->getDenseElement(1));
MOZ_ASSERT(IsCallable(rejectVal));
// Need to wrap the resolution functions before storing them on the Promise.
if (wrappedProto) {
@ -181,6 +199,7 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
return nullptr;
}
// Let the Debugger know about this Promise.
JS::dbg::onNewPromise(cx, promise);
// Step 11.
@ -192,7 +211,7 @@ namespace {
mozilla::Atomic<uint64_t> gIDGenerator(0);
} // namespace
double
uint64_t
PromiseObject::getID()
{
Value idVal(getReservedSlot(PROMISE_ID_SLOT));
@ -200,7 +219,7 @@ PromiseObject::getID()
idVal.setDouble(++gIDGenerator);
setReservedSlot(PROMISE_ID_SLOT, idVal);
}
return idVal.toNumber();
return uint64_t(idVal.toNumber());
}
/**
@ -391,6 +410,124 @@ PromiseObject::reject(JSContext* cx, HandleValue rejectionValue)
return Call(cx, funVal, UndefinedHandleValue, args, &dummy);
}
void PromiseObject::onSettled(JSContext* cx)
{
Rooted<PromiseObject*> promise(cx, this);
RootedObject stack(cx);
if (cx->runtime()->options().asyncStack() || cx->compartment()->isDebuggee()) {
if (!JS::CaptureCurrentStack(cx, &stack, 0)) {
cx->clearPendingException();
return;
}
}
promise->setFixedSlot(PROMISE_RESOLUTION_SITE_SLOT, ObjectOrNullValue(stack));
promise->setFixedSlot(PROMISE_RESOLUTION_TIME_SLOT, Now());
if (promise->state() == JS::PromiseState::Rejected &&
promise->getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() !=
PROMISE_IS_HANDLED_STATE_HANDLED)
{
cx->runtime()->addUnhandledRejectedPromise(cx, promise);
}
JS::dbg::onPromiseSettled(cx, promise);
}
// ES6, 25.4.2.1.
bool
PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction job(cx, &args.callee().as<JSFunction>());
RootedNativeObject jobArgs(cx, &job->getExtendedSlot(0).toObject().as<NativeObject>());
RootedValue argument(cx, jobArgs->getDenseElement(1));
// Step 1 (omitted).
// Steps 2-3.
RootedValue handlerVal(cx, jobArgs->getDenseElement(0));
RootedValue handlerResult(cx);
bool shouldReject = false;
// Steps 4-7.
if (handlerVal.isNumber()) {
int32_t handlerNum = int32_t(handlerVal.toNumber());
// Step 4.
if (handlerNum == PROMISE_HANDLER_IDENTITY) {
handlerResult = argument;
} else {
// Step 5.
MOZ_ASSERT(handlerNum == PROMISE_HANDLER_THROWER);
shouldReject = true;
handlerResult = argument;
}
} else {
// Step 6.
FixedInvokeArgs<1> args2(cx);
args2[0].set(argument);
if (!Call(cx, handlerVal, UndefinedHandleValue, args2, &handlerResult)) {
shouldReject = true;
// Not much we can do about uncatchable exceptions, so just bail
// for those.
if (!cx->isExceptionPending() || !GetAndClearException(cx, &handlerResult))
return false;
}
}
// Steps 7-9.
FixedInvokeArgs<1> args2(cx);
args2[0].set(handlerResult);
RootedValue calleeOrRval(cx);
if (shouldReject) {
calleeOrRval = jobArgs->getDenseElement(3);
} else {
calleeOrRval = jobArgs->getDenseElement(2);
}
bool result = Call(cx, calleeOrRval, UndefinedHandleValue, args2, &calleeOrRval);
args.rval().set(calleeOrRval);
return result;
}
// ES6, 25.4.2.2.
bool
PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction job(cx, &args.callee().as<JSFunction>());
RootedNativeObject jobArgs(cx, &job->getExtendedSlot(0).toObject().as<NativeObject>());
RootedValue promise(cx, jobArgs->getDenseElement(2));
RootedValue then(cx, jobArgs->getDenseElement(0));
RootedValue thenable(cx, jobArgs->getDenseElement(1));
// Step 1.
RootedValue resolveVal(cx);
RootedValue rejectVal(cx);
if (!CreateResolvingFunctions(cx, promise, &resolveVal, &rejectVal))
return false;
// Step 2.
FixedInvokeArgs<2> args2(cx);
args2[0].set(resolveVal);
args2[1].set(rejectVal);
RootedValue rval(cx);
// In difference to the usual pattern, we return immediately on success.
if (Call(cx, then, thenable, args2, &rval))
return true;
if (!GetAndClearException(cx, &rval))
return false;
FixedInvokeArgs<1> rejectArgs(cx);
rejectArgs[0].set(rval);
return Call(cx, rejectVal, UndefinedHandleValue, rejectArgs, &rval);
}
} // namespace js
static JSObject*

View File

@ -19,7 +19,7 @@ class AutoSetNewObjectMetadata;
class PromiseObject : public NativeObject
{
public:
static const unsigned RESERVED_SLOTS = 11;
static const unsigned RESERVED_SLOTS = 12;
static const Class class_;
static const Class protoClass_;
static PromiseObject* create(JSContext* cx, HandleObject executor,
@ -42,10 +42,16 @@ class PromiseObject : public NativeObject
MOZ_MUST_USE bool resolve(JSContext* cx, HandleValue resolutionValue);
MOZ_MUST_USE bool reject(JSContext* cx, HandleValue rejectionValue);
void onSettled(JSContext* cx);
double allocationTime() { return getFixedSlot(PROMISE_ALLOCATION_TIME_SLOT).toNumber(); }
double resolutionTime() { return getFixedSlot(PROMISE_RESOLUTION_TIME_SLOT).toNumber(); }
JSObject* allocationSite() { return &getFixedSlot(PROMISE_ALLOCATION_SITE_SLOT).toObject(); }
JSObject* resolutionSite() { return &getFixedSlot(PROMISE_RESOLUTION_SITE_SLOT).toObject(); }
JSObject* allocationSite() {
return getFixedSlot(PROMISE_ALLOCATION_SITE_SLOT).toObjectOrNull();
}
JSObject* resolutionSite() {
return getFixedSlot(PROMISE_RESOLUTION_SITE_SLOT).toObjectOrNull();
}
double lifetime() {
double now = JS::TimeClip(static_cast<double>(PRMJ_Now()) / PRMJ_USEC_PER_MSEC).toDouble();
return now - allocationTime();
@ -55,9 +61,23 @@ class PromiseObject : public NativeObject
return resolutionTime() - allocationTime();
}
MOZ_MUST_USE bool dependentPromises(JSContext* cx, MutableHandle<GCVector<Value>> values);
double getID();
uint64_t getID();
bool markedAsUncaught() {
return getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() != PROMISE_IS_HANDLED_STATE_HANDLED;
}
void markAsReported() {
MOZ_ASSERT(getFixedSlot(PROMISE_IS_HANDLED_SLOT).toInt32() ==
PROMISE_IS_HANDLED_STATE_UNHANDLED);
setFixedSlot(PROMISE_IS_HANDLED_SLOT, Int32Value(PROMISE_IS_HANDLED_STATE_REPORTED));
}
};
// ES6, 25.4.2.1.
bool PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp);
// ES6, 25.4.2.2.
bool PromiseResolveThenableJob(JSContext* cx, unsigned argc, Value* vp);
} // namespace js
#endif /* builtin_Promise_h */

View File

@ -124,6 +124,7 @@ function FulfillUnwrappedPromise(value) {
}
// Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
// ES2016 February 12 draft.
function ResolvePromise(promise, valueOrReason, reactionsSlot, state) {
// Step 1.
assert(GetPromiseState(promise) === PROMISE_STATE_PENDING,
@ -151,12 +152,11 @@ function ResolvePromise(promise, valueOrReason, reactionsSlot, state) {
UnsafeSetReservedSlot(promise, PROMISE_REJECT_FUNCTION_SLOT, null);
// Now that everything else is done, do the things the debugger needs.
let site = _dbg_captureCurrentStack(0);
UnsafeSetReservedSlot(promise, PROMISE_RESOLUTION_SITE_SLOT, site);
UnsafeSetReservedSlot(promise, PROMISE_RESOLUTION_TIME_SLOT, std_Date_now());
// Step 7 of RejectPromise implemented in the debugger intrinsic.
_dbg_onPromiseSettled(promise);
// Step 7.
// Step 7 of FulfillPromise.
// Step 8 of RejectPromise.
return TriggerPromiseReactions(reactions, valueOrReason);
}
@ -209,7 +209,7 @@ function NewPromiseCapability(C) {
// ES6, 25.4.1.6. is implemented as an intrinsic in SelfHosting.cpp.
// ES6, 25.4.1.7.
// ES2016, February 12 draft, 25.4.1.7.
function RejectPromise(promise, reason) {
return ResolvePromise(promise, reason, PROMISE_REJECT_REACTIONS_SLOT, PROMISE_STATE_REJECTED);
}
@ -222,66 +222,26 @@ function TriggerPromiseReactions(reactions, argument) {
// Step 2 (implicit).
}
// ES2016, February 12 draft 25.4.1.9, implemented in SelfHosting.cpp.
// ES6, 25.4.2.1.
function EnqueuePromiseReactionJob(reaction, argument) {
_EnqueuePromiseJob(function PromiseReactionJob() {
// Step 1.
assert(IsPromiseReaction(reaction), "Invalid promise reaction record");
// Step 2.
let promiseCapability = reaction.capabilities;
// Step 3.
let handler = reaction.handler;
let handlerResult = argument;
let shouldReject = false;
// Steps 4-6.
if (handler === PROMISE_HANDLER_IDENTITY) {
// handlerResult = argument; (implicit)
} else if (handler === PROMISE_HANDLER_THROWER) {
// handlerResult = argument; (implicit)
shouldReject = true;
} else {
try {
handlerResult = callContentFunction(handler, undefined, argument);
} catch (e) {
handlerResult = e;
shouldReject = true;
}
}
// Step 7.
if (shouldReject) {
// Step 7.a.
callContentFunction(promiseCapability.reject, undefined, handlerResult);
// Step 7.b.
return;
}
// Steps 8-9.
return callContentFunction(promiseCapability.resolve, undefined, handlerResult);
});
let capabilities = reaction.capabilities;
_EnqueuePromiseReactionJob([reaction.handler,
argument,
capabilities.resolve,
capabilities.reject
],
capabilities.promise);
}
// ES6, 25.4.2.2.
function EnqueuePromiseResolveThenableJob(promiseToResolve, thenable, then) {
_EnqueuePromiseJob(function PromiseResolveThenableJob() {
// Step 1.
let {0: resolve, 1: reject} = CreateResolvingFunctions(promiseToResolve);
// Steps 2-3.
try {
// Step 2.
callContentFunction(then, thenable, resolve, reject);
} catch (thenCallResult) {
// Steps 3.a-b.
callFunction(reject, undefined, thenCallResult);
}
// Step 4 (implicit, no need to return anything).
});
_EnqueuePromiseResolveThenableJob([then,
thenable,
promiseToResolve
],
promiseToResolve);
}
// ES6, 25.4.3.1. (Implemented in C++).
@ -901,7 +861,7 @@ function UnwrappedPerformPromiseThen(fulfilledHandler, rejectedHandler, promise,
resultCapability);
}
// ES6, 25.4.5.3.1.
// ES2016, March 1, 2016 draft, 25.4.5.3.1.
function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability) {
// Step 1.
assert(IsPromise(promise), "Can't call PerformPromiseThen on non-Promise objects");
@ -955,15 +915,28 @@ function PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability)
}
// Step 9.
else if (state === PROMISE_STATE_REJECTED) {
else {
// Step 9.a.
let reason = UnsafeGetReservedSlot(promise, PROMISE_RESULT_SLOT);
assert(state === PROMISE_STATE_REJECTED, "Invalid Promise state " + state);
// Step 9.b.
let reason = UnsafeGetReservedSlot(promise, PROMISE_RESULT_SLOT);
// Step 9.c.
if (UnsafeGetInt32FromReservedSlot(promise, PROMISE_IS_HANDLED_SLOT) !==
PROMISE_IS_HANDLED_STATE_HANDLED)
{
HostPromiseRejectionTracker(promise, PROMISE_REJECTION_TRACKER_OPERATION_HANDLE);
}
// Step 9.d.
EnqueuePromiseReactionJob(rejectReaction, reason);
}
// Step 10.
UnsafeSetReservedSlot(promise, PROMISE_IS_HANDLED_SLOT, PROMISE_IS_HANDLED_STATE_HANDLED);
// Step 11.
return resultCapability.promise;
}

View File

@ -68,14 +68,22 @@
#define PROMISE_ALLOCATION_TIME_SLOT 8
#define PROMISE_RESOLUTION_TIME_SLOT 9
#define PROMISE_ID_SLOT 10
#define PROMISE_IS_HANDLED_SLOT 11
#define PROMISE_STATE_PENDING 0
#define PROMISE_STATE_FULFILLED 1
#define PROMISE_STATE_REJECTED 2
#define PROMISE_IS_HANDLED_STATE_HANDLED 0
#define PROMISE_IS_HANDLED_STATE_UNHANDLED 1
#define PROMISE_IS_HANDLED_STATE_REPORTED 2
#define PROMISE_HANDLER_IDENTITY 0
#define PROMISE_HANDLER_THROWER 1
#define PROMISE_REJECTION_TRACKER_OPERATION_REJECT false
#define PROMISE_REJECTION_TRACKER_OPERATION_HANDLE true
// NB: keep these in sync with the copy in jsfriendapi.h.
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */

View File

@ -853,9 +853,10 @@ class GCRuntime
bool isVerifyPreBarriersEnabled() const { return false; }
#endif
// Free certain LifoAlloc blocks from the background sweep thread.
// Free certain LifoAlloc blocks when it is safe to do so.
void freeUnusedLifoBlocksAfterSweeping(LifoAlloc* lifo);
void freeAllLifoBlocksAfterSweeping(LifoAlloc* lifo);
void freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo);
// Public here for ReleaseArenaLists and FinalizeTypedArenas.
void releaseArena(Arena* arena, const AutoLockGC& lock);
@ -1169,9 +1170,15 @@ class GCRuntime
/*
* Free LIFO blocks are transferred to this allocator before being freed on
* the background GC thread.
* the background GC thread after sweeping.
*/
LifoAlloc freeLifoAlloc;
LifoAlloc blocksToFreeAfterSweeping;
/*
* Free LIFO blocks are transferred to this allocator before being freed
* after minor GC.
*/
LifoAlloc blocksToFreeAfterMinorGC;
/* Index of current zone group (for stats). */
unsigned zoneGroupIndex;

View File

@ -219,12 +219,6 @@ Zone::discardJitCode(FreeOp* fop)
/* Only mark OSI points if code is being discarded. */
jit::InvalidateAll(fop, this);
/* The storebuffer may contain pointers into data owned by BaselineScript. */
JSRuntime* rt = runtimeFromMainThread();
if (!rt->isHeapCollecting())
rt->gc.evictNursery();
MOZ_ASSERT(rt->gc.nursery.isEmpty());
for (ZoneCellIter i(this, AllocKind::SCRIPT); !i.done(); i.next()) {
JSScript* script = i.get<JSScript>();
jit::FinishInvalidation(fop, script);
@ -243,7 +237,15 @@ Zone::discardJitCode(FreeOp* fop)
script->resetWarmUpCounter();
}
jitZone()->optimizedStubSpace()->free();
/*
* When scripts contains pointers to nursery things, the store buffer
* can contain entries that point into the optimized stub space. Since
* this method can be called outside the context of a GC, this situation
* could result in us trying to mark invalid store buffer entries.
*
* Defer freeing any allocated blocks until after the next minor GC.
*/
jitZone()->optimizedStubSpace()->freeAllAfterMinorGC(fop->runtime());
}
}

View File

@ -0,0 +1,13 @@
options("strict", "werror");
var o = {};
var failureCode = 0;
try {
// Don't throw here.
if (o.a || o.b)
failureCode = 1;
} catch (e) {
failureCode = 2
}
assertEq(failureCode, 0);

View File

@ -0,0 +1,36 @@
if (typeof Promise === "undefined")
quit(0);
let g = newGlobal();
let dbg = new Debugger();
let gw = dbg.addDebuggee(g);
g.promise = Promise.resolve(42);
let promiseDO = gw.getOwnPropertyDescriptor('promise').value;
assertEq(promiseDO.isPromise, true);
let state = promiseDO.promiseState;
assertEq(state.state, "fulfilled");
assertEq(state.value, 42);
assertEq("reason" in state, true);
assertEq(state.reason, undefined);
let allocationSite = promiseDO.promiseAllocationSite;
// Depending on whether async stacks are activated, this can be null, which
// has typeof null.
assertEq(typeof allocationSite === "object", true);
let resolutionSite = promiseDO.promiseResolutionSite;
// Depending on whether async stacks are activated, this can be null, which
// has typeof null.
assertEq(typeof resolutionSite === "object", true);
assertEq(promiseDO.promiseID, 1);
assertEq(typeof promiseDO.promiseDependentPromises, "object");
assertEq(promiseDO.promiseDependentPromises.length, 0);
assertEq(typeof promiseDO.promiseLifetime, "number");
assertEq(typeof promiseDO.promiseTimeToResolution, "number");

View File

@ -208,7 +208,8 @@ BaselineCompiler::compile()
pcMappingIndexEntries.length(),
pcEntries.length(),
bytecodeTypeMapEntries,
yieldOffsets_.length()));
yieldOffsets_.length()),
JS::DeletePolicy<BaselineScript>(cx->runtime()));
if (!baselineScript) {
ReportOutOfMemory(cx);
return Method_Error;

View File

@ -871,9 +871,6 @@ jit::RecompileOnStackBaselineScriptsForDebugMode(JSContext* cx,
if (entries.empty())
return true;
// Scripts can entrain nursery things. See note in js::ReleaseAllJITCode.
cx->runtime()->gc.evictNursery();
// When the profiler is enabled, we need to have suppressed sampling,
// since the basline jit scripts are in a state of flux.
MOZ_ASSERT(!cx->runtime()->isProfilerSamplingEnabled());

View File

@ -45,6 +45,12 @@ PCMappingSlotInfo::ToSlotLocation(const StackValue* stackVal)
return SlotIgnore;
}
void
ICStubSpace::freeAllAfterMinorGC(JSRuntime* rt)
{
rt->gc.freeAllLifoBlocksAfterMinorGC(&allocator_);
}
BaselineScript::BaselineScript(uint32_t prologueOffset, uint32_t epilogueOffset,
uint32_t profilerEnterToggleOffset,
uint32_t profilerExitToggleOffset,
@ -482,22 +488,29 @@ BaselineScript::Trace(JSTracer* trc, BaselineScript* script)
void
BaselineScript::Destroy(FreeOp* fop, BaselineScript* script)
{
/*
* When the script contains pointers to nursery things, the store buffer
* will contain entries refering to the referenced things. Since we can
* destroy scripts outside the context of a GC, this situation can result
* in invalid store buffer entries. Assert that if we do destroy scripts
* outside of a GC that we at least emptied the nursery first.
*/
MOZ_ASSERT(fop->runtime()->gc.nursery.isEmpty());
MOZ_ASSERT(!script->hasPendingIonBuilder());
script->unlinkDependentWasmModules(fop);
/*
* When the script contains pointers to nursery things, the store buffer can
* contain entries that point into the fallback stub space. Since we can
* destroy scripts outside the context of a GC, this situation could result
* in us trying to mark invalid store buffer entries.
*
* Defer freeing any allocated blocks until after the next minor GC.
*/
script->fallbackStubSpace_.freeAllAfterMinorGC(fop->runtime());
fop->delete_(script);
}
void
JS::DeletePolicy<js::jit::BaselineScript>::operator()(const js::jit::BaselineScript* script)
{
BaselineScript::Destroy(rt_->defaultFreeOp(), const_cast<BaselineScript*>(script));
}
void
BaselineScript::clearDependentWasmModules()
{

View File

@ -245,6 +245,12 @@ struct BaselineScript
uint32_t traceLoggerExitToggleOffset,
uint32_t postDebugPrologueOffset);
~BaselineScript() {
// The contents of the fallback stub space are removed and freed
// separately after the next minor GC. See BaselineScript::Destroy.
MOZ_ASSERT(fallbackStubSpace_.isEmpty());
}
static BaselineScript* New(JSScript* jsscript, uint32_t prologueOffset,
uint32_t epilogueOffset, uint32_t postDebugPrologueOffset,
uint32_t profilerEnterToggleOffset,
@ -599,4 +605,18 @@ BaselineCompile(JSContext* cx, JSScript* script, bool forceDebugInstrumentation
} // namespace jit
} // namespace js
namespace JS {
template <>
struct DeletePolicy<js::jit::BaselineScript>
{
explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {}
void operator()(const js::jit::BaselineScript* script);
private:
JSRuntime* rt_;
};
} // namespace JS
#endif /* jit_BaselineJIT_h */

View File

@ -3470,20 +3470,8 @@ CodeGenerator::emitPostWriteBarrier(Register objreg)
void
CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool)
{
const LAllocation* obj = ool->object();
// Check whether the object is a global that we have already barriered
// before calling into the VM.
if (obj->isConstant()) {
JSObject* object = &obj->toConstant()->toObject();
if (object->is<GlobalObject>()) {
JSCompartment* comp = object->compartment();
AbsoluteAddress addr(&comp->globalWriteBarriered);
masm.branch32(Assembler::NotEqual, addr, Imm32(0), ool->rejoin());
}
}
saveLiveVolatile(ool->lir());
const LAllocation* obj = ool->object();
emitPostWriteBarrier(obj);
restoreLiveVolatile(ool->lir());

View File

@ -35,6 +35,14 @@ class ICStubSpace
JS_DECLARE_NEW_METHODS(allocate, alloc, inline)
void freeAllAfterMinorGC(JSRuntime* rt);
#ifdef DEBUG
bool isEmpty() const {
return allocator_.isEmpty();
}
#endif
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return allocator_.sizeOfExcludingThis(mallocSizeOf);
}
@ -50,10 +58,6 @@ struct OptimizedICStubSpace : public ICStubSpace
OptimizedICStubSpace()
: ICStubSpace(STUB_DEFAULT_CHUNK_SIZE)
{}
void free() {
allocator_.freeAll();
}
};
// Space for fallback stubs. Every BaselineScript has a

View File

@ -1220,9 +1220,26 @@ void
IonScript::Destroy(FreeOp* fop, IonScript* script)
{
script->unlinkFromRuntime(fop);
/*
* When the script contains pointers to nursery things, the store buffer can
* contain entries that point into the fallback stub space. Since we can
* destroy scripts outside the context of a GC, this situation could result
* in us trying to mark invalid store buffer entries.
*
* Defer freeing any allocated blocks until after the next minor GC.
*/
script->fallbackStubSpace_.freeAllAfterMinorGC(fop->runtime());
fop->delete_(script);
}
void
JS::DeletePolicy<js::jit::IonScript>::operator()(const js::jit::IonScript* script)
{
IonScript::Destroy(rt_->defaultFreeOp(), const_cast<IonScript*>(script));
}
void
IonScript::toggleBarriers(bool enabled, ReprotectCode reprotect)
{

View File

@ -331,6 +331,12 @@ struct IonScript
// Do not call directly, use IonScript::New. This is public for cx->new_.
IonScript();
~IonScript() {
// The contents of the fallback stub space are removed and freed
// separately after the next minor GC. See IonScript::Destroy.
MOZ_ASSERT(fallbackStubSpace_.isEmpty());
}
static IonScript* New(JSContext* cx, RecompileInfo recompileInfo,
uint32_t frameSlots, uint32_t argumentSlots, uint32_t frameSize,
size_t snapshotsListSize, size_t snapshotsRVATableSize,
@ -798,6 +804,17 @@ struct Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
};
} // namespace ubi
template <>
struct DeletePolicy<js::jit::IonScript>
{
explicit DeletePolicy(JSRuntime* rt) : rt_(rt) {}
void operator()(const js::jit::IonScript* script);
private:
JSRuntime* rt_;
};
} // namespace JS
#endif /* jit_IonCode_h */

View File

@ -632,7 +632,7 @@ PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj)
MOZ_ASSERT(obj->is<GlobalObject>());
if (!obj->compartment()->globalWriteBarriered) {
PostWriteBarrier(rt, obj);
obj->compartment()->globalWriteBarriered = 1;
obj->compartment()->globalWriteBarriered = true;
}
}

View File

@ -4777,6 +4777,14 @@ JS::SetEnqueuePromiseJobCallback(JSRuntime* rt, JSEnqueuePromiseJobCallback call
rt->enqueuePromiseJobCallbackData = data;
}
extern JS_PUBLIC_API(void)
JS::SetPromiseRejectionTrackerCallback(JSRuntime* rt, JSPromiseRejectionTrackerCallback callback,
void* data /* = nullptr */)
{
rt->promiseRejectionTrackerCallback = callback;
rt->promiseRejectionTrackerCallbackData = data;
}
JS_PUBLIC_API(JSObject*)
JS::NewPromiseObject(JSContext* cx, HandleObject executor, HandleObject proto /* = nullptr */)
{
@ -4818,7 +4826,7 @@ JS::GetPromiseState(JS::HandleObject obj)
return promise->as<PromiseObject>().state();
}
JS_PUBLIC_API(double)
JS_PUBLIC_API(uint64_t)
JS::GetPromiseID(JS::HandleObject promise)
{
return promise->as<PromiseObject>().getID();
@ -5055,8 +5063,6 @@ JS_NewStringCopyN(JSContext* cx, const char* s, size_t n)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
if (!n)
return cx->names().empty;
return NewStringCopyN<CanGC>(cx, s, n);
}
@ -5065,7 +5071,7 @@ JS_NewStringCopyZ(JSContext* cx, const char* s)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
if (!s || !*s)
if (!s)
return cx->runtime()->emptyString;
return NewStringCopyZ<CanGC>(cx, s);
}

View File

@ -603,7 +603,20 @@ typedef bool
(* JSInterruptCallback)(JSContext* cx);
typedef bool
(* JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job, void* data);
(* JSEnqueuePromiseJobCallback)(JSContext* cx, JS::HandleObject job,
JS::HandleObject allocationSite, void* data);
enum class PromiseRejectionHandlingState {
Unhandled,
Handled
};
typedef void
(* JSPromiseRejectionTrackerCallback)(JSContext* cx, JS::HandleObject promise,
PromiseRejectionHandlingState state, void* data);
typedef void
(* JSProcessPromiseCallback)(JSContext* cx, JS::HandleObject promise);
typedef void
(* JSErrorReporter)(JSContext* cx, const char* message, JSErrorReport* report);
@ -4402,13 +4415,23 @@ namespace JS {
*
* SpiderMonkey doesn't schedule Promise resolution jobs itself; instead,
* using this function the embedding can provide a callback to do that
* scheduling. The provided `callback` is invoked with the promise job
* and the `data` pointer passed here as arguments.
* scheduling. The provided `callback` is invoked with the promise job,
* the corresponding Promise's allocation stack, and the `data` pointer
* passed here as arguments.
*/
extern JS_PUBLIC_API(void)
SetEnqueuePromiseJobCallback(JSRuntime* rt, JSEnqueuePromiseJobCallback callback,
void* data = nullptr);
/**
* Sets the callback that's invoked whenever a Promise is rejected without
* a rejection handler, and when a Promise that was previously rejected
* without a handler gets a handler attached.
*/
extern JS_PUBLIC_API(void)
SetPromiseRejectionTrackerCallback(JSRuntime* rt, JSPromiseRejectionTrackerCallback callback,
void* data = nullptr);
/**
* Returns a new instance of the Promise builtin class in the current
* compartment, with the right slot layout. If a `proto` is passed, that gets
@ -4453,7 +4476,7 @@ GetPromiseState(JS::HandleObject promise);
/**
* Returns the given Promise's process-unique ID.
*/
JS_PUBLIC_API(double)
JS_PUBLIC_API(uint64_t)
GetPromiseID(JS::HandleObject promise);
/**

View File

@ -63,7 +63,7 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options =
allocationMetadataBuilder(nullptr),
lastAnimationTime(0),
regExps(runtime_),
globalWriteBarriered(0),
globalWriteBarriered(false),
detachedTypedObjects(0),
objectMetadataState(ImmediateMetadata()),
propertyTree(thisForCtor()),
@ -680,7 +680,7 @@ JSCompartment::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime t
void
JSCompartment::sweepAfterMinorGC()
{
globalWriteBarriered = 0;
globalWriteBarriered = false;
if (innerViews.needsSweepAfterMinorGC())
innerViews.sweepAfterMinorGC();

View File

@ -427,10 +427,10 @@ struct JSCompartment
* For generational GC, record whether a write barrier has added this
* compartment's global to the store buffer since the last minor GC.
*
* This is used to avoid calling into the VM every time a nursery object is
* written to a property of the global.
* This is used to avoid adding it to the store buffer on every write, which
* can quickly fill the buffer and also cause performance problems.
*/
uint32_t globalWriteBarriered;
bool globalWriteBarriered;
// Non-zero if the storage underlying any typed object in this compartment
// might be detached.

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