mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
merge mozilla-inbound to mozilla-central. r=merge a=merge
MozReview-Commit-ID: BDyuSdNALvH
This commit is contained in:
commit
a0bd7b9c0d
@ -136,8 +136,8 @@ nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGlobal)
|
||||
:
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
mProfilerRAII("nsJSUtils::ExecutionContext", /* PROFILER_LABEL */
|
||||
js::ProfileEntry::Category::JS, __LINE__),
|
||||
mProfilerRAII("nsJSUtils::ExecutionContext", /* dynamicStr */ nullptr,
|
||||
__LINE__, js::ProfileEntry::Category::JS),
|
||||
#endif
|
||||
mCx(aCx)
|
||||
, mCompartment(aCx, aGlobal)
|
||||
|
@ -1,83 +0,0 @@
|
||||
// Temporary implementation of add_task for mochitest-plain until bug 1078657 is
|
||||
// implemented.
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
(function(scope) {
|
||||
var pendingTasks = [];
|
||||
var pendingPromise = null;
|
||||
|
||||
// Strict spawn function that takes a known generatorFunc and assumes that
|
||||
// every yielded value will be a Promise. If nesting is desired, then yield*
|
||||
// should be used!
|
||||
function spawn(generatorFunc) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var iterator = generatorFunc();
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, 'Problem invoking generator func: ' + ex + ': ' + ex.stack);
|
||||
return;
|
||||
}
|
||||
var stepResolved = function(result) {
|
||||
try {
|
||||
var iterStep = iterator.next(result);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, 'Problem invoking iterator step: ' + ex + ': ' + ex.stack);
|
||||
return;
|
||||
}
|
||||
if (iterStep.done) {
|
||||
resolve(iterStep.value);
|
||||
return;
|
||||
}
|
||||
if (!iterStep.value || !iterStep.value.then) {
|
||||
ok(false, 'Iterator step returned non-Promise: ' + iterStep.value);
|
||||
}
|
||||
iterStep.value.then(stepResolved, generalErrback);
|
||||
};
|
||||
stepResolved();
|
||||
});
|
||||
}
|
||||
|
||||
function maybeSpawn(promiseOrGenerator) {
|
||||
if (promiseOrGenerator.then) {
|
||||
return promiseOrGenerator;
|
||||
}
|
||||
return spawn(promiseOrGenerator);
|
||||
}
|
||||
|
||||
scope.add_task = function(thing) {
|
||||
pendingTasks.push(thing);
|
||||
};
|
||||
|
||||
function generalErrback(ex) {
|
||||
ok(false,
|
||||
'A rejection happened: ' +
|
||||
(ex ? (ex + ': ' + ex.stack) : ''));
|
||||
}
|
||||
|
||||
function runNextTask() {
|
||||
if (pendingTasks.length) {
|
||||
pendingPromise = maybeSpawn(pendingTasks.shift());
|
||||
pendingPromise.then(runNextTask, generalErrback);
|
||||
} else {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger runNextTask after we think all JS files have been loaded.
|
||||
// The primary goal is that we can call SimpleTest.finish() after all test
|
||||
// code has been loaded and run. We gate this based on the document's
|
||||
// readyState.
|
||||
var running = false;
|
||||
function maybeStartRunning() {
|
||||
if (!running && document.readyState === 'complete') {
|
||||
running = true;
|
||||
document.removeEventListener('readystateChange', maybeStartRunning);
|
||||
// Defer to a subsequent turn of the event loop to let micro-tasks and any
|
||||
// other clever setTimeout(0) instances run first.
|
||||
window.setTimeout(runNextTask, 0);
|
||||
}
|
||||
}
|
||||
document.addEventListener('readystatechange', maybeStartRunning);
|
||||
maybeStartRunning();
|
||||
})(this);
|
@ -2,11 +2,9 @@
|
||||
support-files =
|
||||
tcpsocket_test.jsm
|
||||
test_tcpsocket_client_and_server_basics.js
|
||||
add_task.js
|
||||
file_udpsocket_iframe.html
|
||||
|
||||
[test_tcpsocket_jsm.html]
|
||||
[test_tcpsocket_client_and_server_basics.html]
|
||||
[test_tcpsocket_enabled_with_perm.html]
|
||||
[test_tcpsocket_legacy.html]
|
||||
[test_udpsocket.html]
|
||||
|
@ -1,11 +1,9 @@
|
||||
[DEFAULT]
|
||||
support-files =
|
||||
add_task.js
|
||||
worker_network_basics.js
|
||||
|
||||
[test_network_basics.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_network_basics_worker.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_tcpsocket_default_permissions.html]
|
||||
[test_tcpsocket_enabled_no_perm.html]
|
||||
[test_tcpsocket_not_exposed_to_content.html]
|
||||
|
@ -1,5 +1,5 @@
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
'createSocket', 'createServer', 'enablePrefsAndPermissions',
|
||||
'createSocket', 'createServer',
|
||||
'socketCompartmentInstanceOfArrayBuffer'];
|
||||
|
||||
this.createSocket = function(host, port, options) {
|
||||
@ -10,10 +10,6 @@ this.createServer = function(port, options, backlog) {
|
||||
return new TCPServerSocket(port, options, backlog);
|
||||
}
|
||||
|
||||
this.enablePrefsAndPermissions = function() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See test_tcpsocket_client_and_server_basics.html's version for rationale.
|
||||
this.socketCompartmentInstanceOfArrayBuffer = function(obj) {
|
||||
return obj instanceof ArrayBuffer;
|
||||
|
@ -11,8 +11,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1084245
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1084245</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="add_task.js"></script>
|
||||
<script type="application/javascript">
|
||||
function createServer(port, options, backlog) {
|
||||
return new TCPServerSocket(port, options, backlog);
|
||||
@ -22,10 +22,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1084245
|
||||
return new TCPSocket(host, port, options);
|
||||
}
|
||||
|
||||
function enablePrefsAndPermissions() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// In the JSM case, ArrayBuffers will be created in the compartment of the
|
||||
// JSM with different globals than the
|
||||
// test_tcpsocket_client_and_server_basics.js test logic sees, so we (and
|
||||
|
@ -1,5 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
// Bug 788960 and later bug 1329245 have taught us that attempting to connect to
|
||||
// a port that is not listening or is no longer listening fails to consistently
|
||||
// result in the error (or any) event we expect on Darwin/OSX/"OS X".
|
||||
const isOSX = (Services.appinfo.OS === "Darwin");
|
||||
const testConnectingToNonListeningPort = !isOSX;
|
||||
|
||||
const SERVER_BACKLOG = -1;
|
||||
|
||||
const SOCKET_EVENTS = ['open', 'data', 'drain', 'error', 'close'];
|
||||
@ -411,13 +418,16 @@ function* test_basics() {
|
||||
// we tell it to.
|
||||
listeningServer.close();
|
||||
|
||||
// - try and connect, get an error
|
||||
clientSocket = createSocket('127.0.0.1', serverPort,
|
||||
{ binaryType: 'arraybuffer' });
|
||||
clientQueue = listenForEventsOnSocket(clientSocket, 'client');
|
||||
is((yield clientQueue.waitForEvent()).type, 'error', 'fail to connect');
|
||||
is(clientSocket.readyState, 'closed',
|
||||
'client readyState should be closed after the failure to connect');
|
||||
// (We don't run this check on OS X where it's flakey; see definition up top.)
|
||||
if (testConnectingToNonListeningPort) {
|
||||
// - try and connect, get an error
|
||||
clientSocket = createSocket('127.0.0.1', serverPort,
|
||||
{ binaryType: 'arraybuffer' });
|
||||
clientQueue = listenForEventsOnSocket(clientSocket, 'client');
|
||||
is((yield clientQueue.waitForEvent()).type, 'error', 'fail to connect');
|
||||
is(clientSocket.readyState, 'closed',
|
||||
'client readyState should be closed after the failure to connect');
|
||||
}
|
||||
}
|
||||
|
||||
add_task(test_basics);
|
||||
|
@ -1,38 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test to ensure TCPSocket permission is disabled by default</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test to ensure TCPSocket permission is disabled by default **/
|
||||
|
||||
var caught = false;
|
||||
try {
|
||||
new TCPSocket("localhost", 80, {})
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
}
|
||||
|
||||
ok(caught, "TCPSocket should not exist by default");
|
||||
|
||||
var caught = false;
|
||||
try {
|
||||
navigator.mozTCPSocket.open("localhost", 80, {})
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
}
|
||||
|
||||
ok(caught, "navigator.mozTCPSocket.open should not exist by default");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,30 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test to ensure TCPSocket permission enabled and no tcp-socket perm does not allow open</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test to ensure TCPSocket preference being turned on does not enable
|
||||
navigator.mozTCPSocket.
|
||||
**/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [['dom.mozTCPSocket.enabled', true]]}, runTest);
|
||||
function runTest() {
|
||||
is('TCPSocket' in this, false, "TCPSocket should not be accessible if dom.mozTCPSocket.enabled is true");
|
||||
is('TCPServerSocket' in this, false, "TCPServerSocket should not be accessible if dom.mozTCPSocket.enabled is true");
|
||||
is('mozTCPSocket' in navigator, false, "mozTCPSocket should not be accessible if dom.mozTCPSocket.enabled is true");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -1,35 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test to ensure TCPSocket permission enabled and open works with tcp-socket perm</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test to ensure TCPSocket permission being turned on enables
|
||||
navigator.mozTCPSocket, and mozTCPSocket.open works when
|
||||
the tcp-socket permission has been granted.
|
||||
**/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [['dom.mozTCPSocket.enabled', true]]}, runTest);
|
||||
|
||||
function runTest() {
|
||||
ok('TCPSocket' in this, "TCPSocket should be accessible if dom.mozTCPSocket.enabled is true");
|
||||
|
||||
ok(new TCPSocket('localhost', 80), "TCPSocket constructor should work for content that has the tcp-socket permission");
|
||||
ok(navigator.mozTCPSocket.open('localhost', 80), "navigator.mozTCPSocket.open should work for content that has the tcp-socket permission");
|
||||
// This just helps the test harness clean up quickly
|
||||
SpecialPowers.forceCC();
|
||||
SpecialPowers.forceGC();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -6,11 +6,11 @@
|
||||
<meta charset="utf-8">
|
||||
<title>Test for 1207090</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
Components.utils.import("chrome://mochitests/content/chrome/dom/network/tests/tcpsocket_test.jsm");
|
||||
</script>
|
||||
<script type="application/javascript" src="add_task.js"></script>
|
||||
<script type="application/javascript" src="test_tcpsocket_client_and_server_basics.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -19,9 +19,6 @@ Test of legacy navigator interface for opening TCPSocket/TCPServerSocket.
|
||||
</pre>
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [ ['dom.mozTCPSocket.enabled', true] ] },
|
||||
runTest);
|
||||
|
||||
function runTest() {
|
||||
// See bug 903830; in e10s mode we never get to find out the localPort if we
|
||||
@ -54,6 +51,7 @@ Test of legacy navigator interface for opening TCPSocket/TCPServerSocket.
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
runTest(); // we used to invoke this as part of a moot pref-setting callback
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
25
dom/network/tests/test_tcpsocket_not_exposed_to_content.html
Normal file
25
dom/network/tests/test_tcpsocket_not_exposed_to_content.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test to ensure TCPSocket permission enabled and no tcp-socket perm does not allow open</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
/**
|
||||
* TCPSocket and its legacy mozTCPSocket variant should never be exposed to
|
||||
* content.
|
||||
*/
|
||||
|
||||
is('TCPSocket' in this, false, "TCPSocket should not be accessible to content");
|
||||
is('TCPServerSocket' in this, false, "TCPServerSocket should not be accessible to content");
|
||||
is('mozTCPSocket' in navigator, false, "mozTCPSocket should not be accessible to content");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -29,35 +29,26 @@ namespace js {
|
||||
//
|
||||
class ProfileEntry
|
||||
{
|
||||
// All fields are marked volatile to prevent the compiler from re-ordering
|
||||
// instructions. Namely this sequence:
|
||||
//
|
||||
// entry[size] = ...;
|
||||
// size++;
|
||||
//
|
||||
// If the size modification were somehow reordered before the stores, then
|
||||
// if a sample were taken it would be examining bogus information.
|
||||
//
|
||||
// A ProfileEntry represents both a C++ profile entry and a JS one.
|
||||
// A ProfileEntry represents either a C++ profile entry or a JS one.
|
||||
|
||||
// Descriptive label for this entry. Must be a static string! Can be an
|
||||
// empty string, but not a null pointer.
|
||||
const char * volatile label_;
|
||||
const char* label_;
|
||||
|
||||
// An additional descriptive string of this entry which is combined with
|
||||
// |label_| in profiler output. Need not be (and usually isn't) static. Can
|
||||
// be null.
|
||||
const char * volatile dynamicString_;
|
||||
const char* dynamicString_;
|
||||
|
||||
// Stack pointer for non-JS entries, the script pointer otherwise.
|
||||
void * volatile spOrScript;
|
||||
void* spOrScript;
|
||||
|
||||
// Line number for non-JS entries, the bytecode offset otherwise.
|
||||
int32_t volatile lineOrPcOffset;
|
||||
int32_t lineOrPcOffset;
|
||||
|
||||
// Bits 0..1 hold the Kind. Bits 2..3 are unused. Bits 4..12 hold the
|
||||
// Category.
|
||||
uint32_t volatile kindAndCategory_;
|
||||
uint32_t kindAndCategory_;
|
||||
|
||||
static int32_t pcToOffset(JSScript* aScript, jsbytecode* aPc);
|
||||
|
||||
@ -103,30 +94,25 @@ class ProfileEntry
|
||||
static_assert((uint32_t(Category::FIRST) & uint32_t(Kind::KIND_MASK)) == 0,
|
||||
"Category overlaps with Kind");
|
||||
|
||||
// All of these methods are marked with the 'volatile' keyword because the
|
||||
// Gecko Profiler's representation of the stack is stored such that all
|
||||
// ProfileEntry instances are volatile. These methods would not be
|
||||
// available unless they were marked as volatile as well.
|
||||
|
||||
bool isCpp() const volatile
|
||||
bool isCpp() const
|
||||
{
|
||||
Kind k = kind();
|
||||
return k == Kind::CPP_NORMAL || k == Kind::CPP_MARKER_FOR_JS;
|
||||
}
|
||||
|
||||
bool isJs() const volatile
|
||||
bool isJs() const
|
||||
{
|
||||
Kind k = kind();
|
||||
return k == Kind::JS_NORMAL || k == Kind::JS_OSR;
|
||||
}
|
||||
|
||||
void setLabel(const char* aLabel) volatile { label_ = aLabel; }
|
||||
const char* label() const volatile { return label_; }
|
||||
void setLabel(const char* aLabel) { label_ = aLabel; }
|
||||
const char* label() const { return label_; }
|
||||
|
||||
const char* dynamicString() const volatile { return dynamicString_; }
|
||||
const char* dynamicString() const { return dynamicString_; }
|
||||
|
||||
void initCppFrame(const char* aLabel, const char* aDynamicString, void* sp, uint32_t aLine,
|
||||
Kind aKind, Category aCategory) volatile
|
||||
Kind aKind, Category aCategory)
|
||||
{
|
||||
label_ = aLabel;
|
||||
dynamicString_ = aDynamicString;
|
||||
@ -137,7 +123,7 @@ class ProfileEntry
|
||||
}
|
||||
|
||||
void initJsFrame(const char* aLabel, const char* aDynamicString, JSScript* aScript,
|
||||
jsbytecode* aPc) volatile
|
||||
jsbytecode* aPc)
|
||||
{
|
||||
label_ = aLabel;
|
||||
dynamicString_ = aDynamicString;
|
||||
@ -147,41 +133,41 @@ class ProfileEntry
|
||||
MOZ_ASSERT(isJs());
|
||||
}
|
||||
|
||||
void setKind(Kind aKind) volatile {
|
||||
void setKind(Kind aKind) {
|
||||
kindAndCategory_ = uint32_t(aKind) | uint32_t(category());
|
||||
}
|
||||
|
||||
Kind kind() const volatile {
|
||||
Kind kind() const {
|
||||
return Kind(kindAndCategory_ & uint32_t(Kind::KIND_MASK));
|
||||
}
|
||||
|
||||
Category category() const volatile {
|
||||
Category category() const {
|
||||
return Category(kindAndCategory_ & uint32_t(Category::CATEGORY_MASK));
|
||||
}
|
||||
|
||||
void* stackAddress() const volatile {
|
||||
void* stackAddress() const {
|
||||
MOZ_ASSERT(!isJs());
|
||||
return spOrScript;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript*) script() const volatile;
|
||||
JS_PUBLIC_API(JSScript*) script() const;
|
||||
|
||||
uint32_t line() const volatile {
|
||||
uint32_t line() const {
|
||||
MOZ_ASSERT(!isJs());
|
||||
return static_cast<uint32_t>(lineOrPcOffset);
|
||||
}
|
||||
|
||||
// Note that the pointer returned might be invalid.
|
||||
JSScript* rawScript() const volatile {
|
||||
JSScript* rawScript() const {
|
||||
MOZ_ASSERT(isJs());
|
||||
return (JSScript*)spOrScript;
|
||||
}
|
||||
|
||||
// We can't know the layout of JSScript, so look in vm/GeckoProfiler.cpp.
|
||||
JS_FRIEND_API(jsbytecode*) pc() const volatile;
|
||||
void setPC(jsbytecode* pc) volatile;
|
||||
JS_FRIEND_API(jsbytecode*) pc() const;
|
||||
void setPC(jsbytecode* pc);
|
||||
|
||||
void trace(JSTracer* trc) volatile;
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
// The offset of a pc into a script's code can actually be 0, so to
|
||||
// signify a nullptr pc, use a -1 index. This is checked against in
|
||||
@ -200,9 +186,24 @@ RegisterContextProfilingEventMarker(JSContext* cx, void (*fn)(const char*));
|
||||
|
||||
} // namespace js
|
||||
|
||||
// The PseudoStack members are accessed in parallel by multiple threads: the
|
||||
// profiler's sampler thread reads these members while other threads modify
|
||||
// them.
|
||||
// Each thread has its own PseudoStack. That thread modifies the PseudoStack,
|
||||
// pushing and popping elements as necessary.
|
||||
//
|
||||
// The PseudoStack is also read periodically by the profiler's sampler thread.
|
||||
// This happens only when the thread that owns the PseudoStack is suspended. So
|
||||
// there are no genuine parallel accesses.
|
||||
//
|
||||
// However, it is possible for pushing/popping to be interrupted by a periodic
|
||||
// sample. Because of this, we need pushing/popping to be effectively atomic.
|
||||
//
|
||||
// - When pushing a new entry, we increment the stack pointer -- making the new
|
||||
// entry visible to the sampler thread -- only after the new entry has been
|
||||
// fully written. The stack pointer is Atomic<> (with SequentiallyConsistent
|
||||
// semantics) to ensure the incrementing is not reordered before the writes.
|
||||
//
|
||||
// - When popping an old entry, the only operation is the decrementing of the
|
||||
// stack pointer, which is obviously atomic.
|
||||
//
|
||||
class PseudoStack
|
||||
{
|
||||
public:
|
||||
@ -255,13 +256,13 @@ class PseudoStack
|
||||
static const uint32_t MaxEntries = 1024;
|
||||
|
||||
// The stack entries.
|
||||
js::ProfileEntry volatile entries[MaxEntries];
|
||||
js::ProfileEntry entries[MaxEntries];
|
||||
|
||||
// This may exceed MaxEntries, so instead use the stackSize() method to
|
||||
// determine the number of valid samples in entries. When this is less
|
||||
// than MaxEntries, it refers to the first free entry past the top of the
|
||||
// in-use stack (i.e. entries[stackPointer - 1] is the top stack entry).
|
||||
mozilla::Atomic<uint32_t> stackPointer;
|
||||
mozilla::Atomic<uint32_t, mozilla::SequentiallyConsistent> stackPointer;
|
||||
};
|
||||
|
||||
#endif /* js_ProfilingStack_h */
|
||||
|
65
js/src/jit-test/tests/debug/bug1353356.js
Normal file
65
js/src/jit-test/tests/debug/bug1353356.js
Normal file
@ -0,0 +1,65 @@
|
||||
// |jit-test| allow-oom; --fuzzing-safe
|
||||
|
||||
var lfLogBuffer = `
|
||||
//corefuzz-dcd-endofdata
|
||||
//corefuzz-dcd-endofdata
|
||||
//corefuzz-dcd-endofdata
|
||||
setJitCompilerOption("ion.warmup.trigger", 4);
|
||||
var g = newGlobal();
|
||||
g.debuggeeGlobal = this;
|
||||
g.eval("(" + function () {
|
||||
dbg = new Debugger(debuggeeGlobal);
|
||||
dbg.onExceptionUnwind = function (frame, exc) {
|
||||
var s = '!';
|
||||
for (var f = frame; f; f = f.older)
|
||||
debuggeeGlobal.log += s;
|
||||
};
|
||||
} + ")();");
|
||||
j('Number.prototype.toSource.call([])');
|
||||
//corefuzz-dcd-endofdata
|
||||
//corefuzz-dcd-endofdata
|
||||
//corefuzz-dcd-endofdata
|
||||
//corefuzz-dcd-selectmode 4
|
||||
//corefuzz-dcd-endofdata
|
||||
}
|
||||
//corefuzz-dcd-endofdata
|
||||
//corefuzz-dcd-selectmode 5
|
||||
//corefuzz-dcd-endofdata
|
||||
oomTest(() => i({
|
||||
new : (true ),
|
||||
thisprops: true
|
||||
}));
|
||||
`;
|
||||
lfLogBuffer = lfLogBuffer.split('\n');
|
||||
var lfRunTypeId = -1;
|
||||
var lfCodeBuffer = "";
|
||||
while (true) {
|
||||
var line = lfLogBuffer.shift();
|
||||
if (line == null) {
|
||||
break;
|
||||
} else if (line == "//corefuzz-dcd-endofdata") {
|
||||
loadFile(lfCodeBuffer);
|
||||
lfCodeBuffer = "";
|
||||
loadFile(line);
|
||||
} else {
|
||||
lfCodeBuffer += line + "\n";
|
||||
}
|
||||
}
|
||||
if (lfCodeBuffer) loadFile(lfCodeBuffer);
|
||||
function loadFile(lfVarx) {
|
||||
try {
|
||||
if (lfVarx.indexOf("//corefuzz-dcd-selectmode ") === 0) {
|
||||
lfRunTypeId = parseInt(lfVarx.split(" ")[1]) % 6;
|
||||
} else {
|
||||
switch (lfRunTypeId) {
|
||||
case 4:
|
||||
oomTest(function() {
|
||||
let m = parseModule(lfVarx);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
evaluate(lfVarx);
|
||||
}
|
||||
}
|
||||
} catch (lfVare) {}
|
||||
}
|
@ -154,6 +154,10 @@ case $cmd in
|
||||
# remove *.pyc and *.pyo files if any
|
||||
find ${tgtpath} -type f -name "*.pyc" -o -name "*.pyo" |xargs rm -f
|
||||
|
||||
# Remove non-JS Cargo.toml files (for example, the invalid Cargo.toml files
|
||||
# used for some testing).
|
||||
find ${tgtpath} -type f -name Cargo.toml | grep -v js | xargs rm -f
|
||||
|
||||
# copy or create INSTALL
|
||||
if [ -e ${STAGING}/INSTALL ]; then
|
||||
cp ${STAGING}/INSTALL ${tgtpath}
|
||||
|
@ -239,7 +239,7 @@ GeckoProfiler::exit(JSScript* script, JSFunction* maybeFun)
|
||||
uint32_t(pseudoStack_->stackPointer),
|
||||
PseudoStack::MaxEntries);
|
||||
for (int32_t i = sp; i >= 0; i--) {
|
||||
volatile ProfileEntry& entry = pseudoStack_->entries[i];
|
||||
ProfileEntry& entry = pseudoStack_->entries[i];
|
||||
if (entry.isJs())
|
||||
fprintf(stderr, " [%d] JS %s\n", i, entry.dynamicString());
|
||||
else
|
||||
@ -247,7 +247,7 @@ GeckoProfiler::exit(JSScript* script, JSFunction* maybeFun)
|
||||
}
|
||||
}
|
||||
|
||||
volatile ProfileEntry& entry = pseudoStack_->entries[sp];
|
||||
ProfileEntry& entry = pseudoStack_->entries[sp];
|
||||
MOZ_ASSERT(entry.isJs());
|
||||
MOZ_ASSERT(entry.script() == script);
|
||||
MOZ_ASSERT(strcmp((const char*) entry.dynamicString(), dynamicString) == 0);
|
||||
@ -310,7 +310,7 @@ GeckoProfiler::allocProfileString(JSScript* script, JSFunction* maybeFun)
|
||||
}
|
||||
|
||||
void
|
||||
GeckoProfiler::trace(JSTracer* trc) volatile
|
||||
GeckoProfiler::trace(JSTracer* trc)
|
||||
{
|
||||
if (pseudoStack_) {
|
||||
size_t size = pseudoStack_->stackSize();
|
||||
@ -353,7 +353,7 @@ GeckoProfiler::checkStringsMapAfterMovingGC()
|
||||
#endif
|
||||
|
||||
void
|
||||
ProfileEntry::trace(JSTracer* trc) volatile
|
||||
ProfileEntry::trace(JSTracer* trc)
|
||||
{
|
||||
if (isJs()) {
|
||||
JSScript* s = rawScript();
|
||||
@ -440,7 +440,7 @@ GeckoProfilerBaselineOSRMarker::GeckoProfilerBaselineOSRMarker(JSRuntime* rt, bo
|
||||
if (sp == 0)
|
||||
return;
|
||||
|
||||
volatile ProfileEntry& entry = profiler->pseudoStack_->entries[sp - 1];
|
||||
ProfileEntry& entry = profiler->pseudoStack_->entries[sp - 1];
|
||||
MOZ_ASSERT(entry.kind() == ProfileEntry::Kind::JS_NORMAL);
|
||||
entry.setKind(ProfileEntry::Kind::JS_OSR);
|
||||
}
|
||||
@ -455,13 +455,13 @@ GeckoProfilerBaselineOSRMarker::~GeckoProfilerBaselineOSRMarker()
|
||||
if (sp == 0)
|
||||
return;
|
||||
|
||||
volatile ProfileEntry& entry = profiler->stack()[sp - 1];
|
||||
ProfileEntry& entry = profiler->stack()[sp - 1];
|
||||
MOZ_ASSERT(entry.kind() == ProfileEntry::Kind::JS_OSR);
|
||||
entry.setKind(ProfileEntry::Kind::JS_NORMAL);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript*)
|
||||
ProfileEntry::script() const volatile
|
||||
ProfileEntry::script() const
|
||||
{
|
||||
MOZ_ASSERT(isJs());
|
||||
auto script = reinterpret_cast<JSScript*>(spOrScript);
|
||||
@ -484,7 +484,7 @@ ProfileEntry::script() const volatile
|
||||
}
|
||||
|
||||
JS_FRIEND_API(jsbytecode*)
|
||||
ProfileEntry::pc() const volatile
|
||||
ProfileEntry::pc() const
|
||||
{
|
||||
MOZ_ASSERT(isJs());
|
||||
if (lineOrPcOffset == NullPCOffset)
|
||||
@ -500,7 +500,7 @@ ProfileEntry::pcToOffset(JSScript* aScript, jsbytecode* aPc) {
|
||||
}
|
||||
|
||||
void
|
||||
ProfileEntry::setPC(jsbytecode* pc) volatile
|
||||
ProfileEntry::setPC(jsbytecode* pc)
|
||||
{
|
||||
MOZ_ASSERT(isJs());
|
||||
JSScript* script = this->script();
|
||||
|
@ -142,7 +142,7 @@ class GeckoProfiler
|
||||
bool init();
|
||||
|
||||
uint32_t stackPointer() { MOZ_ASSERT(installed()); return pseudoStack_->stackPointer; }
|
||||
volatile ProfileEntry* stack() { return pseudoStack_->entries; }
|
||||
ProfileEntry* stack() { return pseudoStack_->entries; }
|
||||
|
||||
/* management of whether instrumentation is on or off */
|
||||
bool enabled() { MOZ_ASSERT_IF(enabled_, installed()); return enabled_; }
|
||||
@ -189,7 +189,7 @@ class GeckoProfiler
|
||||
return &enabled_;
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc) volatile;
|
||||
void trace(JSTracer* trc);
|
||||
void fixupStringsMapAfterMovingGC();
|
||||
#ifdef JSGC_HASH_TABLE_CHECKS
|
||||
void checkStringsMapAfterMovingGC();
|
||||
|
@ -1539,11 +1539,7 @@ jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator
|
||||
uint8_t* top = iter.fp();
|
||||
RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
|
||||
if (!p) {
|
||||
RematerializedFrameVector empty(cx);
|
||||
if (!rematerializedFrames_->add(p, top, Move(empty))) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
RematerializedFrameVector frames(cx);
|
||||
|
||||
// The unit of rematerialization is an uninlined frame and its inlined
|
||||
// frames. Since inlined frames do not exist outside of snapshots, it
|
||||
@ -1558,9 +1554,11 @@ jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator
|
||||
// be in the activation's compartment.
|
||||
AutoCompartmentUnchecked ac(cx, compartment_);
|
||||
|
||||
if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
|
||||
p->value()))
|
||||
{
|
||||
if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover, frames))
|
||||
return nullptr;
|
||||
|
||||
if (!rematerializedFrames_->add(p, top, Move(frames))) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -48,12 +48,15 @@ var ModuleManager = {
|
||||
|
||||
function startup() {
|
||||
ModuleManager.init();
|
||||
|
||||
// GeckoViewNavigation needs to go first because nsIDOMBrowserWindow must set up
|
||||
// before the first remote browser. Bug 1365364.
|
||||
ModuleManager.add("resource://gre/modules/GeckoViewNavigation.jsm",
|
||||
"GeckoViewNavigation");
|
||||
ModuleManager.add("resource://gre/modules/GeckoViewSettings.jsm",
|
||||
"GeckoViewSettings");
|
||||
ModuleManager.add("resource://gre/modules/GeckoViewContent.jsm",
|
||||
"GeckoViewContent");
|
||||
ModuleManager.add("resource://gre/modules/GeckoViewNavigation.jsm",
|
||||
"GeckoViewNavigation");
|
||||
ModuleManager.add("resource://gre/modules/GeckoViewProgress.jsm",
|
||||
"GeckoViewProgress");
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ var test = [
|
||||
'testsrc.1080p.60fps.mp4',
|
||||
];
|
||||
var viewModeIndex = 0;
|
||||
var viewMode = ['fullscreen', 1, 1.1, 2];
|
||||
// Remove fullscreen mode since it causes intermittent failures on try server. See bug 1192317.
|
||||
var viewMode = [1, 1.1, 2];
|
||||
var testResult = {names: [], values: []};
|
||||
|
||||
function init() {
|
||||
|
@ -586,7 +586,7 @@ MOZ_THREAD_LOCAL(ThreadInfo*) TLSInfo::sThreadInfo;
|
||||
// also have a second TLS pointer directly to the PseudoStack. Here's why.
|
||||
//
|
||||
// - We need to be able to push to and pop from the PseudoStack in
|
||||
// profiler_call_{enter,exit}.
|
||||
// ProfilerStackFrameRAII.
|
||||
//
|
||||
// - Those two functions are hot and must be defined in GeckoProfiler.h so they
|
||||
// can be inlined.
|
||||
@ -595,7 +595,7 @@ MOZ_THREAD_LOCAL(ThreadInfo*) TLSInfo::sThreadInfo;
|
||||
//
|
||||
// This second pointer isn't ideal, but does provide a way to satisfy those
|
||||
// constraints. TLSInfo manages it, except for the uses in
|
||||
// profiler_call_{enter,exit}.
|
||||
// ProfilerStackFrameRAII.
|
||||
MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
|
||||
|
||||
// The name of the main thread.
|
||||
@ -724,8 +724,7 @@ AddDynamicCodeLocationTag(ProfileBuffer* aBuffer, const char* aStr)
|
||||
|
||||
static void
|
||||
AddPseudoEntry(PSLockRef aLock, ProfileBuffer* aBuffer,
|
||||
volatile js::ProfileEntry& entry,
|
||||
NotNull<RacyThreadInfo*> aRacyInfo)
|
||||
js::ProfileEntry& entry, NotNull<RacyThreadInfo*> aRacyInfo)
|
||||
{
|
||||
MOZ_ASSERT(entry.kind() == js::ProfileEntry::Kind::CPP_NORMAL ||
|
||||
entry.kind() == js::ProfileEntry::Kind::JS_NORMAL);
|
||||
@ -827,7 +826,7 @@ MergeStacksIntoProfile(PSLockRef aLock, ProfileBuffer* aBuffer,
|
||||
const TickSample& aSample, NativeStack& aNativeStack)
|
||||
{
|
||||
NotNull<RacyThreadInfo*> racyInfo = aSample.mRacyInfo;
|
||||
volatile js::ProfileEntry* pseudoEntries = racyInfo->entries;
|
||||
js::ProfileEntry* pseudoEntries = racyInfo->entries;
|
||||
uint32_t pseudoCount = racyInfo->stackSize();
|
||||
JSContext* context = aSample.mJSContext;
|
||||
|
||||
@ -902,7 +901,7 @@ MergeStacksIntoProfile(PSLockRef aLock, ProfileBuffer* aBuffer,
|
||||
uint8_t* nativeStackAddr = nullptr;
|
||||
|
||||
if (pseudoIndex != pseudoCount) {
|
||||
volatile js::ProfileEntry& pseudoEntry = pseudoEntries[pseudoIndex];
|
||||
js::ProfileEntry& pseudoEntry = pseudoEntries[pseudoIndex];
|
||||
|
||||
if (pseudoEntry.isCpp()) {
|
||||
lastPseudoCppStackAddr = (uint8_t*) pseudoEntry.stackAddress();
|
||||
@ -952,7 +951,7 @@ MergeStacksIntoProfile(PSLockRef aLock, ProfileBuffer* aBuffer,
|
||||
// Check to see if pseudoStack frame is top-most.
|
||||
if (pseudoStackAddr > jsStackAddr && pseudoStackAddr > nativeStackAddr) {
|
||||
MOZ_ASSERT(pseudoIndex < pseudoCount);
|
||||
volatile js::ProfileEntry& pseudoEntry = pseudoEntries[pseudoIndex];
|
||||
js::ProfileEntry& pseudoEntry = pseudoEntries[pseudoIndex];
|
||||
|
||||
// Pseudo-frames with the CPP_MARKER_FOR_JS kind are just annotations and
|
||||
// should not be recorded in the profile.
|
||||
@ -1100,7 +1099,7 @@ DoNativeBacktrace(PSLockRef aLock, ProfileBuffer* aBuffer,
|
||||
for (uint32_t i = racyInfo->stackSize(); i > 0; --i) {
|
||||
// The pseudostack grows towards higher indices, so we iterate
|
||||
// backwards (from callee to caller).
|
||||
volatile js::ProfileEntry& entry = racyInfo->entries[i - 1];
|
||||
js::ProfileEntry& entry = racyInfo->entries[i - 1];
|
||||
if (!entry.isJs() && strcmp(entry.label(), "EnterJIT") == 0) {
|
||||
// Found JIT entry frame. Unwind up to that point (i.e., force
|
||||
// the stack walk to stop before the block of saved registers;
|
||||
@ -2857,7 +2856,7 @@ profiler_get_backtrace_noalloc(char *output, size_t outputSize)
|
||||
|
||||
bool includeDynamicString = !ActivePS::FeaturePrivacy(lock);
|
||||
|
||||
volatile js::ProfileEntry* pseudoEntries = pseudoStack->entries;
|
||||
js::ProfileEntry* pseudoEntries = pseudoStack->entries;
|
||||
uint32_t pseudoCount = pseudoStack->stackSize();
|
||||
|
||||
for (uint32_t i = 0; i < pseudoCount; i++) {
|
||||
|
@ -98,7 +98,8 @@ using UniqueProfilerBacktrace =
|
||||
// just store the raw pointers to the literal strings. Consequently,
|
||||
// PROFILER_LABEL frames take up considerably less space in the profile buffer
|
||||
// than PROFILER_LABEL_DYNAMIC frames.
|
||||
#define PROFILER_LABEL_DYNAMIC(name_space, info, category, str) do {} while (0)
|
||||
#define PROFILER_LABEL_DYNAMIC(name_space, info, category, dynamicStr) \
|
||||
do {} while (0)
|
||||
|
||||
// Insert a marker in the profile timeline. This is useful to delimit something
|
||||
// important happening such as the first paint. Unlike profiler_label that are
|
||||
@ -128,20 +129,20 @@ using UniqueProfilerBacktrace =
|
||||
#define PROFILER_LABEL(name_space, info, category) \
|
||||
PROFILER_PLATFORM_TRACING(name_space "::" info) \
|
||||
mozilla::ProfilerStackFrameRAII \
|
||||
PROFILER_APPEND_LINE_NUMBER(profiler_raii)(name_space "::" info, category, \
|
||||
__LINE__)
|
||||
PROFILER_APPEND_LINE_NUMBER(profiler_raii)(name_space "::" info, nullptr, \
|
||||
__LINE__, category)
|
||||
|
||||
#define PROFILER_LABEL_FUNC(category) \
|
||||
PROFILER_PLATFORM_TRACING(PROFILER_FUNCTION_NAME) \
|
||||
mozilla::ProfilerStackFrameRAII \
|
||||
PROFILER_APPEND_LINE_NUMBER(profiler_raii)(PROFILER_FUNCTION_NAME, category, \
|
||||
__LINE__)
|
||||
PROFILER_APPEND_LINE_NUMBER(profiler_raii)(PROFILER_FUNCTION_NAME, nullptr, \
|
||||
__LINE__, category)
|
||||
|
||||
#define PROFILER_LABEL_DYNAMIC(name_space, info, category, str) \
|
||||
#define PROFILER_LABEL_DYNAMIC(name_space, info, category, dynamicStr) \
|
||||
PROFILER_PLATFORM_TRACING(name_space "::" info) \
|
||||
mozilla::ProfilerStackFrameDynamicRAII \
|
||||
PROFILER_APPEND_LINE_NUMBER(profiler_raii)(name_space "::" info, category, \
|
||||
__LINE__, str)
|
||||
mozilla::ProfilerStackFrameRAII \
|
||||
PROFILER_APPEND_LINE_NUMBER(profiler_raii)(name_space "::" info, dynamicStr, \
|
||||
__LINE__, category)
|
||||
|
||||
#define PROFILER_MARKER(marker_name) profiler_add_marker(marker_name)
|
||||
#define PROFILER_MARKER_PAYLOAD(marker_name, payload) \
|
||||
@ -405,51 +406,10 @@ PROFILER_FUNC(void* profiler_get_stack_top(), nullptr)
|
||||
class nsISupports;
|
||||
class ProfilerMarkerPayload;
|
||||
|
||||
// This exists purely for profiler_call_{enter,exit}. See the comment on the
|
||||
// This exists purely for ProfilerStackFrameRAII. See the comment on the
|
||||
// definition in platform.cpp for details.
|
||||
extern MOZ_THREAD_LOCAL(PseudoStack*) sPseudoStack;
|
||||
|
||||
// Returns a handle to pass on exit. This can check that we are popping the
|
||||
// correct callstack. Operates the same whether the profiler is active or not.
|
||||
//
|
||||
// A short-lived, non-owning PseudoStack reference is created between each
|
||||
// profiler_call_enter() / profiler_call_exit() call pair. RAII objects (e.g.
|
||||
// ProfilerStackFrameRAII) ensure that these calls are balanced. Furthermore,
|
||||
// the RAII objects exist within the thread itself, which means they are
|
||||
// necessarily bounded by the lifetime of the thread, which ensures that the
|
||||
// references held can't be used after the PseudoStack is destroyed.
|
||||
inline void*
|
||||
profiler_call_enter(const char* aLabel, js::ProfileEntry::Category aCategory,
|
||||
void* aFrameAddress, uint32_t aLine,
|
||||
const char* aDynamicString = nullptr)
|
||||
{
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
PseudoStack* pseudoStack = sPseudoStack.get();
|
||||
if (!pseudoStack) {
|
||||
return pseudoStack;
|
||||
}
|
||||
pseudoStack->pushCppFrame(aLabel, aDynamicString, aFrameAddress, aLine,
|
||||
js::ProfileEntry::Kind::CPP_NORMAL, aCategory);
|
||||
|
||||
// The handle is meant to support future changes but for now it is simply
|
||||
// used to avoid having to call TLSInfo::RacyInfo() in profiler_call_exit().
|
||||
return pseudoStack;
|
||||
}
|
||||
|
||||
inline void
|
||||
profiler_call_exit(void* aHandle)
|
||||
{
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
if (!aHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
PseudoStack* pseudoStack = static_cast<PseudoStack*>(aHandle);
|
||||
pseudoStack->pop();
|
||||
}
|
||||
|
||||
// Adds a marker to the PseudoStack. A no-op if the profiler is inactive or in
|
||||
// privacy mode.
|
||||
void profiler_add_marker(const char* aMarkerName,
|
||||
@ -507,41 +467,41 @@ void profiler_add_marker(const char* aMarkerName,
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// This class creates a non-owning PseudoStack reference. Objects of this class
|
||||
// are stack-allocated, and so exist within a thread, and are thus bounded by
|
||||
// the lifetime of the thread, which ensures that the references held can't be
|
||||
// used after the PseudoStack is destroyed.
|
||||
class MOZ_RAII ProfilerStackFrameRAII {
|
||||
public:
|
||||
// We only copy the strings at save time, so to take multiple parameters we'd
|
||||
// need to copy them then.
|
||||
ProfilerStackFrameRAII(const char* aLabel,
|
||||
js::ProfileEntry::Category aCategory, uint32_t aLine
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
ProfilerStackFrameRAII(const char* aLabel, const char* aDynamicString,
|
||||
uint32_t aLine, js::ProfileEntry::Category aCategory
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
mHandle = profiler_call_enter(aLabel, aCategory, this, aLine);
|
||||
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
mPseudoStack = sPseudoStack.get();
|
||||
if (mPseudoStack) {
|
||||
mPseudoStack->pushCppFrame(aLabel, aDynamicString, this, aLine,
|
||||
js::ProfileEntry::Kind::CPP_NORMAL, aCategory);
|
||||
}
|
||||
}
|
||||
~ProfilerStackFrameRAII() {
|
||||
profiler_call_exit(mHandle);
|
||||
|
||||
~ProfilerStackFrameRAII()
|
||||
{
|
||||
// This function runs both on and off the main thread.
|
||||
|
||||
if (mPseudoStack) {
|
||||
mPseudoStack->pop();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
void* mHandle;
|
||||
};
|
||||
|
||||
class MOZ_RAII ProfilerStackFrameDynamicRAII {
|
||||
public:
|
||||
ProfilerStackFrameDynamicRAII(const char* aLabel,
|
||||
js::ProfileEntry::Category aCategory, uint32_t aLine,
|
||||
const char* aDynamicString)
|
||||
{
|
||||
mHandle = profiler_call_enter(aLabel, aCategory, this, aLine,
|
||||
aDynamicString);
|
||||
}
|
||||
|
||||
~ProfilerStackFrameDynamicRAII() {
|
||||
profiler_call_exit(mHandle);
|
||||
}
|
||||
|
||||
private:
|
||||
void* mHandle;
|
||||
// We save a PseudoStack pointer in the ctor so we don't have to redo the TLS
|
||||
// lookup in the dtor.
|
||||
PseudoStack* mPseudoStack;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -583,15 +583,11 @@ TEST(GeckoProfiler, PseudoStack)
|
||||
}
|
||||
|
||||
#if defined(MOZ_GECKO_PROFILER)
|
||||
ProfilerStackFrameRAII raii1("A", js::ProfileEntry::Category::STORAGE, 888);
|
||||
ProfilerStackFrameDynamicRAII raii2("A", js::ProfileEntry::Category::STORAGE,
|
||||
888, dynamic.get());
|
||||
void* handle = profiler_call_enter("A", js::ProfileEntry::Category::NETWORK,
|
||||
this, 999);
|
||||
ProfilerStackFrameRAII raii1("A", nullptr, 888,
|
||||
js::ProfileEntry::Category::STORAGE);
|
||||
ProfilerStackFrameRAII raii2("A", dynamic.get(), 888,
|
||||
js::ProfileEntry::Category::NETWORK);
|
||||
ASSERT_TRUE(profiler_get_backtrace());
|
||||
profiler_call_exit(handle);
|
||||
|
||||
profiler_call_exit(nullptr); // a no-op
|
||||
#endif
|
||||
|
||||
profiler_stop();
|
||||
|
@ -405,7 +405,7 @@ GetPathAfterComponent(const char* filename, const char (&component)[LEN]) {
|
||||
} // namespace
|
||||
|
||||
const char*
|
||||
ThreadStackHelper::AppendJSEntry(const volatile js::ProfileEntry* aEntry,
|
||||
ThreadStackHelper::AppendJSEntry(const js::ProfileEntry* aEntry,
|
||||
intptr_t& aAvailableBufferSize,
|
||||
const char* aPrevLabel)
|
||||
{
|
||||
@ -492,8 +492,8 @@ ThreadStackHelper::FillStackBuffer()
|
||||
intptr_t availableBufferSize = intptr_t(reservedBufferSize);
|
||||
|
||||
// Go from front to back
|
||||
const volatile js::ProfileEntry* entry = mPseudoStack->entries;
|
||||
const volatile js::ProfileEntry* end = entry + mPseudoStack->stackSize();
|
||||
const js::ProfileEntry* entry = mPseudoStack->entries;
|
||||
const js::ProfileEntry* end = entry + mPseudoStack->stackSize();
|
||||
// Deduplicate identical, consecutive frames
|
||||
const char* prevLabel = nullptr;
|
||||
for (; reservedSize-- && entry != end; entry++) {
|
||||
|
@ -77,7 +77,7 @@ private:
|
||||
bool PrepareStackBuffer(Stack& aStack);
|
||||
void FillStackBuffer();
|
||||
#ifdef MOZ_THREADSTACKHELPER_PSEUDO
|
||||
const char* AppendJSEntry(const volatile js::ProfileEntry* aEntry,
|
||||
const char* AppendJSEntry(const js::ProfileEntry* aEntry,
|
||||
intptr_t& aAvailableBufferSize,
|
||||
const char* aPrevLabel);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user