Merge inbound to central, a=merge

MozReview-Commit-ID: IUFdbLdYFhX
This commit is contained in:
Wes Kocher 2017-10-04 16:37:59 -07:00
commit d8985b6e57
326 changed files with 21629 additions and 18864 deletions

View File

@ -8084,7 +8084,6 @@
<![CDATA[
if (this.selected) {
this.style.MozUserFocus = "ignore";
this.clientTop; // just using this to flush style updates
} else if (this.mOverCloseButton ||
this._overPlayingIcon) {
// Prevent tabbox.xml from selecting the tab.

View File

@ -17,18 +17,6 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
],
},
{
stack: [
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
"onxblpopupshowing@chrome://global/content/bindings/popup.xml",
"openPopup@chrome://global/content/bindings/popup.xml",
"show/</<@chrome://browser/content/customizableui/panelUI.js",
],
times: 2, // This number should only ever go down - never up.
},
{
stack: [
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
@ -51,7 +39,7 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
"openPopup@chrome://global/content/bindings/popup.xml",
],
times: 6, // This number should only ever go down - never up.
times: 7, // This number should only ever go down - never up.
},
];

View File

@ -39,7 +39,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
<html:input anonid="input"
class="autocomplete-textbox urlbar-input textbox-input"
allowevents="true"
inputmode="url"
inputmode="mozAwesomebar"
xbl:inherits="tooltiptext=inputtooltiptext,value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,focused,textoverflow"/>
</xul:hbox>
<xul:image anonid="urlbar-go-button"

View File

@ -9967,7 +9967,8 @@ nsDocShell::InternalLoad(nsIURI* aURI,
aURI,
contentType,
aTriggeringPrincipal,
(aLoadType == LOAD_NORMAL_EXTERNAL))) {
(aLoadType == LOAD_NORMAL_EXTERNAL),
!aFileName.IsVoid())) {
// logging to console happens within AllowTopLevelNavigationToDataURI
return NS_OK;
}

View File

@ -1006,6 +1006,12 @@ public:
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (OwnerDoc()->GetPointerLockElement()) {
// Throw an exception 'InvalidStateError' while the page has a locked
// element.
aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!activeState) {
return;
}

View File

@ -1666,18 +1666,17 @@ WebSocketImpl::Init(JSContext* aCx,
nsCOMPtr<nsPIDOMWindowInner> innerWindow;
while (true) {
if (principal) {
bool isNullPrincipal = true;
isNullPrincipal = principal->GetIsNullPrincipal();
if (isNullPrincipal || nsContentUtils::IsSystemPrincipal(principal)) {
break;
}
if (principal && !principal->GetIsNullPrincipal()) {
break;
}
if (!innerWindow) {
innerWindow = do_QueryInterface(globalObject);
if (NS_WARN_IF(!innerWindow)) {
return NS_ERROR_DOM_SECURITY_ERR;
if (!innerWindow) {
// If we are in a XPConnect sandbox or in a JS component,
// innerWindow will be null. There is nothing on top of this to be
// considered.
break;
}
}

View File

@ -0,0 +1,62 @@
<html><body>
<iframe id="frame" sandbox="allow-scripts allow-popups"></iframe>
<script type="application/javascript;version=1.8">
onmessage = function(e) {
parent.postMessage(e.data, '*');
}
var ifr = document.getElementById('frame');
if (location.search == '?nested') {
var url = new URL(location);
url.search = "";
ifr.src = url.href;
} else if (location.search == '?popup') {
var url = new URL(location);
url.search = "?opener";
ifr.srcdoc = "<html><script>" +
"window.open('" + url.href + "', 'foobar');" +
"onmessage = function(e) { " +
" parent.postMessage(e.data, '*'); " +
"}" +
"</scr" + "ipt></html>";
} else if (location.search == '?opener') {
try{
var socket = new WebSocket('ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic');
socket.onerror = function(e) {
opener.postMessage('WS onerror', '*');
};
socket.onopen = function(event) {
opener.postMessage('WS onopen', '*');
};
} catch(e) {
if (e.name == 'SecurityError') {
opener.postMessage('WS Throws!', '*');
} else {
opener.postMessage('WS Throws something else!', '*');
}
}
} else {
ifr.srcdoc = `
<html><script>
try{
var socket = new WebSocket('ws://mochi.test:8888/tests/dom/base/test/file_websocket_basic');
socket.onerror = function(e) {
parent.postMessage('WS onerror', '*');
};
socket.onopen = function(event) {
parent.postMessage('WS onopen', '*');
};
} catch(e) {
if (e.name == 'SecurityError') {
parent.postMessage('WS Throws!', '*');
} else {
parent.postMessage('WS Throws something else!', '*');
}
}
</scr`+`ipt>
</html>`;
}
</script>
</body></html>

View File

@ -804,6 +804,9 @@ skip-if = toolkit == 'android'
skip-if = toolkit == 'android'
[test_websocket_permessage_deflate.html]
skip-if = toolkit == 'android'
[test_webSocket_sandbox.html]
skip-if = toolkit == 'android'
support-files = iframe_webSocket_sandbox.html
[test_websocket1.html]
skip-if = toolkit == 'android'
[test_websocket2.html]

View File

@ -44,17 +44,6 @@
}
};
function flushNeckoCache() {
return new Promise (resolve => {
// We need to do a GC pass to ensure the cache entry has been freed.
SpecialPowers.gc();
var nsICacheTesting = SpecialPowers.Ci.nsICacheTesting;
var cacheTesting = SpecialPowers.Services.cache2;
cacheTesting = cacheTesting.QueryInterface(nsICacheTesting);
cacheTesting.flush(() => { resolve(); });
});
};
function WaitForScriptTagEvent(url) {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
@ -138,9 +127,6 @@
assert_equals(await stateMachineResult, "bytecode_saved",
"[1] ScriptLoadRequest status after the first visit");
// When the bytecode is saved, we have to flush the cache to read it.
await flushNeckoCache();
// Reload the same test page, and verify that the code path taken by
// the nsScriptLoadRequest corresponds to the code path which is
// loading bytecode and executing it.
@ -155,9 +141,6 @@
assert_equals(await stateMachineResult, "fallback_bytecode_saved",
"[3] ScriptLoadRequest status after the SRI hash");
// When the bytecode is saved, we have to flush the cache to read it.
await flushNeckoCache();
// Loading a page, which has the same SRI should verify the SRI and
// continue by executing the bytecode.
var stateMachineResult1 = WaitForScriptTagEvent("file_js_cache_with_sri.html");

View File

@ -0,0 +1,34 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1252751</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<div id="container"></div>
<iframe id="frame"></iframe>
<script type="application/javascript;version=1.8">
var urls = [ "https://example.com/tests/dom/base/test/iframe_webSocket_sandbox.html",
"https://example.com/tests/dom/base/test/iframe_webSocket_sandbox.html?nested",
"https://example.com/tests/dom/base/test/iframe_webSocket_sandbox.html?popup" ];
onmessage = function(e) {
is(e.data, "WS Throws!", "ws://URI cannot be used by a https iframe");
runTest();
}
function runTest() {
if (!urls.length) {
SimpleTest.finish();
return;
}
document.getElementById("frame").src = urls.shift();
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</body>
</html>

View File

@ -4422,6 +4422,10 @@ EventStateManager::SetPointerLock(nsIWidget* aWidget,
if (sIsPointerLocked) {
MOZ_ASSERT(aWidget, "Locking pointer requires a widget");
// Release all pointer capture when a pointer lock is successfully applied
// on an element.
PointerEventHandler::ReleaseAllPointerCapture();
// Store the last known ref point so we can reposition the pointer after unlock.
sPreLockPoint = sLastRefPoint;

View File

@ -1310,6 +1310,11 @@ IMEStateManager::SetIMEState(const IMEState& aState,
nsContentUtils::IsChromeDoc(aContent->OwnerDoc())) {
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::inputmode,
context.mHTMLInputInputmode);
if (context.mHTMLInputInputmode.EqualsLiteral("mozAwesomebar") &&
!nsContentUtils::IsChromeDoc(aContent->OwnerDoc())) {
// mozAwesomebar should be allowed only in chrome
context.mHTMLInputInputmode.Truncate();
}
}
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,

View File

@ -168,6 +168,17 @@ PointerEventHandler::ReleasePointerCaptureById(uint32_t aPointerId)
}
}
/* static */ void
PointerEventHandler::ReleaseAllPointerCapture()
{
for (auto iter = sPointerCaptureList->Iter(); !iter.Done(); iter.Next()) {
PointerCaptureInfo* data = iter.UserData();
if (data && data->mPendingContent) {
ReleasePointerCaptureById(iter.Key());
}
}
}
/* static */ bool
PointerEventHandler::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
{

View File

@ -64,6 +64,7 @@ public:
// Got/release pointer capture of the specified pointer by the content.
static void SetPointerCaptureById(uint32_t aPointerId, nsIContent* aContent);
static void ReleasePointerCaptureById(uint32_t aPointerId);
static void ReleaseAllPointerCapture();
// Get the pointer captured info of the specified pointer.
static PointerCaptureInfo* GetPointerCaptureInfo(uint32_t aPointerId);

View File

@ -10,6 +10,7 @@ with Files("**"):
MOCHITEST_MANIFESTS += [
'test/mochitest.ini',
'test/pointerevents/mochitest.ini',
'test/pointerevents/pointerlock/mochitest.ini',
]
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']

View File

@ -0,0 +1,13 @@
[DEFAULT]
skip-if = os == 'android' # Bug 1312791
support-files =
../mochitest_support_external.js
../mochitest_support_internal.js
../pointerevent_styles.css
../pointerevent_support.js
[test_pointerevent_pointerlock_after_pointercapture-manual.html]
support-files = pointerevent_pointerlock_after_pointercapture-manual.html
disabled = disabled # We don't allow pointer lock in mousemove handlers.
[test_pointerevent_pointerlock_supercedes_capture-manual.html]
support-files = pointerevent_pointerlock_supercedes_capture-manual.html

View File

@ -0,0 +1,69 @@
<!doctype html>
<html>
<head>
<title>Pointer Events pointer lock test</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- Additional helper script for common checks across event types -->
<script type="text/javascript" src="../pointerevent_support.js"></script>
<script>
var got_capture = false;
var lost_capture = false;
var lock_requested = false;
function resetTestState() {
}
function run() {
var test_pointerEvent = setup_pointerevent_test("no pointercapture while pointerlock", ['mouse']);
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
on_event(div1, 'pointerdown', function(event) {
div2.setPointerCapture(event.pointerId);
});
on_event(div1, 'pointermove', function(event) {
if (lost_capture) {
test_pointerEvent.step(function() {
assert_equals(document.pointerLockElement, div1, "document.pointerLockElement should be div1.");
assert_true(lost_capture, "Pointer capture was lost after got a pointer lock.");
});
test_pointerEvent.done();
}
});
on_event(div2, 'pointermove', function(event) {
if (got_capture && !lock_requested) {
div1.requestPointerLock();
lock_requested = true;
}
});
on_event(div2, 'gotpointercapture', function(event) {
got_capture = true;
});
on_event(div2, 'lostpointercapture', function(event) {
lost_capture = true;
});
}
</script>
</head>
<body onload="run()">
<h1>Pointer Events pointer lock test</h1>
<h2 id="pointerTypeDescription"></h2>
<h4>
Test Description: This test checks that we release the exsiting pointer capture when any element in the page gets a pointer lock.
<ol>
<li>Press left button down on the green rectangle and hold it.</li>
<li>Move the mouse inside the green rectangle.</li>
</ol>
Test passes if the pointer capture is released on the yellow rectangle when the green rectangle gets the pointer lock.
</h4>
<div id="testContainer">
<div id="div1" style="width:800px;height:250px;background:green"></div>
<div id="div2" style="width:800px;height:250px;background:yellow"></div>
</div>
<div class="spacer"></div>
</body>
</html>

View File

@ -0,0 +1,93 @@
<!doctype html>
<html>
<head>
<title>Pointer Events pointer lock tests</title>
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- Additional helper script for common checks across event types -->
<script type="text/javascript" src="../pointerevent_support.js"></script>
<script>
var lock_change_count = 0;
var capture_count = 0;
var mouse_move_count = 0;
function resetTestState() {
}
function run() {
var test_pointerEvent = setup_pointerevent_test("no pointercapture while pointerlock", ['mouse']);
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
on_event(div1, 'pointerdown', function(event) {
div2.setPointerCapture(event.pointerId);
div1.requestPointerLock();
});
on_event(div1, 'pointermove', function(event) {
if (lock_change_count == 1) {
mouse_move_count++;
if (mouse_move_count == 2) {
try {
div2.setPointerCapture(event.pointerId);
test_pointerEvent.step(function () {
assert_unreached("DOMException: InvalidStateError should have been thrown.");
});
} catch (e) {
test_pointerEvent.step(function () {
assert_equals(e.name, "InvalidStateError", "DOMException should be InvalidStateError");
});
}
} else if (mouse_move_count == 3) {
document.exitPointerLock();
mouse_move_count = 0;
}
} else if (lock_change_count == 2) {
mouse_move_count++;
if (mouse_move_count == 2) {
test_pointerEvent.step(function() {
assert_equals(capture_count, 0, "There shouldn't be any capture events fired.");
});
test_pointerEvent.done();
}
}
});
on_event(div2, 'gotpointercapture', function(event) {
capture_count++;
});
on_event(div2, 'lostpointercapture', function(event) {
capture_count++;
});
on_event(document, 'pointerlockchange', function(event) {
lock_change_count++;
test_pointerEvent.step(function() {
if (lock_change_count == 1)
assert_equals(document.pointerLockElement, div1, "document.pointerLockElement should be div1.");
else if (lock_change_count == 2)
assert_equals(document.pointerLockElement, null, "document.pointerLockElement should be null.");
});
});
}
</script>
</head>
<body onload="run()">
<h1>Pointer Events pointer lock test</h1>
<h2 id="pointerTypeDescription"></h2>
<h4>
Test Description: This test checks that we do not set the pointer capture when any element in the page gets a pointer lock.
<ol>
<li>Press left button down on the green rectangle and hold it.</li>
<li>Move the mouse inside the green rectangle.</li>
</ol>
Test passes if the pointer capture is not set when the green rectangle gets the pointer lock.
</h4>
<div id="testContainer">
<div id="div1" style="width:800px;height:250px;background:green"></div>
<div id="div2" style="width:800px;height:250px;background:yellow"></div>
</div>
<div class="spacer"></div>
</body>
</html>

View File

@ -0,0 +1,35 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1399740
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1399740</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="mochitest_support_external.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function startTest() {
runTestInNewWindow("pointerevent_pointerlock_after_pointercapture-manual.html");
}
function executeTest(int_win) {
int_win.document.addEventListener("gotpointercapture", () => {
int_win.document.addEventListener("pointerlockchange", () => {
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
}, { once: true });
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
}, { once: true });
sendMouseEvent(int_win, "div1", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
}
</script>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1399740
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1399740</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="mochitest_support_external.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
function startTest() {
runTestInNewWindow("pointerevent_pointerlock_supercedes_capture-manual.html");
}
function executeTest(int_win) {
// Wait for the pointer is locked.
int_win.document.addEventListener("pointerlockchange", () => {
ok(int_win.document.pointerLockElement, "document must has been pointerlocked");
int_win.document.addEventListener("pointerlockchange", () => {
// Wait for the pointer is unlocked.
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mouseup", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
}, { once: true });
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
sendMouseEvent(int_win, "div1", "mousemove", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
}, { once: true });
sendMouseEvent(int_win, "div1", "mousedown", {inputSource:MouseEvent.MOZ_SOURCE_MOUSE});
}
</script>
</head>
<body>
</body>
</html>

View File

@ -2660,6 +2660,18 @@ HTMLMediaElement::FastSeek(double aTime, ErrorResult& aRv)
already_AddRefed<Promise>
HTMLMediaElement::SeekToNextFrame(ErrorResult& aRv)
{
/* This will cause JIT code to be kept around longer, to help performance
* when using SeekToNextFrame to iterate through every frame of a video.
*/
nsCOMPtr<nsIGlobalObject> global =
do_QueryInterface(OwnerDoc()->GetInnerWindow());
if (global) {
if (JSObject *obj = global->GetGlobalJSObject()) {
js::NotifyAnimationActivity(obj);
}
}
return Seek(CurrentTime(), SeekTarget::NextFrame, aRv);
}

View File

@ -430,7 +430,8 @@ SRICheckDataVerifier::DataSummaryLength(uint32_t aDataLen, const uint8_t* aData,
// decode the content of the buffer
size_t offset = sizeof(mHashType);
size_t len = *reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]);
decltype(mHashLength) len = 0;
memcpy(&len, &aData[offset], sizeof(mHashLength));
offset += sizeof(mHashLength);
SRIVERBOSE(("SRICheckDataVerifier::DataSummaryLength, header {%x, %x, %x, %x, %x, ...}",
@ -467,18 +468,20 @@ SRICheckDataVerifier::ImportDataSummary(uint32_t aDataLen, const uint8_t* aData)
// decode the content of the buffer
size_t offset = 0;
if (*reinterpret_cast<const decltype(mHashType)*>(&aData[offset]) != mHashType) {
decltype(mHashType) hashType;
memcpy(&hashType, &aData[offset], sizeof(mHashType));
if (hashType != mHashType) {
SRILOG(("SRICheckDataVerifier::ImportDataSummary, hash type[%d] does not match[%d]",
*reinterpret_cast<const decltype(mHashType)*>(&aData[offset]),
mHashType));
hashType, mHashType));
return NS_ERROR_SRI_UNEXPECTED_HASH_TYPE;
}
offset += sizeof(mHashType);
if (*reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]) != mHashLength) {
decltype(mHashLength) hashLength;
memcpy(&hashLength, &aData[offset], sizeof(mHashLength));
if (hashLength != mHashLength) {
SRILOG(("SRICheckDataVerifier::ImportDataSummary, hash length[%d] does not match[%d]",
*reinterpret_cast<const decltype(mHashLength)*>(&aData[offset]),
mHashLength));
hashLength, mHashLength));
return NS_ERROR_SRI_UNEXPECTED_HASH_TYPE;
}
offset += sizeof(mHashLength);
@ -500,9 +503,9 @@ SRICheckDataVerifier::ExportDataSummary(uint32_t aDataLen, uint8_t* aData)
// serialize the hash in the buffer
size_t offset = 0;
*reinterpret_cast<decltype(mHashType)*>(&aData[offset]) = mHashType;
memcpy(&aData[offset], &mHashType, sizeof(mHashType));
offset += sizeof(mHashType);
*reinterpret_cast<decltype(mHashLength)*>(&aData[offset]) = mHashLength;
memcpy(&aData[offset], &mHashLength, sizeof(mHashLength));
offset += sizeof(mHashLength);
SRIVERBOSE(("SRICheckDataVerifier::ExportDataSummary, header {%x, %x, %x, %x, %x, ...}",
@ -522,9 +525,9 @@ SRICheckDataVerifier::ExportEmptyDataSummary(uint32_t aDataLen, uint8_t* aData)
// serialize an unknown hash in the buffer, to be able to skip it later
size_t offset = 0;
*reinterpret_cast<decltype(mHashType)*>(&aData[offset]) = 0;
memset(&aData[offset], 0, sizeof(mHashType));
offset += sizeof(mHashType);
*reinterpret_cast<decltype(mHashLength)*>(&aData[offset]) = 0;
memset(&aData[offset], 0, sizeof(mHashLength));
offset += sizeof(mHashLength);
SRIVERBOSE(("SRICheckDataVerifier::ExportEmptyDataSummary, header {%x, %x, %x, %x, %x, ...}",

View File

@ -26,7 +26,8 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
nsIURI* aURI,
nsContentPolicyType aContentPolicyType,
nsIPrincipal* aTriggeringPrincipal,
bool aLoadFromExternal)
bool aLoadFromExternal,
bool aIsDownLoad)
{
// Let's block all toplevel document navigations to a data: URI.
// In all cases where the toplevel document is navigated to a
@ -39,7 +40,7 @@ nsContentSecurityManager::AllowTopLevelNavigationToDataURI(
if (!mozilla::net::nsIOService::BlockToplevelDataUriNavigations()) {
return true;
}
if (aContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT) {
if (aContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT || aIsDownLoad) {
return true;
}
bool isDataURI =
@ -590,6 +591,7 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
uri,
newLoadInfo->GetExternalContentPolicyType(),
nullTriggeringPrincipal,
false,
false)) {
// logging to console happens within AllowTopLevelNavigationToDataURI
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);

View File

@ -35,7 +35,8 @@ public:
static bool AllowTopLevelNavigationToDataURI(nsIURI* aURI,
nsContentPolicyType aContentPolicyType,
nsIPrincipal* aTriggeringPrincipal,
bool aLoadFromExternal);
bool aLoadFromExternal,
bool aIsDownload);
private:
static nsresult CheckChannel(nsIChannel* aChannel);

View File

@ -3,3 +3,6 @@
support-files =
file_toplevel_data_navigations.sjs
file_toplevel_data_meta_redirect.html
[browser_test_data_download.js]
support-files =
file_data_download.html

View File

@ -0,0 +1,37 @@
"use strict";
const kTestPath = getRootDirectory(gTestPath)
.replace("chrome://mochitests/content", "http://example.com")
const kTestURI = kTestPath + "file_data_download.html";
function addWindowListener(aURL, aCallback) {
Services.wm.addListener({
onOpenWindow(aXULWindow) {
info("window opened, waiting for focus");
Services.wm.removeListener(this);
var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
waitForFocus(function() {
is(domwindow.document.location.href, aURL, "should have seen the right window open");
aCallback(domwindow);
}, domwindow);
},
onCloseWindow(aXULWindow) { },
onWindowTitleChange(aXULWindow, aNewTitle) { }
});
}
function test() {
waitForExplicitFinish();
Services.prefs.setBoolPref("security.data_uri.block_toplevel_data_uri_navigations", true);
registerCleanupFunction(function() {
Services.prefs.clearUserPref("security.data_uri.block_toplevel_data_uri_navigations");
});
addWindowListener("chrome://mozapps/content/downloads/unknownContentType.xul", function(win) {
is(win.document.getElementById("location").value, "data-foo.html",
"file name of download should match");
win.close();
finish();
});
gBrowser.loadURI(kTestURI);
}

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test download attribute for data: URI</title>
</head>
<body>
<a href="data:text/html,<body>data download</body>" download="data-foo.html" id="testlink">download data</a>
<script>
// click the link to have the downoad panel appear
let testlink = document.getElementById("testlink");
testlink.click();
</script>
</body>
</html>

View File

@ -1,4 +1,4 @@
Mozilla Public License Version 2.0
Mozilla Public License Version 2.0
==================================
1. Definitions

View File

@ -57,7 +57,13 @@ macro_rules! ioctl {
(($ioty as u32) << TYPESHIFT) |
(($nr as u32) << NRSHIFT) |
((size as u32) << SIZESHIFT);
from_unix_result(libc::ioctl(fd, ioc as libc::c_ulong, val))
#[cfg(not(target_env = "musl"))]
type IocType = libc::c_ulong;
#[cfg(target_env = "musl")]
type IocType = libc::c_int;
from_unix_result(libc::ioctl(fd, ioc as IocType, val))
}
);
}

View File

@ -65,7 +65,8 @@ function executeTest(aWindow) {
"hello.html?ForBypassingHttpCache"))
// Tear down
.then(_ => registration.unregister());
.then(_ => registration.unregister())
.then(_ => aWindow.close());
}
function register(aWindow, aURL, aScope) {

View File

@ -7470,6 +7470,7 @@ HTMLEditRules::CheckInterlinePosition(Selection& aSelection)
OwningNonNull<nsINode> selNode =
*aSelection.GetRangeAt(0)->GetStartContainer();
int32_t selOffset = aSelection.GetRangeAt(0)->StartOffset();
nsIContent* child = aSelection.GetRangeAt(0)->GetChildAtStartOffset();
// First, let's check to see if we are after a <br>. We take care of this
// special-case first so that we don't accidentally fall through into one of
@ -7482,7 +7483,11 @@ HTMLEditRules::CheckInterlinePosition(Selection& aSelection)
}
// Are we after a block? If so try set caret to following content
node = htmlEditor->GetPriorHTMLSibling(selNode, selOffset);
if (child) {
node = htmlEditor->GetPriorHTMLSibling(child);
} else {
node = nullptr;
}
if (node && IsBlockNode(*node)) {
aSelection.SetInterlinePosition(true);
return;

View File

@ -3823,40 +3823,6 @@ HTMLEditor::GetPriorHTMLSibling(nsIDOMNode* inNode,
return NS_OK;
}
/**
* GetPriorHTMLSibling() returns the previous editable sibling, if there is
* one within the parent. just like above routine but takes a parent/offset
* instead of a node.
*/
nsIContent*
HTMLEditor::GetPriorHTMLSibling(nsINode* aParent,
int32_t aOffset)
{
MOZ_ASSERT(aParent);
nsIContent* node = aParent->GetChildAt(aOffset - 1);
if (!node || IsEditable(node)) {
return node;
}
return GetPriorHTMLSibling(node);
}
nsresult
HTMLEditor::GetPriorHTMLSibling(nsIDOMNode* inParent,
int32_t inOffset,
nsCOMPtr<nsIDOMNode>* outNode)
{
NS_ENSURE_TRUE(outNode, NS_ERROR_NULL_POINTER);
*outNode = nullptr;
nsCOMPtr<nsINode> parent = do_QueryInterface(inParent);
NS_ENSURE_TRUE(parent, NS_ERROR_NULL_POINTER);
*outNode = do_QueryInterface(GetPriorHTMLSibling(parent, inOffset));
return NS_OK;
}
/**
* GetNextHTMLSibling() returns the next editable sibling, if there is
* one within the parent.
@ -4477,7 +4443,7 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
(!startOffset && !endOffset))) {
// A unique node is selected, let's also apply the background color to
// the containing block, possibly the node itself
nsCOMPtr<nsIContent> selectedNode = startNode->GetChildAt(startOffset);
nsCOMPtr<nsIContent> selectedNode = range->GetChildAtStartOffset();
nsCOMPtr<Element> blockParent = GetBlock(*selectedNode);
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;

View File

@ -770,9 +770,6 @@ protected:
nsIContent* GetPriorHTMLSibling(nsINode* aNode);
nsresult GetPriorHTMLSibling(nsIDOMNode*inNode,
nsCOMPtr<nsIDOMNode>* outNode);
nsIContent* GetPriorHTMLSibling(nsINode* aParent, int32_t aOffset);
nsresult GetPriorHTMLSibling(nsIDOMNode* inParent, int32_t inOffset,
nsCOMPtr<nsIDOMNode>* outNode);
nsIContent* GetNextHTMLSibling(nsINode* aNode);
nsresult GetNextHTMLSibling(nsIDOMNode* inNode,

View File

@ -23,7 +23,7 @@ namespace js {
class Activation;
namespace jit {
class JitActivation;
class JitProfilingFrameIterator;
class JSJitProfilingFrameIterator;
class JitcodeGlobalEntry;
} // namespace jit
namespace wasm {
@ -75,16 +75,16 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
return *static_cast<const js::wasm::ProfilingFrameIterator*>(storage());
}
js::jit::JitProfilingFrameIterator& jitIter() {
js::jit::JSJitProfilingFrameIterator& jsJitIter() {
MOZ_ASSERT(!done());
MOZ_ASSERT(isJit());
return *static_cast<js::jit::JitProfilingFrameIterator*>(storage());
MOZ_ASSERT(isJSJit());
return *static_cast<js::jit::JSJitProfilingFrameIterator*>(storage());
}
const js::jit::JitProfilingFrameIterator& jitIter() const {
const js::jit::JSJitProfilingFrameIterator& jsJitIter() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(isJit());
return *static_cast<const js::jit::JitProfilingFrameIterator*>(storage());
MOZ_ASSERT(isJSJit());
return *static_cast<const js::jit::JSJitProfilingFrameIterator*>(storage());
}
void settleFrames();
@ -134,7 +134,7 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
} JS_HAZ_GC_INVALIDATED;
bool isWasm() const;
bool isJit() const;
bool isJSJit() const;
uint32_t extractStack(Frame* frames, uint32_t offset, uint32_t end) const;

View File

@ -2472,6 +2472,13 @@ testingFunc_inIon(JSContext* cx, unsigned argc, Value* vp)
return true;
}
if (cx->activation()->hasWasmExitFP()) {
// Exited through wasm. Note this is false when the fast wasm->jit exit
// was taken, in which case we actually have jit frames on the stack.
args.rval().setBoolean(false);
return true;
}
ScriptFrameIter iter(cx);
if (!iter.done() && iter.isIon()) {
// Reset the counter of the IonScript's script.

View File

@ -428,7 +428,7 @@ GCRuntime::allocateArena(Chunk* chunk, Zone* zone, AllocKind thingKind,
// Trigger an incremental slice if needed.
if (checkThresholds)
maybeAllocTriggerZoneGC(zone, lock);
maybeAllocTriggerGC(zone, lock);
return arena;
}

View File

@ -167,14 +167,14 @@ class GCSchedulingTunables
*
* Fraction of threshold.gcBytes() which triggers an incremental GC.
*/
UnprotectedData<float> zoneAllocThresholdFactor_;
UnprotectedData<float> allocThresholdFactor_;
/*
* JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT
*
* The same except when doing so would interrupt an already running GC.
*/
UnprotectedData<float> zoneAllocThresholdFactorAvoidInterrupt_;
UnprotectedData<float> allocThresholdFactorAvoidInterrupt_;
/*
* Number of bytes to allocate between incremental slices in GCs triggered
@ -251,8 +251,8 @@ class GCSchedulingTunables
size_t gcMaxBytes() const { return gcMaxBytes_; }
size_t gcMaxNurseryBytes() const { return gcMaxNurseryBytes_; }
size_t gcZoneAllocThresholdBase() const { return gcZoneAllocThresholdBase_; }
float zoneAllocThresholdFactor() const { return zoneAllocThresholdFactor_; }
float zoneAllocThresholdFactorAvoidInterrupt() const { return zoneAllocThresholdFactorAvoidInterrupt_; }
float allocThresholdFactor() const { return allocThresholdFactor_; }
float allocThresholdFactorAvoidInterrupt() const { return allocThresholdFactorAvoidInterrupt_; }
size_t zoneAllocDelayBytes() const { return zoneAllocDelayBytes_; }
bool isDynamicHeapGrowthEnabled() const { return dynamicHeapGrowthEnabled_; }
uint64_t highFrequencyThresholdUsec() const { return highFrequencyThresholdUsec_; }
@ -654,41 +654,46 @@ using AllocKinds = mozilla::EnumSet<AllocKind>;
template <typename T>
class MemoryCounter
{
// Bytes counter to measure memory pressure for GC scheduling. It runs
// from maxBytes down to zero.
mozilla::Atomic<ptrdiff_t, mozilla::ReleaseAcquire> bytes_;
// Bytes counter to measure memory pressure for GC scheduling. It counts
// upwards from zero.
mozilla::Atomic<size_t, mozilla::ReleaseAcquire> bytes_;
// GC trigger threshold for memory allocations.
js::ActiveThreadData<size_t> maxBytes_;
size_t maxBytes_;
// Whether a GC has been triggered as a result of bytes falling below
// zero.
//
// This should be a bool, but Atomic only supports 32-bit and pointer-sized
// types.
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> triggered_;
// Initial GC trigger threshold.
GCLockData<size_t> initialMaxBytes_;
// Whether a GC has been triggered as a result of bytes_ exceeding
// maxBytes_.
mozilla::Atomic<bool, mozilla::ReleaseAcquire> triggered_;
public:
MemoryCounter()
: bytes_(0),
maxBytes_(0),
initialMaxBytes_(0),
triggered_(false)
{ }
void reset() {
bytes_ = maxBytes_;
triggered_ = false;
void updateOnGC(const AutoLockGC& lock) {
if (isTooMuchMalloc())
maxBytes_ *= 2;
else
maxBytes_ = std::max(initialMaxBytes_.ref(), size_t(maxBytes_ * 0.9));
reset();
}
void setMax(size_t newMax) {
void setMax(size_t newMax, const AutoLockGC& lock) {
// For compatibility treat any value that exceeds PTRDIFF_T_MAX to
// mean that value.
maxBytes_ = (ptrdiff_t(newMax) >= 0) ? newMax : size_t(-1) >> 1;
initialMaxBytes_ = (ptrdiff_t(newMax) >= 0) ? newMax : size_t(-1) >> 1;
maxBytes_ = initialMaxBytes_;
reset();
}
bool update(T* owner, size_t bytes) {
bytes_ -= ptrdiff_t(bytes);
bytes_ += ptrdiff_t(bytes);
if (MOZ_UNLIKELY(isTooMuchMalloc())) {
if (!triggered_)
triggered_ = owner->triggerGCForTooMuchMalloc();
@ -696,9 +701,26 @@ class MemoryCounter
return triggered_;
}
void decrement(size_t bytes) {
MOZ_ASSERT(bytes <= bytes_);
bytes_ -= bytes;
}
void adopt(MemoryCounter<T>& other) {
bytes_ += other.bytes();
other.reset();
}
ptrdiff_t bytes() const { return bytes_; }
size_t maxBytes() const { return maxBytes_; }
bool isTooMuchMalloc() const { return bytes_ <= 0; }
size_t initialMaxBytes(const AutoLockGC& lock) const { return initialMaxBytes_; }
bool isTooMuchMalloc() const { return bytes_ >= maxBytes_; }
private:
void reset() {
bytes_ = 0;
triggered_ = false;
}
};
class GCRuntime
@ -723,7 +745,7 @@ class GCRuntime
uint32_t getParameter(JSGCParamKey key, const AutoLockGC& lock);
MOZ_MUST_USE bool triggerGC(JS::gcreason::Reason reason);
void maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock);
void maybeAllocTriggerGC(Zone* zone, const AutoLockGC& lock);
// The return value indicates if we were able to do the GC.
bool triggerZoneGC(Zone* zone, JS::gcreason::Reason reason,
size_t usedBytes, size_t thresholdBytes);
@ -844,9 +866,9 @@ class GCRuntime
int32_t getMallocBytes() const { return mallocCounter.bytes(); }
size_t maxMallocBytesAllocated() const { return mallocCounter.maxBytes(); }
bool isTooMuchMalloc() const { return mallocCounter.isTooMuchMalloc(); }
void resetMallocBytes() { mallocCounter.reset(); }
void setMaxMallocBytes(size_t value);
void updateMallocCounter(JS::Zone* zone, size_t nbytes);
void setMaxMallocBytes(size_t value, const AutoLockGC& lock);
bool updateMallocCounter(size_t nbytes) { return mallocCounter.update(this, nbytes); }
void updateMallocCountersOnGC();
void setGCCallback(JSGCCallback callback, void* data);
void callGCCallback(JSGCStatus status) const;

View File

@ -68,8 +68,8 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group)
AutoLockGC lock(rt);
threshold.updateAfterGC(8192, GC_NORMAL, rt->gc.tunables, rt->gc.schedulingState, lock);
setGCMaxMallocBytes(rt->gc.maxMallocBytesAllocated() * 0.9);
jitCodeCounter.setMax(jit::MaxCodeBytesPerProcess * 0.8);
setGCMaxMallocBytes(rt->gc.maxMallocBytesAllocated() * 0.9, lock);
jitCodeCounter.setMax(jit::MaxCodeBytesPerProcess * 0.8, lock);
}
Zone::~Zone()

View File

@ -442,18 +442,28 @@ struct Zone : public JS::shadow::Zone,
return false;
}
void resetGCMallocBytes() { gcMallocCounter.reset(); }
void setGCMaxMallocBytes(size_t value) { gcMallocCounter.setMax(value); }
void updateMallocCounter(size_t nbytes) { gcMallocCounter.update(this, nbytes); }
void updateGCMallocBytesOnGC(const js::AutoLockGC& lock) {
gcMallocCounter.updateOnGC(lock);
}
void setGCMaxMallocBytes(size_t value, const js::AutoLockGC& lock) {
gcMallocCounter.setMax(value, lock);
}
void updateMallocCounter(size_t nbytes) {
if (!runtime_->gc.updateMallocCounter(nbytes))
gcMallocCounter.update(this, nbytes);
}
void adoptMallocBytes(Zone* other) {
gcMallocCounter.adopt(other->gcMallocCounter);
}
size_t GCMaxMallocBytes() const { return gcMallocCounter.maxBytes(); }
size_t GCMallocBytes() const { return gcMallocCounter.bytes(); }
void updateJitCodeMallocBytes(size_t size) { jitCodeCounter.update(this, size); }
// Resets all the memory counters.
void resetAllMallocBytes() {
resetGCMallocBytes();
jitCodeCounter.reset();
// Updates all the memory counters after GC.
void updateAllMallocBytesOnGC(const js::AutoLockGC& lock) {
updateGCMallocBytesOnGC(lock);
jitCodeCounter.updateOnGC(lock);
}
bool isTooMuchMalloc() const {
return gcMallocCounter.isTooMuchMalloc() ||

View File

@ -440,7 +440,7 @@ PatchBaselineFramesForDebugMode(JSContext* cx, const CooperatingContext& target,
// If profiling is off, patch the resume address to nullptr,
// to ensure the old address is not used anywhere.
//
// If profiling is on, JitProfilingFrameIterator requires a
// If profiling is on, JSJitProfilingFrameIterator requires a
// valid return address.
MOZ_ASSERT(frame.baselineFrame()->isHandlingException());
MOZ_ASSERT(frame.baselineFrame()->overridePc() == pc);

View File

@ -4809,14 +4809,16 @@ IonBuilder::createCallObject(MDefinition* callee, MDefinition* env)
// Get a template CallObject that we'll use to generate inline object
// creation.
CallObject* templateObj = inspector->templateCallObject();
MConstant* templateCst = MConstant::NewConstraintlessObject(alloc(), templateObj);
current->add(templateCst);
// Allocate the object. Run-once scripts need a singleton type, so always do
// a VM call in such cases.
MNewCallObjectBase* callObj;
if (script()->treatAsRunOnce() || templateObj->isSingleton())
callObj = MNewSingletonCallObject::New(alloc(), templateObj);
callObj = MNewSingletonCallObject::New(alloc(), templateCst);
else
callObj = MNewCallObject::New(alloc(), templateObj);
callObj = MNewCallObject::New(alloc(), templateCst);
current->add(callObj);
// Initialize the object's reserved slots. No post barrier is needed here,

View File

@ -45,14 +45,14 @@ JSJitFrameIter::prevFrameLocalSize() const
}
inline JitFrameLayout*
JitProfilingFrameIterator::framePtr()
JSJitProfilingFrameIterator::framePtr()
{
MOZ_ASSERT(!done());
return (JitFrameLayout*) fp_;
}
inline JSScript*
JitProfilingFrameIterator::frameScript()
JSJitProfilingFrameIterator::frameScript()
{
return ScriptFromCalleeToken(framePtr()->calleeToken());
}

View File

@ -6,6 +6,7 @@
#include "jit/JSJitFrameIter-inl.h"
#include "jit/BaselineDebugModeOSR.h"
#include "jit/BaselineIC.h"
#include "jit/JitcodeMap.h"
#include "jit/JitFrames.h"
@ -453,3 +454,310 @@ JSJitFrameIter::verifyReturnAddressUsingNativeToBytecodeMap()
return true;
}
#endif // DEBUG
JSJitProfilingFrameIterator::JSJitProfilingFrameIterator(
JSContext* cx, const JS::ProfilingFrameIterator::RegisterState& state)
{
// If no profilingActivation is live, initialize directly to
// end-of-iteration state.
if (!cx->profilingActivation()) {
type_ = JitFrame_CppToJSJit;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return;
}
MOZ_ASSERT(cx->profilingActivation()->isJit());
JitActivation* act = cx->profilingActivation()->asJit();
// If the top JitActivation has a null lastProfilingFrame, assume that
// it's a trivially empty activation, and initialize directly
// to end-of-iteration state.
if (!act->lastProfilingFrame()) {
type_ = JitFrame_CppToJSJit;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return;
}
// Get the fp from the current profilingActivation
fp_ = (uint8_t*) act->lastProfilingFrame();
void* lastCallSite = act->lastProfilingCallSite();
JitcodeGlobalTable* table = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
// Profiler sampling must NOT be suppressed if we are here.
MOZ_ASSERT(cx->isProfilerSamplingEnabled());
// Try initializing with sampler pc
if (tryInitWithPC(state.pc))
return;
// Try initializing with sampler pc using native=>bytecode table.
if (tryInitWithTable(table, state.pc, cx->runtime(), /* forLastCallSite = */ false))
return;
// Try initializing with lastProfilingCallSite pc
if (lastCallSite) {
if (tryInitWithPC(lastCallSite))
return;
// Try initializing with lastProfilingCallSite pc using native=>bytecode table.
if (tryInitWithTable(table, lastCallSite, cx->runtime(), /* forLastCallSite = */ true))
return;
}
MOZ_ASSERT(frameScript()->hasBaselineScript());
// If nothing matches, for now just assume we are at the start of the last frame's
// baseline jit code.
type_ = JitFrame_BaselineJS;
returnAddressToFp_ = frameScript()->baselineScript()->method()->raw();
}
template <typename ReturnType = CommonFrameLayout*>
static inline ReturnType
GetPreviousRawFrame(CommonFrameLayout* frame)
{
size_t prevSize = frame->prevFrameLocalSize() + frame->headerSize();
return ReturnType((uint8_t*)frame + prevSize);
}
JSJitProfilingFrameIterator::JSJitProfilingFrameIterator(void* exitFrame)
{
// Skip the exit frame.
ExitFrameLayout* frame = (ExitFrameLayout*) exitFrame;
moveToNextFrame(frame);
}
bool
JSJitProfilingFrameIterator::tryInitWithPC(void* pc)
{
JSScript* callee = frameScript();
// Check for Ion first, since it's more likely for hot code.
if (callee->hasIonScript() && callee->ionScript()->method()->containsNativePC(pc)) {
type_ = JitFrame_IonJS;
returnAddressToFp_ = pc;
return true;
}
// Check for containment in Baseline jitcode second.
if (callee->hasBaselineScript() && callee->baselineScript()->method()->containsNativePC(pc)) {
type_ = JitFrame_BaselineJS;
returnAddressToFp_ = pc;
return true;
}
return false;
}
bool
JSJitProfilingFrameIterator::tryInitWithTable(JitcodeGlobalTable* table, void* pc, JSRuntime* rt,
bool forLastCallSite)
{
if (!pc)
return false;
const JitcodeGlobalEntry* entry = table->lookup(pc);
if (!entry)
return false;
JSScript* callee = frameScript();
MOZ_ASSERT(entry->isIon() || entry->isBaseline() || entry->isIonCache() || entry->isDummy());
// Treat dummy lookups as an empty frame sequence.
if (entry->isDummy()) {
type_ = JitFrame_CppToJSJit;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return true;
}
if (entry->isIon()) {
// If looked-up callee doesn't match frame callee, don't accept lastProfilingCallSite
if (entry->ionEntry().getScript(0) != callee)
return false;
type_ = JitFrame_IonJS;
returnAddressToFp_ = pc;
return true;
}
if (entry->isBaseline()) {
// If looked-up callee doesn't match frame callee, don't accept lastProfilingCallSite
if (forLastCallSite && entry->baselineEntry().script() != callee)
return false;
type_ = JitFrame_BaselineJS;
returnAddressToFp_ = pc;
return true;
}
if (entry->isIonCache()) {
void* ptr = entry->ionCacheEntry().rejoinAddr();
const JitcodeGlobalEntry& ionEntry = table->lookupInfallible(ptr);
MOZ_ASSERT(ionEntry.isIon());
if (ionEntry.ionEntry().getScript(0) != callee)
return false;
type_ = JitFrame_IonJS;
returnAddressToFp_ = pc;
return true;
}
return false;
}
void
JSJitProfilingFrameIterator::fixBaselineReturnAddress()
{
MOZ_ASSERT(type_ == JitFrame_BaselineJS);
BaselineFrame* bl = (BaselineFrame*)(fp_ - BaselineFrame::FramePointerOffset -
BaselineFrame::Size());
// Debug mode OSR for Baseline uses a "continuation fixer" and stashes the
// actual return address in an auxiliary structure.
if (BaselineDebugModeOSRInfo* info = bl->getDebugModeOSRInfo()) {
returnAddressToFp_ = info->resumeAddr;
return;
}
// Resuming a generator via .throw() pushes a bogus return address onto
// the stack. We have the actual jsbytecode* stashed on the frame itself;
// translate that into the Baseline code address.
if (jsbytecode* override = bl->maybeOverridePc()) {
JSScript* script = bl->script();
returnAddressToFp_ = script->baselineScript()->nativeCodeForPC(script, override);
return;
}
}
void
JSJitProfilingFrameIterator::operator++()
{
JitFrameLayout* frame = framePtr();
moveToNextFrame(frame);
}
void
JSJitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame)
{
/*
* fp_ points to a Baseline or Ion frame. The possible call-stacks
* patterns occurring between this frame and a previous Ion or Baseline
* frame are as follows:
*
* <Baseline-Or-Ion>
* ^
* |
* ^--- Ion
* |
* ^--- Baseline Stub <---- Baseline
* |
* ^--- WasmToJSJit <---- (other wasm frames, not handled by this iterator)
* |
* ^--- Argument Rectifier
* | ^
* | |
* | ^--- Ion
* | |
* | ^--- Baseline Stub <---- Baseline
* |
* ^--- Entry Frame (From C++)
* Exit Frame (From previous JitActivation)
* ^
* |
* ^--- Ion
* |
* ^--- Baseline
* |
* ^--- Baseline Stub <---- Baseline
*/
FrameType prevType = frame->prevType();
if (prevType == JitFrame_IonJS) {
returnAddressToFp_ = frame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(frame);
type_ = JitFrame_IonJS;
return;
}
if (prevType == JitFrame_BaselineJS) {
returnAddressToFp_ = frame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(frame);
type_ = JitFrame_BaselineJS;
fixBaselineReturnAddress();
return;
}
if (prevType == JitFrame_BaselineStub) {
BaselineStubFrameLayout* stubFrame = GetPreviousRawFrame<BaselineStubFrameLayout*>(frame);
MOZ_ASSERT(stubFrame->prevType() == JitFrame_BaselineJS);
returnAddressToFp_ = stubFrame->returnAddress();
fp_ = ((uint8_t*) stubFrame->reverseSavedFramePtr())
+ jit::BaselineFrame::FramePointerOffset;
type_ = JitFrame_BaselineJS;
return;
}
if (prevType == JitFrame_Rectifier) {
RectifierFrameLayout* rectFrame = GetPreviousRawFrame<RectifierFrameLayout*>(frame);
FrameType rectPrevType = rectFrame->prevType();
if (rectPrevType == JitFrame_IonJS) {
returnAddressToFp_ = rectFrame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(rectFrame);
type_ = JitFrame_IonJS;
return;
}
if (rectPrevType == JitFrame_BaselineStub) {
BaselineStubFrameLayout* stubFrame =
GetPreviousRawFrame<BaselineStubFrameLayout*>(rectFrame);
returnAddressToFp_ = stubFrame->returnAddress();
fp_ = ((uint8_t*) stubFrame->reverseSavedFramePtr())
+ jit::BaselineFrame::FramePointerOffset;
type_ = JitFrame_BaselineJS;
return;
}
MOZ_CRASH("Bad frame type prior to rectifier frame.");
}
if (prevType == JitFrame_IonICCall) {
IonICCallFrameLayout* callFrame =
GetPreviousRawFrame<IonICCallFrameLayout*>(frame);
MOZ_ASSERT(callFrame->prevType() == JitFrame_IonJS);
returnAddressToFp_ = callFrame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(callFrame);
type_ = JitFrame_IonJS;
return;
}
if (prevType == JitFrame_WasmToJSJit) {
// No previous js jit frame, this is a transition frame, used to pass
// a wasm iterator the correct value of FP.
returnAddressToFp_ = nullptr;
fp_ = GetPreviousRawFrame<uint8_t*>(frame);
type_ = JitFrame_WasmToJSJit;
return;
}
if (prevType == JitFrame_CppToJSJit) {
// No previous frame, set to null to indicate that
// JSJitProfilingFrameIterator is done().
returnAddressToFp_ = nullptr;
fp_ = nullptr;
type_ = JitFrame_CppToJSJit;
return;
}
MOZ_CRASH("Bad frame type.");
}

View File

@ -284,7 +284,7 @@ class JSJitFrameIter
class JitcodeGlobalTable;
class JitProfilingFrameIterator
class JSJitProfilingFrameIterator
{
uint8_t* fp_;
FrameType type_;
@ -300,9 +300,9 @@ class JitProfilingFrameIterator
void moveToNextFrame(CommonFrameLayout* frame);
public:
JitProfilingFrameIterator(JSContext* cx,
JSJitProfilingFrameIterator(JSContext* cx,
const JS::ProfilingFrameIterator::RegisterState& state);
explicit JitProfilingFrameIterator(void* exitFrame);
explicit JSJitProfilingFrameIterator(void* exitFrame);
void operator++();
bool done() const { return fp_ == nullptr; }

View File

@ -2409,313 +2409,6 @@ InlineFrameIterator::dump() const
fputc('\n', stderr);
}
JitProfilingFrameIterator::JitProfilingFrameIterator(
JSContext* cx, const JS::ProfilingFrameIterator::RegisterState& state)
{
// If no profilingActivation is live, initialize directly to
// end-of-iteration state.
if (!cx->profilingActivation()) {
type_ = JitFrame_CppToJSJit;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return;
}
MOZ_ASSERT(cx->profilingActivation()->isJit());
JitActivation* act = cx->profilingActivation()->asJit();
// If the top JitActivation has a null lastProfilingFrame, assume that
// it's a trivially empty activation, and initialize directly
// to end-of-iteration state.
if (!act->lastProfilingFrame()) {
type_ = JitFrame_CppToJSJit;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return;
}
// Get the fp from the current profilingActivation
fp_ = (uint8_t*) act->lastProfilingFrame();
void* lastCallSite = act->lastProfilingCallSite();
JitcodeGlobalTable* table = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
// Profiler sampling must NOT be suppressed if we are here.
MOZ_ASSERT(cx->isProfilerSamplingEnabled());
// Try initializing with sampler pc
if (tryInitWithPC(state.pc))
return;
// Try initializing with sampler pc using native=>bytecode table.
if (tryInitWithTable(table, state.pc, cx->runtime(), /* forLastCallSite = */ false))
return;
// Try initializing with lastProfilingCallSite pc
if (lastCallSite) {
if (tryInitWithPC(lastCallSite))
return;
// Try initializing with lastProfilingCallSite pc using native=>bytecode table.
if (tryInitWithTable(table, lastCallSite, cx->runtime(), /* forLastCallSite = */ true))
return;
}
MOZ_ASSERT(frameScript()->hasBaselineScript());
// If nothing matches, for now just assume we are at the start of the last frame's
// baseline jit code.
type_ = JitFrame_BaselineJS;
returnAddressToFp_ = frameScript()->baselineScript()->method()->raw();
}
template <typename ReturnType = CommonFrameLayout*>
inline ReturnType
GetPreviousRawFrame(CommonFrameLayout* frame)
{
size_t prevSize = frame->prevFrameLocalSize() + frame->headerSize();
return ReturnType((uint8_t*)frame + prevSize);
}
JitProfilingFrameIterator::JitProfilingFrameIterator(void* exitFrame)
{
// Skip the exit frame.
ExitFrameLayout* frame = (ExitFrameLayout*) exitFrame;
moveToNextFrame(frame);
}
bool
JitProfilingFrameIterator::tryInitWithPC(void* pc)
{
JSScript* callee = frameScript();
// Check for Ion first, since it's more likely for hot code.
if (callee->hasIonScript() && callee->ionScript()->method()->containsNativePC(pc)) {
type_ = JitFrame_IonJS;
returnAddressToFp_ = pc;
return true;
}
// Check for containment in Baseline jitcode second.
if (callee->hasBaselineScript() && callee->baselineScript()->method()->containsNativePC(pc)) {
type_ = JitFrame_BaselineJS;
returnAddressToFp_ = pc;
return true;
}
return false;
}
bool
JitProfilingFrameIterator::tryInitWithTable(JitcodeGlobalTable* table, void* pc, JSRuntime* rt,
bool forLastCallSite)
{
if (!pc)
return false;
const JitcodeGlobalEntry* entry = table->lookup(pc);
if (!entry)
return false;
JSScript* callee = frameScript();
MOZ_ASSERT(entry->isIon() || entry->isBaseline() || entry->isIonCache() || entry->isDummy());
// Treat dummy lookups as an empty frame sequence.
if (entry->isDummy()) {
type_ = JitFrame_CppToJSJit;
fp_ = nullptr;
returnAddressToFp_ = nullptr;
return true;
}
if (entry->isIon()) {
// If looked-up callee doesn't match frame callee, don't accept lastProfilingCallSite
if (entry->ionEntry().getScript(0) != callee)
return false;
type_ = JitFrame_IonJS;
returnAddressToFp_ = pc;
return true;
}
if (entry->isBaseline()) {
// If looked-up callee doesn't match frame callee, don't accept lastProfilingCallSite
if (forLastCallSite && entry->baselineEntry().script() != callee)
return false;
type_ = JitFrame_BaselineJS;
returnAddressToFp_ = pc;
return true;
}
if (entry->isIonCache()) {
void* ptr = entry->ionCacheEntry().rejoinAddr();
const JitcodeGlobalEntry& ionEntry = table->lookupInfallible(ptr);
MOZ_ASSERT(ionEntry.isIon());
if (ionEntry.ionEntry().getScript(0) != callee)
return false;
type_ = JitFrame_IonJS;
returnAddressToFp_ = pc;
return true;
}
return false;
}
void
JitProfilingFrameIterator::fixBaselineReturnAddress()
{
MOZ_ASSERT(type_ == JitFrame_BaselineJS);
BaselineFrame* bl = (BaselineFrame*)(fp_ - BaselineFrame::FramePointerOffset -
BaselineFrame::Size());
// Debug mode OSR for Baseline uses a "continuation fixer" and stashes the
// actual return address in an auxiliary structure.
if (BaselineDebugModeOSRInfo* info = bl->getDebugModeOSRInfo()) {
returnAddressToFp_ = info->resumeAddr;
return;
}
// Resuming a generator via .throw() pushes a bogus return address onto
// the stack. We have the actual jsbytecode* stashed on the frame itself;
// translate that into the Baseline code address.
if (jsbytecode* override = bl->maybeOverridePc()) {
JSScript* script = bl->script();
returnAddressToFp_ = script->baselineScript()->nativeCodeForPC(script, override);
return;
}
}
void
JitProfilingFrameIterator::operator++()
{
JitFrameLayout* frame = framePtr();
moveToNextFrame(frame);
}
void
JitProfilingFrameIterator::moveToNextFrame(CommonFrameLayout* frame)
{
/*
* fp_ points to a Baseline or Ion frame. The possible call-stacks
* patterns occurring between this frame and a previous Ion or Baseline
* frame are as follows:
*
* <Baseline-Or-Ion>
* ^
* |
* ^--- Ion
* |
* ^--- Baseline Stub <---- Baseline
* |
* ^--- WasmToJSJit <---- (other wasm frames, not handled by this iterator)
* |
* ^--- Argument Rectifier
* | ^
* | |
* | ^--- Ion
* | |
* | ^--- Baseline Stub <---- Baseline
* |
* ^--- Entry Frame (From C++)
* Exit Frame (From previous JitActivation)
* ^
* |
* ^--- Ion
* |
* ^--- Baseline
* |
* ^--- Baseline Stub <---- Baseline
*/
FrameType prevType = frame->prevType();
if (prevType == JitFrame_IonJS) {
returnAddressToFp_ = frame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(frame);
type_ = JitFrame_IonJS;
return;
}
if (prevType == JitFrame_BaselineJS) {
returnAddressToFp_ = frame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(frame);
type_ = JitFrame_BaselineJS;
fixBaselineReturnAddress();
return;
}
if (prevType == JitFrame_BaselineStub) {
BaselineStubFrameLayout* stubFrame = GetPreviousRawFrame<BaselineStubFrameLayout*>(frame);
MOZ_ASSERT(stubFrame->prevType() == JitFrame_BaselineJS);
returnAddressToFp_ = stubFrame->returnAddress();
fp_ = ((uint8_t*) stubFrame->reverseSavedFramePtr())
+ jit::BaselineFrame::FramePointerOffset;
type_ = JitFrame_BaselineJS;
return;
}
if (prevType == JitFrame_Rectifier) {
RectifierFrameLayout* rectFrame = GetPreviousRawFrame<RectifierFrameLayout*>(frame);
FrameType rectPrevType = rectFrame->prevType();
if (rectPrevType == JitFrame_IonJS) {
returnAddressToFp_ = rectFrame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(rectFrame);
type_ = JitFrame_IonJS;
return;
}
if (rectPrevType == JitFrame_BaselineStub) {
BaselineStubFrameLayout* stubFrame =
GetPreviousRawFrame<BaselineStubFrameLayout*>(rectFrame);
returnAddressToFp_ = stubFrame->returnAddress();
fp_ = ((uint8_t*) stubFrame->reverseSavedFramePtr())
+ jit::BaselineFrame::FramePointerOffset;
type_ = JitFrame_BaselineJS;
return;
}
MOZ_CRASH("Bad frame type prior to rectifier frame.");
}
if (prevType == JitFrame_IonICCall) {
IonICCallFrameLayout* callFrame =
GetPreviousRawFrame<IonICCallFrameLayout*>(frame);
MOZ_ASSERT(callFrame->prevType() == JitFrame_IonJS);
returnAddressToFp_ = callFrame->returnAddress();
fp_ = GetPreviousRawFrame<uint8_t*>(callFrame);
type_ = JitFrame_IonJS;
return;
}
if (prevType == JitFrame_WasmToJSJit) {
// No previous js jit frame, this is a transition frame, used to pass
// a wasm iterator the correct value of FP.
returnAddressToFp_ = nullptr;
fp_ = GetPreviousRawFrame<uint8_t*>(frame);
type_ = JitFrame_WasmToJSJit;
return;
}
if (prevType == JitFrame_CppToJSJit) {
// No previous frame, set to null to indicate that
// JitProfilingFrameIterator is done().
returnAddressToFp_ = nullptr;
fp_ = nullptr;
type_ = JitFrame_CppToJSJit;
return;
}
MOZ_CRASH("Bad frame type.");
}
JitFrameLayout*
InvalidationBailoutStack::fp() const
{

View File

@ -13147,45 +13147,40 @@ class MNewNamedLambdaObject : public MNullaryInstruction
}
};
class MNewCallObjectBase : public MNullaryInstruction
class MNewCallObjectBase : public MUnaryInstruction
, public SingleObjectPolicy::Data
{
CompilerGCPointer<CallObject*> templateObj_;
protected:
MNewCallObjectBase(Opcode op, CallObject* templateObj)
: MNullaryInstruction(op),
templateObj_(templateObj)
MNewCallObjectBase(Opcode op, MConstant* templateObj)
: MUnaryInstruction(op, templateObj)
{
setResultType(MIRType::Object);
}
public:
CallObject* templateObject() {
return templateObj_;
CallObject* templateObject() const {
return &getOperand(0)->toConstant()->toObject().as<CallObject>();
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
bool appendRoots(MRootList& roots) const override {
return roots.append(templateObj_);
}
};
class MNewCallObject : public MNewCallObjectBase
{
public:
INSTRUCTION_HEADER(NewCallObject)
TRIVIAL_NEW_WRAPPERS
explicit MNewCallObject(CallObject* templateObj)
explicit MNewCallObject(MConstant* templateObj)
: MNewCallObjectBase(classOpcode, templateObj)
{
MOZ_ASSERT(!templateObj->isSingleton());
MOZ_ASSERT(!templateObject()->isSingleton());
}
static MNewCallObject*
New(TempAllocator& alloc, CallObject* templateObj)
{
return new(alloc) MNewCallObject(templateObj);
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
return true;
}
};
@ -13193,16 +13188,11 @@ class MNewSingletonCallObject : public MNewCallObjectBase
{
public:
INSTRUCTION_HEADER(NewSingletonCallObject)
TRIVIAL_NEW_WRAPPERS
explicit MNewSingletonCallObject(CallObject* templateObj)
explicit MNewSingletonCallObject(MConstant* templateObj)
: MNewCallObjectBase(classOpcode, templateObj)
{}
static MNewSingletonCallObject*
New(TempAllocator& alloc, CallObject* templateObj)
{
return new(alloc) MNewSingletonCallObject(templateObj);
}
};
class MNewStringObject :

View File

@ -1518,6 +1518,35 @@ RLambdaArrow::recover(JSContext* cx, SnapshotIterator& iter) const
return true;
}
bool
MNewCallObject::writeRecoverData(CompactBufferWriter& writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_NewCallObject));
return true;
}
RNewCallObject::RNewCallObject(CompactBufferReader& reader)
{
}
bool
RNewCallObject::recover(JSContext* cx, SnapshotIterator& iter) const
{
Rooted<CallObject*> templateObj(cx, &iter.read().toObject().as<CallObject>());
RootedShape shape(cx, templateObj->lastProperty());
RootedObjectGroup group(cx, templateObj->group());
JSObject* resultObject = NewCallObject(cx, shape, group);
if (!resultObject)
return false;
RootedValue result(cx);
result.setObject(*resultObject);
iter.storeInstructionResult(result);
return true;
}
bool
MSimdBox::writeRecoverData(CompactBufferWriter& writer) const
{

View File

@ -104,6 +104,7 @@ namespace jit {
_(NewArray) \
_(NewIterator) \
_(NewDerivedTypedObject) \
_(NewCallObject) \
_(CreateThisWithTemplate) \
_(Lambda) \
_(LambdaArrow) \
@ -639,6 +640,14 @@ class RLambdaArrow final : public RInstruction
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
};
class RNewCallObject final : public RInstruction
{
public:
RINSTRUCTION_HEADER_NUM_OP_(NewCallObject, 1)
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const override;
};
class RSimdBox final : public RInstruction
{
private:

View File

@ -1609,6 +1609,17 @@ JSContext::findVersion()
return runtime()->defaultVersion();
}
void
JSContext::updateMallocCounter(size_t nbytes)
{
if (!zone()) {
runtime()->updateMallocCounter(nbytes);
return;
}
zone()->updateMallocCounter(nbytes);
}
#ifdef DEBUG
JS::AutoCheckRequestDepth::AutoCheckRequestDepth(JSContext* cxArg)

View File

@ -142,9 +142,7 @@ struct JSContext : public JS::RootingContext,
/* Clear the pending exception (if any) due to OOM. */
void recoverFromOutOfMemory();
inline void updateMallocCounter(size_t nbytes) {
runtime()->updateMallocCounter(zone(), nbytes);
}
void updateMallocCounter(size_t nbytes);
void reportAllocationOverflow() {
js::ReportAllocationOverflow(this);

View File

@ -281,10 +281,10 @@ namespace TuningDefaults {
static const size_t GCZoneAllocThresholdBase = 30 * 1024 * 1024;
/* JSGC_ALLOCATION_THRESHOLD_FACTOR */
static const float ZoneAllocThresholdFactor = 0.9f;
static const float AllocThresholdFactor = 0.9f;
/* JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT */
static const float ZoneAllocThresholdFactorAvoidInterrupt = 0.9f;
static const float AllocThresholdFactorAvoidInterrupt = 0.9f;
/* no parameter */
static const size_t ZoneAllocDelayBytes = 1024 * 1024;
@ -1165,7 +1165,7 @@ GCRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
*/
MOZ_ALWAYS_TRUE(tunables.setParameter(JSGC_MAX_BYTES, maxbytes, lock));
MOZ_ALWAYS_TRUE(tunables.setParameter(JSGC_MAX_NURSERY_BYTES, maxNurseryBytes, lock));
setMaxMallocBytes(maxbytes);
setMaxMallocBytes(maxbytes, lock);
const char* size = getenv("JSGC_MARK_STACK_LIMIT");
if (size)
@ -1247,9 +1247,7 @@ GCRuntime::setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock)
{
switch (key) {
case JSGC_MAX_MALLOC_BYTES:
setMaxMallocBytes(value);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->setGCMaxMallocBytes(maxMallocBytesAllocated() * 0.9);
setMaxMallocBytes(value, lock);
break;
case JSGC_SLICE_TIME_BUDGET:
defaultTimeBudget_ = value ? value : SliceBudget::UnlimitedTimeBudget;
@ -1350,14 +1348,14 @@ GCSchedulingTunables::setParameter(JSGCParamKey key, uint32_t value, const AutoL
float newFactor = value / 100.0;
if (newFactor <= 0.1 || newFactor > 1.0)
return false;
zoneAllocThresholdFactor_ = newFactor;
allocThresholdFactor_ = newFactor;
break;
}
case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT: {
float newFactor = value / 100.0;
if (newFactor <= 0.1 || newFactor > 1.0)
return false;
zoneAllocThresholdFactorAvoidInterrupt_ = newFactor;
allocThresholdFactorAvoidInterrupt_ = newFactor;
break;
}
case JSGC_MIN_EMPTY_CHUNK_COUNT:
@ -1416,9 +1414,8 @@ GCSchedulingTunables::GCSchedulingTunables()
: gcMaxBytes_(0),
gcMaxNurseryBytes_(0),
gcZoneAllocThresholdBase_(TuningDefaults::GCZoneAllocThresholdBase),
zoneAllocThresholdFactor_(TuningDefaults::ZoneAllocThresholdFactor),
zoneAllocThresholdFactorAvoidInterrupt_(
TuningDefaults::ZoneAllocThresholdFactorAvoidInterrupt),
allocThresholdFactor_(TuningDefaults::AllocThresholdFactor),
allocThresholdFactorAvoidInterrupt_(TuningDefaults::AllocThresholdFactorAvoidInterrupt),
zoneAllocDelayBytes_(TuningDefaults::ZoneAllocDelayBytes),
dynamicHeapGrowthEnabled_(TuningDefaults::DynamicHeapGrowthEnabled),
highFrequencyThresholdUsec_(TuningDefaults::HighFrequencyThresholdUsec),
@ -1438,9 +1435,7 @@ GCRuntime::resetParameter(JSGCParamKey key, AutoLockGC& lock)
{
switch (key) {
case JSGC_MAX_MALLOC_BYTES:
setMaxMallocBytes(0xffffffff);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->setGCMaxMallocBytes(maxMallocBytesAllocated() * 0.9);
setMaxMallocBytes(0xffffffff, lock);
break;
case JSGC_SLICE_TIME_BUDGET:
defaultTimeBudget_ = TuningDefaults::DefaultTimeBudget;
@ -1507,11 +1502,10 @@ GCSchedulingTunables::resetParameter(JSGCParamKey key, const AutoLockGC& lock)
gcZoneAllocThresholdBase_ = TuningDefaults::GCZoneAllocThresholdBase;
break;
case JSGC_ALLOCATION_THRESHOLD_FACTOR:
zoneAllocThresholdFactor_ = TuningDefaults::ZoneAllocThresholdFactor;
allocThresholdFactor_ = TuningDefaults::AllocThresholdFactor;
break;
case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT:
zoneAllocThresholdFactorAvoidInterrupt_ =
TuningDefaults::ZoneAllocThresholdFactorAvoidInterrupt;
allocThresholdFactorAvoidInterrupt_ = TuningDefaults::AllocThresholdFactorAvoidInterrupt;
break;
case JSGC_MIN_EMPTY_CHUNK_COUNT:
setMinEmptyChunkCount(TuningDefaults::MinEmptyChunkCount);
@ -1574,9 +1568,9 @@ GCRuntime::getParameter(JSGCParamKey key, const AutoLockGC& lock)
case JSGC_ALLOCATION_THRESHOLD:
return tunables.gcZoneAllocThresholdBase() / 1024 / 1024;
case JSGC_ALLOCATION_THRESHOLD_FACTOR:
return uint32_t(tunables.zoneAllocThresholdFactor() * 100);
return uint32_t(tunables.allocThresholdFactor() * 100);
case JSGC_ALLOCATION_THRESHOLD_FACTOR_AVOID_INTERRUPT:
return uint32_t(tunables.zoneAllocThresholdFactorAvoidInterrupt() * 100);
return uint32_t(tunables.allocThresholdFactorAvoidInterrupt() * 100);
case JSGC_MIN_EMPTY_CHUNK_COUNT:
return tunables.minEmptyChunkCount(lock);
case JSGC_MAX_EMPTY_CHUNK_COUNT:
@ -1816,19 +1810,11 @@ js::RemoveRawValueRoot(JSContext* cx, Value* vp)
}
void
GCRuntime::setMaxMallocBytes(size_t value)
GCRuntime::setMaxMallocBytes(size_t value, const AutoLockGC& lock)
{
mallocCounter.setMax(value);
mallocCounter.setMax(value, lock);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->setGCMaxMallocBytes(value);
}
void
GCRuntime::updateMallocCounter(JS::Zone* zone, size_t nbytes)
{
bool triggered = mallocCounter.update(this, nbytes);
if (!triggered && zone)
zone->updateMallocCounter(nbytes);
zone->setGCMaxMallocBytes(value * 0.9, lock);
}
double
@ -3178,56 +3164,76 @@ GCRuntime::triggerGC(JS::gcreason::Reason reason)
}
void
GCRuntime::maybeAllocTriggerZoneGC(Zone* zone, const AutoLockGC& lock)
GCRuntime::maybeAllocTriggerGC(Zone* zone, const AutoLockGC& lock)
{
size_t usedBytes = zone->usage.gcBytes();
size_t thresholdBytes = zone->threshold.gcTriggerBytes();
MOZ_ASSERT(!JS::CurrentThreadIsHeapCollecting());
if (!CurrentThreadCanAccessRuntime(rt)) {
/* Zones in use by a helper thread can't be collected. */
// Zones in use by a helper thread can't be collected.
MOZ_ASSERT(zone->usedByHelperThread() || zone->isAtomsZone());
return;
}
// Check GC bytes triggers.
size_t usedBytes = zone->usage.gcBytes();
size_t thresholdBytes = zone->threshold.gcTriggerBytes();
if (usedBytes >= thresholdBytes) {
/*
* The threshold has been surpassed, immediately trigger a GC,
* which will be done non-incrementally.
*/
// The threshold has been surpassed, immediately trigger a GC, which
// will be done non-incrementally.
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, thresholdBytes);
} else {
bool wouldInterruptCollection;
size_t igcThresholdBytes;
float zoneAllocThresholdFactor;
return;
}
wouldInterruptCollection = isIncrementalGCInProgress() &&
!zone->isCollecting();
zoneAllocThresholdFactor = wouldInterruptCollection ?
tunables.zoneAllocThresholdFactorAvoidInterrupt() :
tunables.zoneAllocThresholdFactor();
bool wouldInterruptCollection = isIncrementalGCInProgress() && !zone->isCollecting();
float zoneGCThresholdFactor =
wouldInterruptCollection ? tunables.allocThresholdFactorAvoidInterrupt()
: tunables.allocThresholdFactor();
igcThresholdBytes = thresholdBytes * zoneAllocThresholdFactor;
size_t igcThresholdBytes = thresholdBytes * zoneGCThresholdFactor;
if (usedBytes >= igcThresholdBytes) {
// Reduce the delay to the start of the next incremental slice.
if (zone->gcDelayBytes < ArenaSize)
zone->gcDelayBytes = 0;
else
zone->gcDelayBytes -= ArenaSize;
if (usedBytes >= igcThresholdBytes) {
// Reduce the delay to the start of the next incremental slice.
if (zone->gcDelayBytes < ArenaSize)
zone->gcDelayBytes = 0;
else
zone->gcDelayBytes -= ArenaSize;
if (!zone->gcDelayBytes) {
// Start or continue an in progress incremental GC. We do this
// to try to avoid performing non-incremental GCs on zones
// which allocate a lot of data, even when incremental slices
// can't be triggered via scheduling in the event loop.
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, igcThresholdBytes);
if (!zone->gcDelayBytes) {
// Start or continue an in progress incremental GC. We do this
// to try to avoid performing non-incremental GCs on zones
// which allocate a lot of data, even when incremental slices
// can't be triggered via scheduling in the event loop.
triggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER, usedBytes, igcThresholdBytes);
// Delay the next slice until a certain amount of allocation
// has been performed.
zone->gcDelayBytes = tunables.zoneAllocDelayBytes();
}
// Delay the next slice until a certain amount of allocation
// has been performed.
zone->gcDelayBytes = tunables.zoneAllocDelayBytes();
return;
}
}
// Check malloc bytes triggers.
size_t mallocBytes = mallocCounter.bytes();
wouldInterruptCollection = isIncrementalGCInProgress() && !isFull;
float fullGCThresholdFactor =
wouldInterruptCollection ? tunables.allocThresholdFactorAvoidInterrupt()
: tunables.allocThresholdFactor();
size_t mallocThesholdBytes = zone->GCMaxMallocBytes() * fullGCThresholdFactor;
if (mallocBytes > mallocThesholdBytes) {
stats().recordTrigger(mallocBytes, mallocThesholdBytes);
MOZ_ALWAYS_TRUE(triggerGC(JS::gcreason::TOO_MUCH_MALLOC));
return;
}
mallocBytes = zone->GCMallocBytes();
mallocThesholdBytes = zone->GCMaxMallocBytes() * zoneGCThresholdFactor;
if (mallocBytes > mallocThesholdBytes)
triggerZoneGC(zone, JS::gcreason::TOO_MUCH_MALLOC, mallocBytes, mallocThesholdBytes);
}
bool
@ -4265,6 +4271,8 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
if (isIncremental)
markCompartments();
updateMallocCountersOnGC();
/*
* Process any queued source compressions during the start of a major
* GC.
@ -4345,6 +4353,28 @@ GCRuntime::markCompartments()
}
}
void
GCRuntime::updateMallocCountersOnGC()
{
AutoLockGC lock(rt);
size_t totalBytesInCollectedZones = 0;
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
if (zone->isCollecting()) {
totalBytesInCollectedZones += zone->GCMallocBytes();
zone->updateGCMallocBytesOnGC(lock);
}
}
// Update the runtime malloc counter. If we are doing a full GC then clear
// it, otherwise decrement it by the previous malloc bytes count for the
// zones we did collect.
if (isFull)
mallocCounter.updateOnGC(lock);
else
mallocCounter.decrement(totalBytesInCollectedZones);
}
template <class ZoneIterT>
void
GCRuntime::markWeakReferences(gcstats::PhaseKind phase)
@ -7145,12 +7175,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
clearSelectedForMarking();
#endif
/* Clear gcMallocBytes for all zones. */
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
zone->resetAllMallocBytes();
resetMallocBytes();
TraceMajorGCEnd();
return IncrementalResult::Ok;
@ -7524,7 +7548,7 @@ GCRuntime::minorGC(JS::gcreason::Reason reason, gcstats::PhaseKind phase)
{
AutoLockGC lock(rt);
for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
maybeAllocTriggerZoneGC(zone, lock);
maybeAllocTriggerGC(zone, lock);
}
}
@ -7723,6 +7747,9 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target)
{
JSRuntime* rt = source->runtimeFromActiveCooperatingThread();
rt->gc.mergeCompartments(source, target);
AutoLockGC lock(rt);
rt->gc.maybeAllocTriggerGC(target->zone(), lock);
}
void
@ -7810,6 +7837,7 @@ GCRuntime::mergeCompartments(JSCompartment* source, JSCompartment* target)
target->zone()->arenas.adoptArenas(rt, &source->zone()->arenas, targetZoneIsCollecting);
target->zone()->usage.adopt(source->zone()->usage);
target->zone()->adoptUniqueIds(source->zone());
target->zone()->adoptMallocBytes(source->zone());
// Merge other info in source's zone into target's zone.
target->zone()->types.typeLifoAlloc().transferFrom(&source->zone()->types.typeLifoAlloc());

View File

@ -756,7 +756,7 @@ ArrayBufferObject::createForWasm(JSContext* cx, uint32_t initialSize,
auto contents = BufferContents::create<WASM>(wasmBuf->dataPointer());
buffer->initialize(initialSize, contents, OwnsData);
cx->zone()->updateMallocCounter(wasmBuf->mappedSize());
cx->updateMallocCounter(wasmBuf->mappedSize());
return buffer;
}
@ -801,7 +801,7 @@ ArrayBufferObject::prepareForAsmJS(JSContext* cx, Handle<ArrayBufferObject*> buf
buffer->changeContents(cx, BufferContents::create<WASM>(data), OwnsData);
buffer->setIsPreparedForAsmJS();
MOZ_ASSERT(data == buffer->dataPointer());
cx->zone()->updateMallocCounter(wasmBuf->mappedSize());
cx->updateMallocCounter(wasmBuf->mappedSize());
return true;
}
@ -1061,7 +1061,7 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
nAllocated = JS_ROUNDUP(nbytes, js::gc::SystemPageSize());
else if (contents.kind() == WASM)
nAllocated = contents.wasmBuffer()->allocatedBytes();
cx->zone()->updateMallocCounter(nAllocated);
cx->updateMallocCounter(nAllocated);
}
} else {
MOZ_ASSERT(ownsState == OwnsData);

View File

@ -74,7 +74,7 @@ GetTopProfilingJitFrame(Activation* act)
if (!jsExitFP)
return nullptr;
jit::JitProfilingFrameIterator iter(jsExitFP);
jit::JSJitProfilingFrameIterator iter(jsExitFP);
MOZ_ASSERT(!iter.done());
return iter.fp();
}

View File

@ -799,13 +799,7 @@ JSRuntime::forkRandomKeyGenerator()
void
JSRuntime::updateMallocCounter(size_t nbytes)
{
updateMallocCounter(nullptr, nbytes);
}
void
JSRuntime::updateMallocCounter(JS::Zone* zone, size_t nbytes)
{
gc.updateMallocCounter(zone, nbytes);
gc.updateMallocCounter(nbytes);
}
JS_FRIEND_API(void*)

View File

@ -960,7 +960,6 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
* the caller must ensure that no deadlock possible during OOM reporting.
*/
void updateMallocCounter(size_t nbytes);
void updateMallocCounter(JS::Zone* zone, size_t nbytes);
void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }

View File

@ -1865,10 +1865,10 @@ JS::ProfilingFrameIterator::ProfilingFrameIterator(JSContext* cx, const Register
MOZ_ASSERT(activation_->isProfiling());
static_assert(sizeof(wasm::ProfilingFrameIterator) <= StorageSpace &&
sizeof(jit::JitProfilingFrameIterator) <= StorageSpace,
sizeof(jit::JSJitProfilingFrameIterator) <= StorageSpace,
"ProfilingFrameIterator::storage_ is too small");
static_assert(alignof(void*) >= alignof(wasm::ProfilingFrameIterator) &&
alignof(void*) >= alignof(jit::JitProfilingFrameIterator),
alignof(void*) >= alignof(jit::JSJitProfilingFrameIterator),
"ProfilingFrameIterator::storage_ is too weakly aligned");
iteratorConstruct(state);
@ -1891,7 +1891,7 @@ JS::ProfilingFrameIterator::operator++()
if (isWasm())
++wasmIter();
else
++jitIter();
++jsJitIter();
settle();
}
@ -1899,8 +1899,8 @@ void
JS::ProfilingFrameIterator::settleFrames()
{
// Handle transition frames (see comment in JitFrameIter::operator++).
if (isJit() && !jitIter().done() && jitIter().frameType() == jit::JitFrame_WasmToJSJit) {
wasm::Frame* fp = (wasm::Frame*) jitIter().fp();
if (isJSJit() && !jsJitIter().done() && jsJitIter().frameType() == jit::JitFrame_WasmToJSJit) {
wasm::Frame* fp = (wasm::Frame*) jsJitIter().fp();
iteratorDestroy();
new (storage()) wasm::ProfilingFrameIterator(*activation_->asJit(), fp);
kind_ = Kind::Wasm;
@ -1943,7 +1943,7 @@ JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState& state)
return;
}
new (storage()) jit::JitProfilingFrameIterator(cx_, state);
new (storage()) jit::JSJitProfilingFrameIterator(cx_, state);
kind_ = Kind::JSJit;
}
@ -1964,7 +1964,7 @@ JS::ProfilingFrameIterator::iteratorConstruct()
return;
}
new (storage()) jit::JitProfilingFrameIterator(activation->jsExitFP());
new (storage()) jit::JSJitProfilingFrameIterator(activation->jsExitFP());
kind_ = Kind::JSJit;
}
@ -1979,7 +1979,7 @@ JS::ProfilingFrameIterator::iteratorDestroy()
return;
}
jitIter().~JitProfilingFrameIterator();
jsJitIter().~JSJitProfilingFrameIterator();
}
bool
@ -1991,7 +1991,7 @@ JS::ProfilingFrameIterator::iteratorDone()
if (isWasm())
return wasmIter().done();
return jitIter().done();
return jsJitIter().done();
}
void*
@ -2003,7 +2003,7 @@ JS::ProfilingFrameIterator::stackAddress() const
if (isWasm())
return wasmIter().stackAddress();
return jitIter().stackAddress();
return jsJitIter().stackAddress();
}
Maybe<JS::ProfilingFrameIterator::Frame>
@ -2021,10 +2021,10 @@ JS::ProfilingFrameIterator::getPhysicalFrameAndEntry(jit::JitcodeGlobalEntry* en
return mozilla::Some(frame);
}
MOZ_ASSERT(isJit());
MOZ_ASSERT(isJSJit());
// Look up an entry for the return address.
void* returnAddr = jitIter().returnAddressToFp();
void* returnAddr = jsJitIter().returnAddressToFp();
jit::JitcodeGlobalTable* table = cx_->runtime()->jitRuntime()->getJitcodeGlobalTable();
if (hasSampleBufferGen())
*entry = table->lookupForSamplerInfallible(returnAddr, cx_->runtime(), sampleBufferGen_);
@ -2067,7 +2067,7 @@ JS::ProfilingFrameIterator::extractStack(Frame* frames, uint32_t offset, uint32_
// Extract the stack for the entry. Assume maximum inlining depth is <64
const char* labels[64];
uint32_t depth = entry.callStackAtAddr(cx_->runtime(), jitIter().returnAddressToFp(),
uint32_t depth = entry.callStackAtAddr(cx_->runtime(), jsJitIter().returnAddressToFp(),
labels, ArrayLength(labels));
MOZ_ASSERT(depth < ArrayLength(labels));
for (uint32_t i = 0; i < depth; i++) {
@ -2095,7 +2095,7 @@ JS::ProfilingFrameIterator::isWasm() const
}
bool
JS::ProfilingFrameIterator::isJit() const
JS::ProfilingFrameIterator::isJSJit() const
{
return kind_ == Kind::JSJit;
}

View File

@ -92,7 +92,7 @@ FinishStringFlat(JSContext* cx, StringBuffer& sb, Buffer& cb)
* The allocation was made on a TempAllocPolicy, so account for the string
* data on the string's zone.
*/
str->zone()->updateMallocCounter(sizeof(CharT) * len);
cx->updateMallocCounter(sizeof(CharT) * len);
buf.forget();
return str;

View File

@ -1260,8 +1260,10 @@ nsFrameConstructorState::GetOutOfFlowFrameItems(nsIFrame* aNewFrame,
if (disp->mTopLayer != NS_STYLE_TOP_LAYER_NONE) {
*aPlaceholderType = PLACEHOLDER_FOR_TOPLAYER;
if (disp->mPosition == NS_STYLE_POSITION_FIXED) {
*aPlaceholderType |= PLACEHOLDER_FOR_FIXEDPOS;
return &mTopLayerFixedItems;
}
*aPlaceholderType |= PLACEHOLDER_FOR_ABSPOS;
return &mTopLayerAbsoluteItems;
}
if (disp->mPosition == NS_STYLE_POSITION_ABSOLUTE) {
@ -1303,11 +1305,11 @@ nsFrameConstructorState::ConstructBackdropFrameFor(nsIContent* aContent,
nsAbsoluteItems* frameItems = GetOutOfFlowFrameItems(backdropFrame,
true, true, false,
&placeholderType);
MOZ_ASSERT(placeholderType == PLACEHOLDER_FOR_TOPLAYER);
MOZ_ASSERT(placeholderType & PLACEHOLDER_FOR_TOPLAYER);
nsIFrame* placeholder = nsCSSFrameConstructor::
CreatePlaceholderFrameFor(mPresShell, aContent, backdropFrame,
frame, nullptr, PLACEHOLDER_FOR_TOPLAYER);
frame, nullptr, placeholderType);
nsFrameList temp(placeholder, placeholder);
frame->SetInitialChildList(nsIFrame::kBackdropList, temp);
@ -1361,7 +1363,7 @@ nsFrameConstructorState::AddChild(nsIFrame* aNewFrame,
// Add the placeholder frame to the flow
aFrameItems.AddChild(placeholderFrame);
if (placeholderType == PLACEHOLDER_FOR_TOPLAYER) {
if (placeholderType & PLACEHOLDER_FOR_TOPLAYER) {
ConstructBackdropFrameFor(aContent, aNewFrame);
}
}

View File

@ -1528,6 +1528,8 @@ nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
{
nsIFrame::ChildListID id = nsIFrame::kPrincipalList;
MOZ_DIAGNOSTIC_ASSERT(!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW));
if (aChildFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
nsIFrame* pif = aChildFrame->GetPrevInFlow();
if (pif->GetParent() == aChildFrame->GetParent()) {
@ -1536,35 +1538,6 @@ nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
else {
id = nsIFrame::kOverflowContainersList;
}
}
// See if the frame is moved out of the flow
else if (aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
// Look at the style information to tell
const nsStyleDisplay* disp = aChildFrame->StyleDisplay();
if (NS_STYLE_POSITION_ABSOLUTE == disp->mPosition) {
id = nsIFrame::kAbsoluteList;
} else if (NS_STYLE_POSITION_FIXED == disp->mPosition) {
if (nsLayoutUtils::IsReallyFixedPos(aChildFrame)) {
id = nsIFrame::kFixedList;
} else {
id = nsIFrame::kAbsoluteList;
}
#ifdef MOZ_XUL
} else if (StyleDisplay::MozPopup == disp->mDisplay) {
// Out-of-flows that are DISPLAY_POPUP must be kids of the root popup set
#ifdef DEBUG
nsIFrame* parent = aChildFrame->GetParent();
NS_ASSERTION(parent && parent->IsPopupSetFrame(), "Unexpected parent");
#endif // DEBUG
id = nsIFrame::kPopupList;
#endif // MOZ_XUL
} else {
NS_ASSERTION(aChildFrame->IsFloating(), "not a floated frame");
id = nsIFrame::kFloatList;
}
} else {
LayoutFrameType childType = aChildFrame->Type();
if (LayoutFrameType::MenuPopup == childType) {
@ -1599,19 +1572,8 @@ nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
nsContainerFrame* parent = aChildFrame->GetParent();
bool found = parent->GetChildList(id).ContainsFrame(aChildFrame);
if (!found) {
if (!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
found = parent->GetChildList(nsIFrame::kOverflowList)
.ContainsFrame(aChildFrame);
}
else if (aChildFrame->IsFloating()) {
found = parent->GetChildList(nsIFrame::kOverflowOutOfFlowList)
.ContainsFrame(aChildFrame);
if (!found) {
found = parent->GetChildList(nsIFrame::kPushedFloatsList)
.ContainsFrame(aChildFrame);
}
}
// else it's positioned and should have been on the 'id' child list.
found = parent->GetChildList(nsIFrame::kOverflowList)
.ContainsFrame(aChildFrame);
NS_POSTCONDITION(found, "not in child list");
}
#endif
@ -7426,14 +7388,19 @@ nsLayoutUtils::GetDeviceContextForScreenInfo(nsPIDOMWindowOuter* aWindow)
}
/* static */ bool
nsLayoutUtils::IsReallyFixedPos(nsIFrame* aFrame)
nsLayoutUtils::IsReallyFixedPos(const nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame->GetParent(),
"IsReallyFixedPos called on frame not in tree");
NS_PRECONDITION(aFrame->StyleDisplay()->mPosition ==
NS_STYLE_POSITION_FIXED,
"IsReallyFixedPos called on non-'position:fixed' frame");
MOZ_ASSERT(aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED,
"IsReallyFixedPos called on non-'position:fixed' frame");
return MayBeReallyFixedPos(aFrame);
}
/* static */ bool
nsLayoutUtils::MayBeReallyFixedPos(const nsIFrame* aFrame)
{
MOZ_ASSERT(aFrame->GetParent(),
"MayBeReallyFixedPos called on frame not in tree");
LayoutFrameType parentType = aFrame->GetParent()->Type();
return parentType == LayoutFrameType::Viewport ||
parentType == LayoutFrameType::PageContent;

View File

@ -2087,12 +2087,23 @@ public:
GetDeviceContextForScreenInfo(nsPIDOMWindowOuter* aWindow);
/**
* Some frames with 'position: fixed' (nsStylePosition::mDisplay ==
* Some frames with 'position: fixed' (nsStyleDisplay::mPosition ==
* NS_STYLE_POSITION_FIXED) are not really fixed positioned, since
* they're inside an element with -moz-transform. This function says
* whether such an element is a real fixed-pos element.
*/
static bool IsReallyFixedPos(nsIFrame* aFrame);
static bool IsReallyFixedPos(const nsIFrame* aFrame);
/**
* This function says whether `aFrame` would really be a fixed positioned
* frame if the frame was created with NS_STYLE_POSITION_FIXED.
*
* It is effectively the same as IsReallyFixedPos, but without asserting the
* position value. Use it only when you know what you're doing, like when
* tearing down the frame tree (where styles may have changed due to
* ::first-line reparenting and rule changes at the same time).
*/
static bool MayBeReallyFixedPos(const nsIFrame* aFrame);
/**
* Obtain a SourceSurface from the given DOM element, if possible.

View File

@ -634,7 +634,7 @@ load text-overflow-form-elements.html
load text-overflow-iframe.html
asserts(1-4) load 1225005.html # bug 682647 and bug 448083
load 1233191.html
asserts-if(stylo,0-15) load 1271765.html # bug 1324684
load 1271765.html
asserts(2) load 1272983-1.html # bug 586628
asserts(2) load 1272983-2.html # bug 586628
load 1275059.html

View File

@ -25,9 +25,9 @@ using namespace mozilla::gfx;
nsIFrame*
NS_NewPlaceholderFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
nsFrameState aTypeBit)
nsFrameState aTypeBits)
{
return new (aPresShell) nsPlaceholderFrame(aContext, aTypeBit);
return new (aPresShell) nsPlaceholderFrame(aContext, aTypeBits);
}
NS_IMPL_FRAMEARENA_HELPERS(nsPlaceholderFrame)
@ -155,6 +155,26 @@ nsPlaceholderFrame::Reflow(nsPresContext* aPresContext,
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
}
static nsIFrame::ChildListID
ChildListIDForOutOfFlow(nsFrameState aPlaceholderState, const nsIFrame* aChild)
{
if (aPlaceholderState & PLACEHOLDER_FOR_FLOAT) {
return nsIFrame::kFloatList;
}
if (aPlaceholderState & PLACEHOLDER_FOR_POPUP) {
return nsIFrame::kPopupList;
}
if (aPlaceholderState & PLACEHOLDER_FOR_FIXEDPOS) {
return nsLayoutUtils::MayBeReallyFixedPos(aChild)
? nsIFrame::kFixedList : nsIFrame::kAbsoluteList;
}
if (aPlaceholderState & PLACEHOLDER_FOR_ABSPOS) {
return nsIFrame::kAbsoluteList;
}
MOZ_DIAGNOSTIC_ASSERT(false, "unknown list");
return nsIFrame::kFloatList;
}
void
nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
@ -162,12 +182,13 @@ nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
if (oof) {
mOutOfFlowFrame = nullptr;
oof->DeleteProperty(nsIFrame::PlaceholderFrameProperty());
// If aDestructRoot is not an ancestor of the out-of-flow frame,
// then call RemoveFrame on it here.
// Also destroy it here if it's a popup frame. (Bug 96291)
if ((GetStateBits() & PLACEHOLDER_FOR_POPUP) ||
!nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof)) {
ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof);
ChildListID listId = ChildListIDForOutOfFlow(GetStateBits(), oof);
nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager();
fm->RemoveFrame(listId, oof);
}

View File

@ -40,7 +40,7 @@
nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext,
nsFrameState aTypeBit);
nsFrameState aTypeBits);
#define PLACEHOLDER_TYPE_MASK (PLACEHOLDER_FOR_FLOAT | \
PLACEHOLDER_FOR_ABSPOS | \
@ -65,18 +65,19 @@ public:
*/
friend nsIFrame* NS_NewPlaceholderFrame(nsIPresShell* aPresShell,
nsStyleContext* aContext,
nsFrameState aTypeBit);
nsPlaceholderFrame(nsStyleContext* aContext, nsFrameState aTypeBit)
nsFrameState aTypeBits);
nsPlaceholderFrame(nsStyleContext* aContext, nsFrameState aTypeBits)
: nsFrame(aContext, kClassID)
, mOutOfFlowFrame(nullptr)
{
NS_PRECONDITION(aTypeBit == PLACEHOLDER_FOR_FLOAT ||
aTypeBit == PLACEHOLDER_FOR_ABSPOS ||
aTypeBit == PLACEHOLDER_FOR_FIXEDPOS ||
aTypeBit == PLACEHOLDER_FOR_POPUP ||
aTypeBit == PLACEHOLDER_FOR_TOPLAYER,
"Unexpected type bit");
AddStateBits(aTypeBit);
MOZ_ASSERT(aTypeBits == PLACEHOLDER_FOR_FLOAT ||
aTypeBits == PLACEHOLDER_FOR_ABSPOS ||
aTypeBits == PLACEHOLDER_FOR_FIXEDPOS ||
aTypeBits == PLACEHOLDER_FOR_POPUP ||
aTypeBits == (PLACEHOLDER_FOR_TOPLAYER | PLACEHOLDER_FOR_ABSPOS) ||
aTypeBits == (PLACEHOLDER_FOR_TOPLAYER | PLACEHOLDER_FOR_FIXEDPOS),
"Unexpected type bit");
AddStateBits(aTypeBits);
}
// Get/Set the associated out of flow frame

View File

@ -1,4 +1,4 @@
fuzzy-if(skiaContent,1,10) HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
fuzzy-if(skiaContent,1,10) fuzzy-if(Android,2,10) HTTP(..) == text-control-baseline-1.html text-control-baseline-1-ref.html
fuzzy-if(cocoaWidget,16,64) fuzzy-if(Android,52,64) fuzzy-if(winWidget,88,624) == display-block-baselines-1.html display-block-baselines-1-ref.html # anti-aliasing issues
== display-block-baselines-2.html display-block-baselines-2-ref.html
== display-block-baselines-3.html display-block-baselines-3-ref.html

View File

@ -149,12 +149,14 @@ CSSVariableResolver::ResolveVariable(size_t aID)
}
nsString resolvedValue;
nsCSSTokenSerializationType firstToken, lastToken;
if (!mParser.ResolveVariableValue(mVariables[aID].mValue, mOutput,
resolvedValue, firstToken, lastToken)) {
resolvedValue.Truncate(0);
if (mParser.ResolveVariableValue(mVariables[aID].mValue, mOutput,
resolvedValue, firstToken, lastToken)) {
mOutput->Put(mVariables[aID].mVariableName, resolvedValue,
firstToken, lastToken);
} else {
mOutput->Put(mVariables[aID].mVariableName, EmptyString(),
eCSSTokenSerialization_Nothing, eCSSTokenSerialization_Nothing);
}
mOutput->Put(mVariables[aID].mVariableName, resolvedValue,
firstToken, lastToken);
}
mVariables[aID].mResolved = true;
}

View File

@ -0,0 +1,12 @@
<style></style>
<script>
document.documentElement.className = 'c1'
o1 = document.createElement('form')
o2 = document.createElement('e')
o1.className = 'c2'
document.documentElement.appendChild(o1)
document.documentElement.appendChild(o2)
document.styleSheets[0].insertRule('.c1:first-line, .c2 { position:fixed', 0);
document.documentElement.getBoundingClientRect()
document.styleSheets[0].cssRules[0].style.position = 'relative'
</script>

View File

@ -0,0 +1,10 @@
<style>
del, *::first-line {
position: absolute;
}
</style>
<del></del>
<script>
document.documentElement.offsetTop;
document.styleSheets[0].cssRules[0].style.position = 'sticky'
</script>

View File

@ -0,0 +1,14 @@
<style>
del {
position: absolute;
}
body::first-line {
color: red;
}
</style>
<del></del>
<script>
document.documentElement.offsetTop;
document.styleSheets[0].cssRules[0].style.position = 'sticky'
</script>

View File

@ -241,3 +241,6 @@ load 1403615.html
load 1403712.html
load 1404180-1.html
load 1404316.html
load 1404324-1.html
load 1404324-2.html
load 1404324-3.html

View File

@ -668,14 +668,7 @@ function BuildConditionSandbox(aURL) {
var env = CC["@mozilla.org/process/environment;1"].
getService(CI.nsIEnvironment);
// xr.XPCOMABI throws exception for configurations without full ABI
// support (mobile builds on ARM)
var XPCOMABI = "";
try {
XPCOMABI = xr.XPCOMABI;
} catch(e) {}
sandbox.xulRuntime = CU.cloneInto({widgetToolkit: xr.widgetToolkit, OS: xr.OS, XPCOMABI: XPCOMABI}, sandbox);
sandbox.xulRuntime = CU.cloneInto({widgetToolkit: xr.widgetToolkit, OS: xr.OS, XPCOMABI: xr.XPCOMABI}, sandbox);
var testRect = gBrowser.getBoundingClientRect();
sandbox.smallScreen = false;

View File

@ -246,7 +246,8 @@ class ReftestArgumentsParser(argparse.ArgumentParser):
self.add_argument("--verify",
action="store_true",
default=False,
help="Test verification mode.")
help="Run tests in verification mode: Run many times in different "
"ways, to see if there are intermittent failures.")
self.add_argument("--verify-max-time",
type=int,

View File

@ -556,7 +556,8 @@ class GeckoInputConnection
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_PASSWORD;
else if (mIMEState == IME_STATE_PLUGIN)
outAttrs.inputType = InputType.TYPE_NULL; // "send key events" mode
else if (mIMETypeHint.equalsIgnoreCase("url"))
else if (mIMETypeHint.equalsIgnoreCase("url") ||
mIMETypeHint.equalsIgnoreCase("mozAwesomebar"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_URI;
else if (mIMETypeHint.equalsIgnoreCase("email"))
outAttrs.inputType |= InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;

View File

@ -1903,7 +1903,7 @@ MOZ_ARG_WITH_BOOL(system-nss,
_USE_SYSTEM_NSS=1 )
if test -n "$_USE_SYSTEM_NSS"; then
AM_PATH_NSS(3.33, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
AM_PATH_NSS(3.34, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
fi
if test -n "$MOZ_SYSTEM_NSS"; then

View File

@ -263,6 +263,7 @@ NSS_Init
NSS_Initialize
NSS_InitWithMerge
NSS_IsInitialized
NSS_OptionGet
NSS_OptionSet
NSS_NoDB_Init
NSS_SecureMemcmp

View File

@ -1 +1 @@
NSS_3_33_RTM
6fb9c5396d52

View File

@ -1 +1 @@
NSS_3_32_BRANCH
NSS_3_33_BRANCH

View File

@ -236,11 +236,14 @@ check_abi()
BASE_NSPR=NSPR_$(head -1 ${HGDIR}/baseline/nss/automation/release/nspr-version.txt | cut -d . -f 1-2 | tr . _)_BRANCH
hg clone -u "${BASE_NSPR}" "${HGDIR}/nspr" "${HGDIR}/baseline/nspr"
if [ $? -ne 0 ]; then
echo "invalid tag ${BASE_NSPR} derived from ${BASE_NSS} automation/release/nspr-version.txt"
return 1
echo "nonexisting tag ${BASE_NSPR} derived from ${BASE_NSS} automation/release/nspr-version.txt"
# Assume that version hasn't been released yet, fall back to trunk
pushd "${HGDIR}/baseline/nspr"
hg update default
popd
fi
print_log "######## building older NSPR/NSS ########"
print_log "######## building baseline NSPR/NSS ########"
pushd ${HGDIR}/baseline/nss
print_log "$ ${MAKE} ${NSS_BUILD_TARGET}"

View File

@ -263,8 +263,7 @@ async function scheduleMac(name, base, args = "") {
},
provisioner: "localprovisioner",
workerType: "nss-macos-10-12",
platform: "mac",
tier: 3
platform: "mac"
});
// Build base definition.

View File

@ -3010,6 +3010,33 @@ certutil_main(int argc, char **argv, PRBool initialize)
}
}
/* if we are going to modify the cert database,
* make sure it's initialized */
if (certutil.commands[cmd_ModifyCertTrust].activated ||
certutil.commands[cmd_CreateAndAddCert].activated ||
certutil.commands[cmd_AddCert].activated ||
certutil.commands[cmd_AddEmailCert].activated) {
if (PK11_NeedUserInit(slot)) {
char *password = NULL;
/* fetch the password from the command line or the file
* if no password is supplied, initialize the password to NULL */
if (pwdata.source == PW_FROMFILE) {
password = SECU_FilePasswd(slot, PR_FALSE, pwdata.data);
} else if (pwdata.source == PW_PLAINTEXT) {
password = PL_strdup(pwdata.data);
}
rv = PK11_InitPin(slot, (char *)NULL, password ? password : "");
if (password) {
PORT_Memset(password, 0, PL_strlen(password));
PORT_Free(password);
}
if (rv != SECSuccess) {
SECU_PrintError(progName, "Could not set password for the slot");
goto shutdown;
}
}
}
/* walk through the upgrade merge if necessary.
* This option is more to test what some applications will want to do
* to do an automatic upgrade. The --merge command is more useful for

View File

@ -57,6 +57,7 @@ typedef enum {
UNSPECIFIED_ERR,
NOCERTDB_MISUSE_ERR,
NSS_INITIALIZE_FAILED_ERR,
INITPW_FAILED_ERR,
LAST_ERR /* must be last */
} Error;
@ -110,7 +111,8 @@ static char *errStrings[] = {
"ERROR: Unable to read from standard input.\n",
"ERROR: Unknown error occurred.\n",
"ERROR: -nocertdb option can only be used with the -jar command.\n",
"ERROR: NSS_Initialize() failed.\n"
"ERROR: NSS_Initialize() failed.\n",
"ERROR: Unable to set initial password on the database.\n"
};
typedef enum {

View File

@ -865,7 +865,7 @@ main(int argc, char* argv[])
errcode = ChangePW(tokenName, pwFile, newpwFile);
break;
case CREATE_COMMAND:
/* The work was already done in init_crypto() */
errcode = InitPW();
break;
case DEFAULT_COMMAND:
errcode = SetDefaultModule(moduleName, slotName, mechanisms);

View File

@ -29,6 +29,7 @@ Error AddModule(char *moduleName, char *libFile, char *ciphers,
Error DeleteModule(char *moduleName);
Error ListModule(char *moduleName);
Error ListModules();
Error InitPW(void);
Error ChangePW(char *tokenName, char *pwFile, char *newpwFile);
Error EnableModule(char *moduleName, char *slotName, PRBool enable);
Error RawAddModule(char *dbmodulespec, char *modulespec);

View File

@ -668,6 +668,39 @@ loser:
return rv;
}
/************************************************************************
*
* I n i t P W
*/
Error
InitPW(void)
{
PK11SlotInfo *slot;
Error ret = UNSPECIFIED_ERR;
slot = PK11_GetInternalKeySlot();
if (!slot) {
PR_fprintf(PR_STDERR, errStrings[NO_SUCH_TOKEN_ERR], "internal");
return NO_SUCH_TOKEN_ERR;
}
/* Set the initial password to empty */
if (PK11_NeedUserInit(slot)) {
if (PK11_InitPin(slot, NULL, "") != SECSuccess) {
PR_fprintf(PR_STDERR, errStrings[INITPW_FAILED_ERR]);
ret = INITPW_FAILED_ERR;
goto loser;
}
}
ret = SUCCESS;
loser:
PK11_FreeSlot(slot);
return ret;
}
/************************************************************************
*
* C h a n g e P W

View File

@ -23,6 +23,7 @@
static char *progName;
PRBool pk12_debugging = PR_FALSE;
PRBool dumpRawFile;
static PRBool pk12uForceUnicode;
PRIntn pk12uErrno = 0;
@ -357,6 +358,7 @@ p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
SECItem p12file = { 0 };
SECStatus rv = SECFailure;
PRBool swapUnicode = PR_FALSE;
PRBool forceUnicode = pk12uForceUnicode;
PRBool trypw;
int error;
@ -424,6 +426,18 @@ p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
SEC_PKCS12DecoderFinish(p12dcx);
uniPwp->len = 0;
trypw = PR_TRUE;
} else if (forceUnicode == pk12uForceUnicode) {
/* try again with a different password encoding */
forceUnicode = !pk12uForceUnicode;
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
forceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decoding failed to set option");
pk12uErrno = PK12UERR_DECODEVERIFY;
break;
}
SEC_PKCS12DecoderFinish(p12dcx);
trypw = PR_TRUE;
} else {
SECU_PrintError(progName, "PKCS12 decode not verified");
pk12uErrno = PK12UERR_DECODEVERIFY;
@ -431,6 +445,15 @@ p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
}
}
} while (trypw == PR_TRUE);
/* revert the option setting */
if (forceUnicode != pk12uForceUnicode) {
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decoding failed to set option");
pk12uErrno = PK12UERR_DECODEVERIFY;
}
}
/* rv has been set at this point */
done:
@ -470,6 +493,8 @@ P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
{
SEC_PKCS12DecoderContext *p12dcx = NULL;
SECItem uniPwitem = { 0 };
PRBool forceUnicode = pk12uForceUnicode;
PRBool trypw;
SECStatus rv = SECFailure;
rv = P12U_InitSlot(slot, slotPw);
@ -480,31 +505,62 @@ P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
return rv;
}
rv = SECFailure;
p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
do {
trypw = PR_FALSE; /* normally we do this once */
rv = SECFailure;
p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
if (p12dcx == NULL) {
goto loser;
}
/* make sure the bags are okey dokey -- nicknames correct, etc. */
rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
if (rv != SECSuccess) {
if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
pk12uErrno = PK12UERR_CERTALREADYEXISTS;
} else {
pk12uErrno = PK12UERR_DECODEVALIBAGS;
if (p12dcx == NULL) {
goto loser;
}
SECU_PrintError(progName, "PKCS12 decode validate bags failed");
goto loser;
}
/* stuff 'em in */
rv = SEC_PKCS12DecoderImportBags(p12dcx);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decode import bags failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
/* make sure the bags are okey dokey -- nicknames correct, etc. */
rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
if (rv != SECSuccess) {
if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
pk12uErrno = PK12UERR_CERTALREADYEXISTS;
} else {
pk12uErrno = PK12UERR_DECODEVALIBAGS;
}
SECU_PrintError(progName, "PKCS12 decode validate bags failed");
goto loser;
}
/* stuff 'em in */
if (forceUnicode != pk12uForceUnicode) {
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
forceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decode set option failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
}
}
rv = SEC_PKCS12DecoderImportBags(p12dcx);
if (rv != SECSuccess) {
if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY &&
forceUnicode == pk12uForceUnicode) {
/* try again with a different password encoding */
forceUnicode = !pk12uForceUnicode;
SEC_PKCS12DecoderFinish(p12dcx);
SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
trypw = PR_TRUE;
} else {
SECU_PrintError(progName, "PKCS12 decode import bags failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
}
}
} while (trypw);
/* revert the option setting */
if (forceUnicode != pk12uForceUnicode) {
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decode set option failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
}
}
fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
@ -947,6 +1003,7 @@ main(int argc, char **argv)
int keyLen = 0;
int certKeyLen = 0;
secuCommand pk12util;
PRInt32 forceUnicode;
#ifdef _CRTDBG_MAP_ALLOC
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
@ -978,6 +1035,14 @@ main(int argc, char **argv)
Usage(progName);
}
rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE, &forceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName,
"Failed to get NSS_PKCS12_DECODE_FORCE_UNICODE option");
Usage(progName);
}
pk12uForceUnicode = forceUnicode;
slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
import_file = (pk12util.options[opt_List].activated) ? SECU_GetOptionArg(&pk12util, opt_List)

View File

@ -173,7 +173,7 @@
},
},
}],
[ 'target_arch=="arm64" or target_arch=="aarch64" or target_arch=="sparc64"', {
[ 'target_arch=="arm64" or target_arch=="aarch64" or target_arch=="sparc64" or target_arch=="ppc64" or target_arch=="ppc64le" or target_arch=="s390x" or target_arch=="mips64"', {
'defines': [
'NSS_USE_64',
],

View File

@ -10,3 +10,4 @@
*/
#error "Do not include this header file."

View File

@ -10,6 +10,7 @@
class DummyPrSocket : public DummyIOLayerMethods {
public:
DummyPrSocket(const uint8_t *buf, size_t len) : buf_(buf), len_(len) {}
virtual ~DummyPrSocket() {}
int32_t Read(PRFileDesc *f, void *data, int32_t len) override;
int32_t Write(PRFileDesc *f, const void *buf, int32_t length) override;

View File

@ -29,6 +29,7 @@ CPPSRCS = \
ssl_gather_unittest.cc \
ssl_gtest.cc \
ssl_hrr_unittest.cc \
ssl_keylog_unittest.cc \
ssl_loopback_unittest.cc \
ssl_misc_unittest.cc \
ssl_record_unittest.cc \

View File

@ -536,7 +536,8 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
SendReceive(); // Need to read so that we absorb the session ticket.
CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@ -549,7 +550,8 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
server_->SetPacketFilter(serverCapture);
ExpectResumption(RESUME_TICKET);
Connect();
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_none);
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ASSERT_LT(0UL, clientCapture->extension().len());
ASSERT_LT(0UL, serverCapture->extension().len());
}

View File

@ -30,6 +30,7 @@
'ssl_gather_unittest.cc',
'ssl_gtest.cc',
'ssl_hrr_unittest.cc',
'ssl_keylog_unittest.cc',
'ssl_loopback_unittest.cc',
'ssl_misc_unittest.cc',
'ssl_record_unittest.cc',

View File

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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 <cstdlib>
#include <fstream>
#include <sstream>
#include "gtest_utils.h"
#include "tls_connect.h"
namespace nss_test {
static const std::string keylog_file_path = "keylog.txt";
class KeyLogFileTest : public TlsConnectGeneric {
public:
void SetUp() {
TlsConnectTestBase::SetUp();
remove(keylog_file_path.c_str());
std::ostringstream sstr;
sstr << "SSLKEYLOGFILE=" << keylog_file_path;
PR_SetEnv(sstr.str().c_str());
}
void CheckKeyLog() {
std::ifstream f(keylog_file_path);
std::map<std::string, size_t> labels;
std::string last_client_random;
for (std::string line; std::getline(f, line);) {
if (line[0] == '#') {
continue;
}
std::istringstream iss(line);
std::string label, client_random, secret;
iss >> label >> client_random >> secret;
ASSERT_EQ(1U, client_random.size());
ASSERT_TRUE(last_client_random.empty() ||
last_client_random == client_random);
last_client_random = client_random;
labels[label]++;
}
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
ASSERT_EQ(1U, labels["CLIENT_RANDOM"]);
} else {
ASSERT_EQ(1U, labels["CLIENT_EARLY_TRAFFIC_SECRET"]);
ASSERT_EQ(1U, labels["CLIENT_HANDSHAKE_TRAFFIC_SECRET"]);
ASSERT_EQ(1U, labels["SERVER_HANDSHAKE_TRAFFIC_SECRET"]);
ASSERT_EQ(1U, labels["CLIENT_TRAFFIC_SECRET_0"]);
ASSERT_EQ(1U, labels["SERVER_TRAFFIC_SECRET_0"]);
ASSERT_EQ(1U, labels["EXPORTER_SECRET"]);
}
}
void ConnectAndCheck() {
Connect();
CheckKeyLog();
_exit(0);
}
};
// Tests are run in a separate process to ensure that NSS is not initialized yet
// and can process the SSLKEYLOGFILE environment variable.
TEST_P(KeyLogFileTest, KeyLogFile) {
testing::GTEST_FLAG(death_test_style) = "threadsafe";
ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
}
INSTANTIATE_TEST_CASE_P(
KeyLogFileDTLS12, KeyLogFileTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(
KeyLogFileTLS12, KeyLogFileTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsV10ToV12));
#ifndef NSS_DISABLE_TLS_1_3
INSTANTIATE_TEST_CASE_P(
KeyLogFileTLS13, KeyLogFileTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsV13));
#endif
} // namespace nss_test

View File

@ -396,7 +396,8 @@ TEST_P(TlsConnectTls13, TestTls13ResumeDifferentGroup) {
client_->ConfigNamedGroups(kFFDHEGroups);
server_->ConfigNamedGroups(kFFDHEGroups);
Connect();
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_none);
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
}
// We need to enable different cipher suites at different times in the following
@ -604,7 +605,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_none);
ssl_sig_rsa_pss_sha256);
// The filter will go away when we reset, so save the captured extension.
DataBuffer initialTicket(c1->extension());
ASSERT_LT(0U, initialTicket.len());
@ -622,7 +623,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_none);
ssl_sig_rsa_pss_sha256);
ASSERT_LT(0U, c2->extension().len());
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
@ -723,4 +724,61 @@ TEST_F(TlsConnectTest, TestTls13ResumptionForcedDowngrade) {
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
}
TEST_P(TlsConnectGeneric, ReConnectTicket) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
// Resume
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);
Connect();
// Only the client knows this.
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
}
TEST_P(TlsConnectGenericPre13, ReConnectCache) {
ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
// Resume
Reset();
ExpectResumption(RESUME_SESSIONID);
Connect();
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
}
TEST_P(TlsConnectGeneric, ReConnectAgainTicket) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
// Resume
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);
Connect();
// Only the client knows this.
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
// Resume connection again
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET, 2);
Connect();
// Only the client knows this.
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
}
} // namespace nss_test

View File

@ -495,6 +495,12 @@ void TlsAgent::CheckKEA(SSLKEAType kea_type, SSLNamedGroup kea_group,
}
}
void TlsAgent::CheckOriginalKEA(SSLNamedGroup kea_group) const {
if (kea_group != ssl_grp_ffdhe_custom) {
EXPECT_EQ(kea_group, info_.originalKeaGroup);
}
}
void TlsAgent::CheckAuthType(SSLAuthType auth_type,
SSLSignatureScheme sig_scheme) const {
EXPECT_EQ(STATE_CONNECTED, state_);
@ -720,6 +726,8 @@ void TlsAgent::Connected() {
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(sizeof(info_), info_.length);
EXPECT_EQ(expect_resumption_, info_.resumed == PR_TRUE);
// Preliminary values are exposed through callbacks during the handshake.
// If either expected values were set or the callbacks were called, check
// that the final values are correct.

View File

@ -95,6 +95,7 @@ class TlsAgent : public PollTarget {
void StartConnect(PRFileDesc* model = nullptr);
void CheckKEA(SSLKEAType kea_type, SSLNamedGroup group,
size_t kea_size = 0) const;
void CheckOriginalKEA(SSLNamedGroup kea_group) const;
void CheckAuthType(SSLAuthType auth_type,
SSLSignatureScheme sig_scheme) const;

View File

@ -113,6 +113,7 @@ TlsConnectTestBase::TlsConnectTestBase(SSLProtocolVariant variant,
server_model_(nullptr),
version_(version),
expected_resumption_mode_(RESUME_NONE),
expected_resumptions_(0),
session_ids_(),
expect_extended_master_secret_(false),
expect_early_data_accepted_(false),
@ -220,12 +221,15 @@ void TlsConnectTestBase::Reset(const std::string& server_name,
Init();
}
void TlsConnectTestBase::ExpectResumption(SessionResumptionMode expected) {
void TlsConnectTestBase::ExpectResumption(SessionResumptionMode expected,
uint8_t num_resumptions) {
expected_resumption_mode_ = expected;
if (expected != RESUME_NONE) {
client_->ExpectResumption();
server_->ExpectResumption();
expected_resumptions_ = num_resumptions;
}
EXPECT_EQ(expected_resumptions_ == 0, expected == RESUME_NONE);
}
void TlsConnectTestBase::EnsureTlsSetup() {
@ -315,10 +319,12 @@ void TlsConnectTestBase::CheckConnected() {
void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
SSLAuthType auth_type,
SSLSignatureScheme sig_scheme) const {
client_->CheckKEA(kea_type, kea_group);
server_->CheckKEA(kea_type, kea_group);
client_->CheckAuthType(auth_type, sig_scheme);
if (kea_group != ssl_grp_none) {
client_->CheckKEA(kea_type, kea_group);
server_->CheckKEA(kea_type, kea_group);
}
server_->CheckAuthType(auth_type, sig_scheme);
client_->CheckAuthType(auth_type, sig_scheme);
}
void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type,
@ -373,6 +379,17 @@ void TlsConnectTestBase::CheckKeys() const {
CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
}
void TlsConnectTestBase::CheckKeysResumption(SSLKEAType kea_type,
SSLNamedGroup kea_group,
SSLNamedGroup original_kea_group,
SSLAuthType auth_type,
SSLSignatureScheme sig_scheme) {
CheckKeys(kea_type, kea_group, auth_type, sig_scheme);
EXPECT_TRUE(expected_resumption_mode_ != RESUME_NONE);
client_->CheckOriginalKEA(original_kea_group);
server_->CheckOriginalKEA(original_kea_group);
}
void TlsConnectTestBase::ConnectExpectFail() {
server_->StartConnect();
client_->StartConnect();
@ -477,8 +494,8 @@ void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client,
void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
EXPECT_NE(RESUME_BOTH, expected);
int resume_count = expected ? 1 : 0;
int stateless_count = (expected & RESUME_TICKET) ? 1 : 0;
int resume_count = expected ? expected_resumptions_ : 0;
int stateless_count = (expected & RESUME_TICKET) ? expected_resumptions_ : 0;
// Note: hch == server counter; hsh == client counter.
SSL3Statistics* stats = SSL_GetStatistics();
@ -491,7 +508,7 @@ void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
if (expected != RESUME_NONE) {
if (client_->version() < SSL_LIBRARY_VERSION_TLS_1_3) {
// Check that the last two session ids match.
ASSERT_EQ(2U, session_ids_.size());
ASSERT_EQ(1U + expected_resumptions_, session_ids_.size());
EXPECT_EQ(session_ids_[session_ids_.size() - 1],
session_ids_[session_ids_.size() - 2]);
} else {

View File

@ -81,6 +81,11 @@ class TlsConnectTestBase : public ::testing::Test {
void CheckKeys(SSLKEAType kea_type, SSLAuthType auth_type) const;
// This version assumes defaults.
void CheckKeys() const;
// Check that keys on resumed sessions.
void CheckKeysResumption(SSLKEAType kea_type, SSLNamedGroup kea_group,
SSLNamedGroup original_kea_group,
SSLAuthType auth_type,
SSLSignatureScheme sig_scheme);
void CheckGroups(const DataBuffer& groups,
std::function<void(SSLNamedGroup)> check_group);
void CheckShares(const DataBuffer& shares,
@ -89,7 +94,8 @@ class TlsConnectTestBase : public ::testing::Test {
void ConfigureVersion(uint16_t version);
void SetExpectedVersion(uint16_t version);
// Expect resumption of a particular type.
void ExpectResumption(SessionResumptionMode expected);
void ExpectResumption(SessionResumptionMode expected,
uint8_t num_resumed = 1);
void DisableAllCiphers();
void EnableOnlyStaticRsaCiphers();
void EnableOnlyDheCiphers();
@ -123,6 +129,7 @@ class TlsConnectTestBase : public ::testing::Test {
std::unique_ptr<TlsAgent> server_model_;
uint16_t version_;
SessionResumptionMode expected_resumption_mode_;
uint8_t expected_resumptions_;
std::vector<std::vector<uint8_t>> session_ids_;
// A simple value of "a", "b". Note that the preferred value of "a" is placed

View File

@ -20,7 +20,7 @@ class TlsRecordHeader;
class AeadCipher {
public:
AeadCipher(CK_MECHANISM_TYPE mech) : mech_(mech), key_(nullptr) {}
~AeadCipher();
virtual ~AeadCipher();
bool Init(PK11SymKey *key, const uint8_t *iv);
virtual bool Aead(bool decrypt, uint64_t seq, const uint8_t *in, size_t inlen,

View File

@ -110,7 +110,9 @@ endif
# NSS_X86_OR_X64 means the target is either x86 or x64
ifeq (,$(filter-out i386 x386 x86 x86_64,$(CPU_ARCH)))
DEFINES += -DNSS_X86_OR_X64
CFLAGS += -mpclmul -maes
EXTRA_SRCS += gcm-x86.c aes-x86.c
$(OBJDIR)/gcm-x86.o: CFLAGS += -mpclmul -maes
$(OBJDIR)/aes-x86.o: CFLAGS += -mpclmul -maes
ifneq (,$(USE_64)$(USE_X32))
DEFINES += -DNSS_X64
else

View File

@ -0,0 +1,157 @@
/* 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/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "rijndael.h"
#include "secerr.h"
#include <wmmintrin.h> /* aes-ni */
#define EXPAND_KEY128(k, rcon, res) \
tmp_key = _mm_aeskeygenassist_si128(k, rcon); \
tmp_key = _mm_shuffle_epi32(tmp_key, 0xFF); \
tmp = _mm_xor_si128(k, _mm_slli_si128(k, 4)); \
tmp = _mm_xor_si128(tmp, _mm_slli_si128(tmp, 4)); \
tmp = _mm_xor_si128(tmp, _mm_slli_si128(tmp, 4)); \
res = _mm_xor_si128(tmp, tmp_key)
static void
native_key_expansion128(AESContext *cx, const unsigned char *key)
{
__m128i *keySchedule = cx->keySchedule;
pre_align __m128i tmp_key post_align;
pre_align __m128i tmp post_align;
keySchedule[0] = _mm_loadu_si128((__m128i *)key);
EXPAND_KEY128(keySchedule[0], 0x01, keySchedule[1]);
EXPAND_KEY128(keySchedule[1], 0x02, keySchedule[2]);
EXPAND_KEY128(keySchedule[2], 0x04, keySchedule[3]);
EXPAND_KEY128(keySchedule[3], 0x08, keySchedule[4]);
EXPAND_KEY128(keySchedule[4], 0x10, keySchedule[5]);
EXPAND_KEY128(keySchedule[5], 0x20, keySchedule[6]);
EXPAND_KEY128(keySchedule[6], 0x40, keySchedule[7]);
EXPAND_KEY128(keySchedule[7], 0x80, keySchedule[8]);
EXPAND_KEY128(keySchedule[8], 0x1B, keySchedule[9]);
EXPAND_KEY128(keySchedule[9], 0x36, keySchedule[10]);
}
#define EXPAND_KEY192_PART1(res, k0, kt, rcon) \
tmp2 = _mm_slli_si128(k0, 4); \
tmp1 = _mm_xor_si128(k0, tmp2); \
tmp2 = _mm_slli_si128(tmp2, 4); \
tmp1 = _mm_xor_si128(_mm_xor_si128(tmp1, tmp2), _mm_slli_si128(tmp2, 4)); \
tmp2 = _mm_aeskeygenassist_si128(kt, rcon); \
res = _mm_xor_si128(tmp1, _mm_shuffle_epi32(tmp2, 0x55))
#define EXPAND_KEY192_PART2(res, k1, k2) \
tmp2 = _mm_xor_si128(k1, _mm_slli_si128(k1, 4)); \
res = _mm_xor_si128(tmp2, _mm_shuffle_epi32(k2, 0xFF))
#define EXPAND_KEY192(k0, res1, res2, res3, carry, rcon1, rcon2) \
EXPAND_KEY192_PART1(tmp3, k0, res1, rcon1); \
EXPAND_KEY192_PART2(carry, res1, tmp3); \
res1 = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(res1), \
_mm_castsi128_pd(tmp3), 0)); \
res2 = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(tmp3), \
_mm_castsi128_pd(carry), 1)); \
EXPAND_KEY192_PART1(res3, tmp3, carry, rcon2)
static void
native_key_expansion192(AESContext *cx, const unsigned char *key)
{
__m128i *keySchedule = cx->keySchedule;
pre_align __m128i tmp1 post_align;
pre_align __m128i tmp2 post_align;
pre_align __m128i tmp3 post_align;
pre_align __m128i carry post_align;
keySchedule[0] = _mm_loadu_si128((__m128i *)key);
keySchedule[1] = _mm_loadu_si128((__m128i *)(key + 16));
EXPAND_KEY192(keySchedule[0], keySchedule[1], keySchedule[2],
keySchedule[3], carry, 0x1, 0x2);
EXPAND_KEY192_PART2(keySchedule[4], carry, keySchedule[3]);
EXPAND_KEY192(keySchedule[3], keySchedule[4], keySchedule[5],
keySchedule[6], carry, 0x4, 0x8);
EXPAND_KEY192_PART2(keySchedule[7], carry, keySchedule[6]);
EXPAND_KEY192(keySchedule[6], keySchedule[7], keySchedule[8],
keySchedule[9], carry, 0x10, 0x20);
EXPAND_KEY192_PART2(keySchedule[10], carry, keySchedule[9]);
EXPAND_KEY192(keySchedule[9], keySchedule[10], keySchedule[11],
keySchedule[12], carry, 0x40, 0x80);
}
#define EXPAND_KEY256_PART(res, rconx, k1x, k2x, X) \
tmp_key = _mm_shuffle_epi32(_mm_aeskeygenassist_si128(k2x, rconx), X); \
tmp2 = _mm_slli_si128(k1x, 4); \
tmp1 = _mm_xor_si128(k1x, tmp2); \
tmp2 = _mm_slli_si128(tmp2, 4); \
tmp1 = _mm_xor_si128(_mm_xor_si128(tmp1, tmp2), _mm_slli_si128(tmp2, 4)); \
res = _mm_xor_si128(tmp1, tmp_key);
#define EXPAND_KEY256(res1, res2, k1, k2, rcon) \
EXPAND_KEY256_PART(res1, rcon, k1, k2, 0xFF); \
EXPAND_KEY256_PART(res2, 0x00, k2, res1, 0xAA)
static void
native_key_expansion256(AESContext *cx, const unsigned char *key)
{
__m128i *keySchedule = cx->keySchedule;
pre_align __m128i tmp_key post_align;
pre_align __m128i tmp1 post_align;
pre_align __m128i tmp2 post_align;
keySchedule[0] = _mm_loadu_si128((__m128i *)key);
keySchedule[1] = _mm_loadu_si128((__m128i *)(key + 16));
EXPAND_KEY256(keySchedule[2], keySchedule[3], keySchedule[0],
keySchedule[1], 0x01);
EXPAND_KEY256(keySchedule[4], keySchedule[5], keySchedule[2],
keySchedule[3], 0x02);
EXPAND_KEY256(keySchedule[6], keySchedule[7], keySchedule[4],
keySchedule[5], 0x04);
EXPAND_KEY256(keySchedule[8], keySchedule[9], keySchedule[6],
keySchedule[7], 0x08);
EXPAND_KEY256(keySchedule[10], keySchedule[11], keySchedule[8],
keySchedule[9], 0x10);
EXPAND_KEY256(keySchedule[12], keySchedule[13], keySchedule[10],
keySchedule[11], 0x20);
EXPAND_KEY256_PART(keySchedule[14], 0x40, keySchedule[12],
keySchedule[13], 0xFF);
}
/*
* AES key expansion using aes-ni instructions.
*/
void
rijndael_native_key_expansion(AESContext *cx, const unsigned char *key,
unsigned int Nk)
{
switch (Nk) {
case 4:
native_key_expansion128(cx, key);
return;
case 6:
native_key_expansion192(cx, key);
return;
case 8:
native_key_expansion256(cx, key);
return;
default:
/* This shouldn't happen (checked by the caller). */
return;
}
}
void
rijndael_native_encryptBlock(AESContext *cx,
unsigned char *output,
const unsigned char *input)
{
int i;
pre_align __m128i m post_align = _mm_loadu_si128((__m128i *)input);
m = _mm_xor_si128(m, cx->keySchedule[0]);
for (i = 1; i < cx->Nr; ++i) {
m = _mm_aesenc_si128(m, cx->keySchedule[i]);
}
m = _mm_aesenclast_si128(m, cx->keySchedule[cx->Nr]);
_mm_storeu_si128((__m128i *)output, m);
}

View File

@ -22,6 +22,37 @@
'-mssse3'
]
},
{
'target_name': 'gcm-aes-x86_c_lib',
'type': 'static_library',
'sources': [
'gcm-x86.c', 'aes-x86.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
],
# Enable isa option for pclmul and aes-ni; supported since gcc 4.4.
# This is only supported by x84/x64. It's not needed for Windows,
# unless clang-cl is used.
'cflags_mozilla': [
'-mpclmul', '-maes'
],
'conditions': [
[ 'OS=="linux" or OS=="android" or OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd"', {
'cflags': [
'-mpclmul', '-maes'
],
}],
# macOS build doesn't use cflags.
[ 'OS=="mac"', {
'xcode_settings': {
'OTHER_CFLAGS': [
'-mpclmul', '-maes'
],
},
}]
]
},
{
'target_name': 'freebl',
'type': 'static_library',
@ -45,6 +76,11 @@
'<(DEPTH)/exports.gyp:nss_exports',
],
'conditions': [
[ 'target_arch=="ia32" or target_arch=="x64"', {
'dependencies': [
'gcm-aes-x86_c_lib'
],
}],
[ 'OS=="linux"', {
'defines!': [
'FREEBL_NO_DEPEND',
@ -76,6 +112,11 @@
'<(DEPTH)/exports.gyp:nss_exports',
],
'conditions': [
[ 'target_arch=="ia32" or target_arch=="x64"', {
'dependencies': [
'gcm-aes-x86_c_lib'
]
}],
[ 'OS!="linux" and OS!="android"', {
'conditions': [
[ 'moz_fold_libs==0', {
@ -154,27 +195,11 @@
'MP_API_COMPATIBLE'
],
'conditions': [
[ 'target_arch=="ia32" or target_arch=="x64"', {
'cflags_mozilla': [
'-mpclmul',
'-maes',
],
'conditions': [
[ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd"', {
'cflags': [
'-mpclmul',
'-maes',
],
}],
],
}],
[ 'OS=="mac"', {
'xcode_settings': {
# I'm not sure since when this is supported.
# But I hope that doesn't matter. We also assume this is x86/x64.
'OTHER_CFLAGS': [
'-mpclmul',
'-maes',
'-std=gnu99',
],
},
@ -268,14 +293,6 @@
'MP_USE_UINT_DIGIT',
],
}],
[ 'target_arch=="ia32" or target_arch=="x64"', {
'cflags': [
# enable isa option for pclmul am aes-ni; supported since gcc 4.4
# This is only support by x84/x64. It's not needed for Windows.
'-mpclmul',
'-maes',
],
}],
[ 'target_arch=="arm"', {
'defines': [
'MP_ASSEMBLY_MULTIPLY',

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