mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Merge inbound to central, a=merge
MozReview-Commit-ID: IUFdbLdYFhX
This commit is contained in:
commit
d8985b6e57
@ -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.
|
||||
|
@ -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.
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
62
dom/base/test/iframe_webSocket_sandbox.html
Normal file
62
dom/base/test/iframe_webSocket_sandbox.html
Normal 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>
|
@ -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]
|
||||
|
@ -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");
|
||||
|
34
dom/base/test/test_webSocket_sandbox.html
Normal file
34
dom/base/test/test_webSocket_sandbox.html
Normal 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>
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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']
|
||||
|
13
dom/events/test/pointerevents/pointerlock/mochitest.ini
Normal file
13
dom/events/test/pointerevents/pointerlock/mochitest.ini
Normal 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
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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, ...}",
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
37
dom/security/test/general/browser_test_data_download.js
Normal file
37
dom/security/test/general/browser_test_data_download.js
Normal 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);
|
||||
}
|
14
dom/security/test/general/file_data_download.html
Normal file
14
dom/security/test/general/file_data_download.html
Normal 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>
|
@ -1,4 +1,4 @@
|
||||
Mozilla Public License Version 2.0
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
|
@ -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))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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() ||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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.");
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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 :
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
170
js/src/jsgc.cpp
170
js/src/jsgc.cpp
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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*)
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
12
layout/style/crashtests/1404324-1.html
Normal file
12
layout/style/crashtests/1404324-1.html
Normal 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>
|
10
layout/style/crashtests/1404324-2.html
Normal file
10
layout/style/crashtests/1404324-2.html
Normal 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>
|
14
layout/style/crashtests/1404324-3.html
Normal file
14
layout/style/crashtests/1404324-3.html
Normal 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>
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -263,6 +263,7 @@ NSS_Init
|
||||
NSS_Initialize
|
||||
NSS_InitWithMerge
|
||||
NSS_IsInitialized
|
||||
NSS_OptionGet
|
||||
NSS_OptionSet
|
||||
NSS_NoDB_Init
|
||||
NSS_SecureMemcmp
|
||||
|
@ -1 +1 @@
|
||||
NSS_3_33_RTM
|
||||
6fb9c5396d52
|
||||
|
@ -1 +1 @@
|
||||
NSS_3_32_BRANCH
|
||||
NSS_3_33_BRANCH
|
||||
|
@ -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}"
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
],
|
||||
|
@ -10,3 +10,4 @@
|
||||
*/
|
||||
|
||||
#error "Do not include this header 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;
|
||||
|
@ -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 \
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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',
|
||||
|
91
security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
Normal file
91
security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
Normal 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
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
157
security/nss/lib/freebl/aes-x86.c
Normal file
157
security/nss/lib/freebl/aes-x86.c
Normal 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);
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user