merge mozilla-inbound to mozilla-central. r=merge a=merge

MozReview-Commit-ID: BDyuSdNALvH
This commit is contained in:
Sebastian Hengst 2017-06-06 11:20:56 +02:00
commit a0bd7b9c0d
26 changed files with 239 additions and 377 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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]

View File

@ -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]

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View 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>

View File

@ -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 */

View 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) {}
}

View File

@ -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}

View File

@ -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();

View File

@ -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();

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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() {

View File

@ -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++) {

View File

@ -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

View File

@ -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();

View File

@ -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++) {

View File

@ -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