This commit is contained in:
Ryan VanderMeulen 2014-08-14 22:15:29 -04:00
Родитель c5e044660b 0771b71c21
Коммит e8c3b4d1bb
50 изменённых файлов: 1003 добавлений и 240 удалений

Просмотреть файл

@ -1289,7 +1289,7 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
} else if (role.EqualsLiteral("xul:progressmeter")) {
accessible = new XULProgressMeterAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xulstatusbar")) {
} else if (role.EqualsLiteral("xul:statusbar")) {
accessible = new XULStatusBarAccessible(aContent, aDoc);
} else if (role.EqualsLiteral("xul:scale")) {

Просмотреть файл

@ -22,6 +22,7 @@
"statusbarpanel shouldn't be accessible.");
testRole("statusbarpanel-iconic", ROLE_PUSHBUTTON);
testRole("statusbarpanel-iconic-text", ROLE_PUSHBUTTON);
testRole("statusbar", ROLE_STATUSBAR);
SimpleTest.finish();
}
@ -49,6 +50,7 @@
<statusbarpanel id="statusbarpanel"></statusbarpanel>
<statusbarpanel id="statusbarpanel-iconic" class="statusbarpanel-iconic"></statusbarpanel>
<statusbarpanel id="statusbarpanel-iconic-text" class="statusbarpanel-iconic-text"></statusbarpanel>
<statusbar id="statusbar"></statusbar>
</hbox>
</window>

Просмотреть файл

@ -217,7 +217,6 @@ class Automation(object):
universal_newlines=False,
startupinfo=None,
creationflags=0):
args = automationutils.wrapCommand(args)
_log.info("INFO | automation.py | Launching: %s", subprocess.list2cmdline(args))
subprocess.Popen.__init__(self, args, bufsize, executable,
stdin, stdout, stderr,

Просмотреть файл

@ -26,7 +26,6 @@ __all__ = [
"getDebuggerInfo",
"DEBUGGER_INFO",
"replaceBackSlashes",
"wrapCommand",
'KeyValueParseError',
'parseKeyValue',
'systemMemory',
@ -402,19 +401,6 @@ def processLeakLog(leakLogFile, leakThreshold = 0):
def replaceBackSlashes(input):
return input.replace('\\', '/')
def wrapCommand(cmd):
"""
If running on OS X 10.5 or older, wrap |cmd| so that it will
be executed as an i386 binary, in case it's a 32-bit/64-bit universal
binary.
"""
if platform.system() == "Darwin" and \
hasattr(platform, 'mac_ver') and \
platform.mac_ver()[0][:4] < '10.6':
return ["arch", "-arch", "i386"] + cmd
# otherwise just execute the command normally
return cmd
class KeyValueParseError(Exception):
"""error when parsing strings of serialized key-values"""
def __init__(self, msg, errors=()):

Просмотреть файл

@ -540,8 +540,8 @@ double
AudioContext::CurrentTime() const
{
MediaStream* stream = Destination()->Stream();
return stream->StreamTimeToSeconds(stream->GetCurrentTime()) +
ExtraCurrentTime();
return StreamTimeToDOMTime(stream->
StreamTimeToSeconds(stream->GetCurrentTime()));
}
void

Просмотреть файл

@ -233,6 +233,11 @@ public:
return aTime - ExtraCurrentTime();
}
double StreamTimeToDOMTime(double aTime) const
{
return aTime + ExtraCurrentTime();
}
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)

Просмотреть файл

@ -358,7 +358,6 @@ private:
// Add the delay caused by the main thread
playbackTick += mSharedBuffers->DelaySoFar();
// Compute the playback time in the coordinate system of the destination
// FIXME: bug 970773
double playbackTime =
mSource->DestinationTimeFromTicks(mDestination, playbackTick);
@ -383,22 +382,13 @@ private:
NS_IMETHODIMP Run()
{
// If it's not safe to run scripts right now, schedule this to run later
if (!nsContentUtils::IsSafeToRunScript()) {
nsContentUtils::AddScriptRunner(this);
nsRefPtr<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*>
(mStream->Engine()->NodeMainThread());
if (!node) {
return NS_OK;
}
nsRefPtr<ScriptProcessorNode> node;
{
// No need to keep holding the lock for the whole duration of this
// function, since we're holding a strong reference to it, so if
// we can obtain the reference, we will hold the node alive in
// this function.
MutexAutoLock lock(mStream->Engine()->NodeMutex());
node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
}
if (!node || !node->Context()) {
AudioContext* context = node->Context();
if (!context) {
return NS_OK;
}
@ -413,9 +403,9 @@ private:
if (!mNullInput) {
ErrorResult rv;
inputBuffer =
AudioBuffer::Create(node->Context(), mInputChannels.Length(),
AudioBuffer::Create(context, mInputChannels.Length(),
node->BufferSize(),
node->Context()->SampleRate(), cx, rv);
context->SampleRate(), cx, rv);
if (rv.Failed()) {
return NS_OK;
}
@ -433,7 +423,7 @@ private:
nsRefPtr<AudioProcessingEvent> event = new AudioProcessingEvent(node, nullptr, nullptr);
event->InitEvent(inputBuffer,
mInputChannels.Length(),
mPlaybackTime);
context->StreamTimeToDOMTime(mPlaybackTime));
node->DispatchTrustedEvent(event);
// Steal the output buffers if they have been set.

Просмотреть файл

@ -117,6 +117,7 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_periodicWave.html]
[test_scriptProcessorNode.html]
[test_scriptProcessorNodeChannelCount.html]
[test_scriptProcessorNode_playbackTime1.html]
[test_scriptProcessorNodeZeroInputOutput.html]
[test_scriptProcessorNodeNotConnected.html]
[test_singleSourceDest.html]

Просмотреть файл

@ -64,8 +64,10 @@ addLoadEvent(function() {
sourceSP.connect(sp);
sp.connect(context.destination);
var lastPlaybackTime = 0;
sp.onaudioprocess = function(e) {
isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
function checkAudioProcessingEvent(e) {
is(e.target, sp, "Correct event target");
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
lastPlaybackTime = e.playbackTime;
@ -76,24 +78,21 @@ addLoadEvent(function() {
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
// Because of the initial latency added by the second script processor node,
// we will never see any generated audio frames in the first callback.
var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
}
sp.onaudioprocess = function(e) {
isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
checkAudioProcessingEvent(e);
// Because of the initial latency added by the second script processor node,
// we will never see any generated audio frames in the first callback.
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
sp.onaudioprocess = function(e) {
is(e.target, sp, "Correct event target");
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
lastPlaybackTime = e.playbackTime;
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
checkAudioProcessingEvent(e);
var firstNonZero = findFirstNonZeroSample(e.inputBuffer);
ok(firstNonZero <= 2048, "First non-zero sample within range");
@ -102,8 +101,6 @@ addLoadEvent(function() {
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), firstNonZero);
compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), 2048 - firstNonZero, firstNonZero, 0);
compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), 2048 - firstNonZero, firstNonZero, 0);
compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
if (firstNonZero == 0) {
// If we did not experience any delays, the test is done!
@ -113,22 +110,12 @@ addLoadEvent(function() {
} else if (firstNonZero != 2048) {
// In case we just saw a zero buffer this time, wait one more round
sp.onaudioprocess = function(e) {
is(e.target, sp, "Correct event target");
ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
lastPlaybackTime = e.playbackTime;
is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
checkAudioProcessingEvent(e);
compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), firstNonZero, 0, 2048 - firstNonZero);
compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), firstNonZero, 0, 2048 - firstNonZero);
compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), undefined, firstNonZero);
compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), undefined, firstNonZero);
compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
sp.onaudioprocess = null;

Просмотреть файл

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test ScriptProcessorNode playbackTime for bug 970773</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(
function() {
const delay = 0.1;
var context = new AudioContext();
SimpleTest.executeSoon( // to ensure that AudioContext has started
function() {
setTimeout( // wait for |delay|
function() {
var sp = context.createScriptProcessor(256);
sp.connect(context.destination);
sp.onaudioprocess =
function(e) {
var minimum =
(delay + e.inputBuffer.length/context.sampleRate) *
(1.0 - 1.0/Math.pow(2.0,52.0)); // double precision
ok(e.playbackTime >= minimum,
"playbackTime " + e.playbackTime +
" beyond expected minimum " + minimum);
sp.onaudioprocess = null;
SimpleTest.finish();
};
}, 1000 * delay);
});
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -71,12 +71,13 @@ class ScriptSettingsStackEntry {
friend class ScriptSettingsStack;
public:
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
~ScriptSettingsStackEntry();
bool NoJSAPI() { return !mGlobalObject; }
protected:
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
nsCOMPtr<nsIGlobalObject> mGlobalObject;
bool mIsCandidateEntryPoint;

Просмотреть файл

@ -4,15 +4,6 @@
# 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/.
DIRS += [
'ucvja',
'ucvcn',
'ucvlatin',
'ucvtw',
'ucvko',
'ucvibm',
]
TEST_DIRS += ['tests']
XPIDL_SOURCES += [
@ -31,6 +22,13 @@ EXPORTS += [
'nsUConvCID.h',
'nsUCSupport.h',
'uconvutil.h',
'ucvcn/nsUCvCnCID.h',
'ucvibm/nsUCvIBMCID.h',
'ucvja/nsUCVJA2CID.h',
'ucvja/nsUCVJACID.h',
'ucvko/nsUCvKOCID.h',
'ucvlatin/nsUCvLatinCID.h',
'ucvtw/nsUCvTWCID.h',
]
UNIFIED_SOURCES += [

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsUCvCnCID.h',
]

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsUCvIBMCID.h',
]

Просмотреть файл

@ -1,10 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsUCVJA2CID.h',
'nsUCVJACID.h',
]

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsUCvKOCID.h',
]

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsUCvLatinCID.h',
]

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS += [
'nsUCvTWCID.h',
]

256
js/public/DebugAPI.h Normal file
Просмотреть файл

@ -0,0 +1,256 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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/. */
// Interfaces by which the embedding can interact with the Debugger API.
#ifndef js_DebugAPI_h
#define js_DebugAPI_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
#include "jspubtd.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
namespace js {
class Debugger;
}
namespace JS {
namespace dbg {
// Helping embedding code build objects for Debugger
// -------------------------------------------------
//
// Some Debugger API features lean on the embedding application to construct
// their result values. For example, Debugger.Frame.prototype.scriptEntryReason
// calls hooks provided by the embedding to construct values explaining why it
// invoked JavaScript; if F is a frame called from a mouse click event handler,
// F.scriptEntryReason would return an object of the form:
//
// { eventType: "mousedown", event: <object> }
//
// where <object> is a Debugger.Object whose referent is the event being
// dispatched.
//
// However, Debugger implements a trust boundary. Debuggee code may be
// considered untrusted; debugger code needs to be protected from debuggee
// getters, setters, proxies, Object.watch watchpoints, and any other feature
// that might accidentally cause debugger code to set the debuggee running. The
// Debugger API tries to make it easy to write safe debugger code by only
// offering access to debuggee objects via Debugger.Object instances, which
// ensure that only those operations whose explicit purpose is to invoke
// debuggee code do so. But this protective membrane is only helpful if we
// interpose Debugger.Object instances in all the necessary spots.
//
// SpiderMonkey's compartment system also implements a trust boundary. The
// debuggee and debugger are always in different compartments. Inter-compartment
// work requires carefully tracking which compartment each JSObject or JS::Value
// belongs to, and ensuring that is is correctly wrapped for each operation.
//
// It seems precarious to expect the embedding's hooks to implement these trust
// boundaries. Instead, the JS::dbg::Builder API segregates the code which
// constructs trusted objects from that which deals with untrusted objects.
// Trusted objects have an entirely different C++ type, so code that improperly
// mixes trusted and untrusted objects is caught at compile time.
//
// In the structure shown above, there are two trusted objects, and one
// untrusted object:
//
// - The overall object, with the 'eventType' and 'event' properties, is a
// trusted object. We're going to return it to D.F.p.scriptEntryReason's
// caller, which will handle it directly.
//
// - The Debugger.Object instance appearing as the value of the 'event' property
// is a trusted object. It belongs to the same Debugger instance as the
// Debugger.Frame instance whose scriptEntryReason accessor was called, and
// presents a safe reflection-oriented API for inspecting its referent, which
// is:
//
// - The actual event object, an untrusted object, and the referent of the
// Debugger.Object above. (Content can do things like replacing accessors on
// Event.prototype.)
//
// Using JS::dbg::Builder, all objects and values the embedding deals with
// directly are considered untrusted, and are assumed to be debuggee values. The
// only way to construct trusted objects is to use Builder's own methods, which
// return a separate Object type. The only way to set a property on a trusted
// object is through that Object type. The actual trusted object is never
// exposed to the embedding.
//
// So, for example, the embedding might use code like the following to construct
// the object shown above, given a Builder passed to it by Debugger:
//
// bool
// MyScriptEntryReason::explain(JSContext *cx,
// Builder &builder,
// Builder::Object &result)
// {
// JSObject *eventObject = ... obtain debuggee event object somehow ...;
// if (!eventObject)
// return false;
// result = builder.newObject(cx);
// return result &&
// result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) &&
// result.defineProperty(cx, "event", eventObject);
// }
//
//
// Object::defineProperty also accepts an Object as the value to store on the
// property. By its type, we know that the value is trusted, so we set it
// directly as the property's value, without interposing a Debugger.Object
// wrapper. This allows the embedding to builted nested structures of trusted
// objects.
//
// The Builder and Builder::Object methods take care of doing whatever
// compartment switching and wrapping are necessary to construct the trusted
// values in the Debugger's compartment.
//
// The Object type is self-rooting. Construction, assignment, and destruction
// all properly root the referent object.
class BuilderOrigin;
class Builder {
// The Debugger instance whose client we are building a value for. We build
// objects in this object's compartment.
PersistentRootedObject debuggerObject;
// debuggerObject's Debugger structure, for convenience.
js::Debugger *debugger;
// Check that |thing| is in the same compartment as our debuggerObject. Used
// for assertions when constructing BuiltThings. We can overload this as we
// add more instantiations of BuiltThing.
#if DEBUG
void assertBuilt(JSObject *obj);
#else
void assertBuilt(JSObject *obj) { }
#endif
protected:
// A reference to a trusted object or value. At the moment, we only use it
// with JSObject *.
template<typename T>
class BuiltThing {
friend class BuilderOrigin;
void nonNull() {}
protected:
// The Builder to which this trusted thing belongs.
Builder &owner;
// A rooted reference to our value.
PersistentRooted<T> value;
BuiltThing(JSContext *cx, Builder &owner_, T value_ = js::GCMethods<T>::initial())
: owner(owner_), value(cx, value_)
{
owner.assertBuilt(value_);
}
// Forward some things from our owner, for convenience.
js::Debugger *debugger() const { return owner.debugger; }
JSObject *debuggerObject() const { return owner.debuggerObject; }
public:
BuiltThing(const BuiltThing &rhs) : owner(rhs.owner), value(rhs.value) { }
BuiltThing &operator=(const BuiltThing &rhs) {
MOZ_ASSERT(&owner == &rhs.owner);
owner.assertBuilt(rhs.value);
value = rhs.value;
return *this;
}
typedef void (BuiltThing::* ConvertibleToBool)();
operator ConvertibleToBool() const {
// If we ever instantiate BuiltThink<Value>, this might not suffice.
return value ? &BuiltThing::nonNull : 0;
}
private:
BuiltThing() MOZ_DELETE;
};
public:
// A reference to a trusted object, possibly null. Instances of Object are
// always properly rooted. They can be copied and assigned, as if they were
// pointers.
class Object: private BuiltThing<JSObject *> {
friend class Builder; // for construction
friend class BuilderOrigin; // for unwrapping
typedef BuiltThing<JSObject *> Base;
// This is private, because only Builders can create Objects that
// actually point to something (hence the 'friend' declaration).
Object(JSContext *cx, Builder &owner_, HandleObject obj) : Base(cx, owner_, obj.get()) { }
bool definePropertyToTrusted(JSContext *cx, const char *name,
JS::MutableHandleValue value);
public:
Object(JSContext *cx, Builder &owner_) : Base(cx, owner_, nullptr) { }
Object(const Object &rhs) : Base(rhs) { }
// Our automatically-generated assignment operator can see our base
// class's assignment operator, so we don't need to write one out here.
// Set the property named |name| on this object to |value|.
//
// If |value| is a string or primitive, re-wrap it for the debugger's
// compartment.
//
// If |value| is an object, assume it is a debuggee object and make a
// Debugger.Object instance referring to it. Set that as the propery's
// value.
//
// If |value| is another trusted object, store it directly as the
// property's value.
//
// On error, report the problem on cx and return false.
bool defineProperty(JSContext *cx, const char *name, JS::HandleValue value);
bool defineProperty(JSContext *cx, const char *name, JS::HandleObject value);
bool defineProperty(JSContext *cx, const char *name, Object &value);
using Base::ConvertibleToBool;
using Base::operator ConvertibleToBool;
};
// Build an empty object for direct use by debugger code, owned by this
// Builder. If an error occurs, report it on cx and return a false Object.
Object newObject(JSContext *cx);
protected:
Builder(JSContext *cx, js::Debugger *debugger);
};
// Debugger itself instantiates this subclass of Builder, which can unwrap
// BuiltThings that belong to it.
class BuilderOrigin : public Builder {
template<typename T>
T unwrapAny(const BuiltThing<T> &thing) {
MOZ_ASSERT(&thing.owner == this);
return thing.value.get();
}
public:
BuilderOrigin(JSContext *cx, js::Debugger *debugger_)
: Builder(cx, debugger_)
{ }
JSObject *unwrap(Object &object) { return unwrapAny(object); }
};
} // namespace dbg
} // namespace JS
#endif /* js_DebugAPI_h */

Просмотреть файл

@ -198,7 +198,10 @@ class Base {
// edges. The EdgeRange should be freed with 'js_delete'. (You could use
// ScopedDJSeletePtr<EdgeRange> to manage it.) On OOM, report an exception
// on |cx| and return nullptr.
virtual EdgeRange *edges(JSContext *cx) const = 0;
//
// If wantNames is true, compute names for edges. Doing so can be expensive
// in time and memory.
virtual EdgeRange *edges(JSContext *cx, bool wantNames) const = 0;
// Return the Zone to which this node's referent belongs, or nullptr if the
// referent is not of a type allocated in SpiderMonkey Zones.
@ -333,9 +336,11 @@ class Node {
const jschar *typeName() const { return base()->typeName(); }
size_t size() const { return base()->size(); }
EdgeRange *edges(JSContext *cx) const { return base()->edges(cx); }
JS::Zone *zone() const { return base()->zone(); }
JSCompartment *compartment() const { return base()->compartment(); }
EdgeRange *edges(JSContext *cx, bool wantNames = true) const {
return base()->edges(cx, wantNames);
}
// A hash policy for ubi::Nodes.
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
@ -365,7 +370,8 @@ class Edge {
virtual ~Edge() { }
public:
// This edge's name.
// This edge's name. This may be nullptr, if Node::edges was called with
// false as the wantNames parameter.
//
// The storage is owned by this Edge, and will be freed when this Edge is
// destructed.
@ -428,7 +434,7 @@ template<typename Referent>
class TracerConcrete : public Base {
const jschar *typeName() const MOZ_OVERRIDE { return concreteTypeName; }
size_t size() const MOZ_OVERRIDE { return 0; } // not implemented yet; bug 1011300
EdgeRange *edges(JSContext *) const MOZ_OVERRIDE;
EdgeRange *edges(JSContext *, bool wantNames) const MOZ_OVERRIDE;
JS::Zone *zone() const MOZ_OVERRIDE { return get().zone(); }
JSCompartment *compartment() const MOZ_OVERRIDE { return nullptr; }
@ -472,7 +478,7 @@ template<>
class Concrete<void> : public Base {
const jschar *typeName() const MOZ_OVERRIDE;
size_t size() const MOZ_OVERRIDE;
EdgeRange *edges(JSContext *cx) const MOZ_OVERRIDE;
EdgeRange *edges(JSContext *cx, bool wantNames) const MOZ_OVERRIDE;
JS::Zone *zone() const MOZ_OVERRIDE;
JSCompartment *compartment() const MOZ_OVERRIDE;

Просмотреть файл

@ -84,7 +84,7 @@ struct BreadthFirst {
// We do nothing with noGC, other than require it to exist, with a lifetime
// that encloses our own.
BreadthFirst(JSContext *cx, Handler &handler, const JS::AutoCheckCannotGC &noGC)
: cx(cx), visited(cx), handler(handler), pending(cx),
: wantNames(true), cx(cx), visited(cx), handler(handler), pending(cx),
traversalBegun(false), stopRequested(false), abandonRequested(false)
{ }
@ -95,6 +95,10 @@ struct BreadthFirst {
// as many starting points as you like. Return false on OOM.
bool addStart(Node node) { return pending.append(node); }
// True if the handler wants us to compute edge names; doing so can be
// expensive in time and memory. True by default.
bool wantNames;
// Traverse the graph in breadth-first order, starting at the given
// start nodes, applying |handler::operator()| for each edge traversed
// as described above.
@ -113,7 +117,7 @@ struct BreadthFirst {
pending.popFront();
// Get a range containing all origin's outgoing edges.
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx));
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx, wantNames));
if (!range)
return false;

Просмотреть файл

@ -123,9 +123,6 @@ ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Gl
if (!GetDataProperty(cx, importVal, field, &v))
return false;
if (!v.isPrimitive())
return LinkFail(cx, "Imported values must be primitives");
switch (global.varInitCoercion()) {
case AsmJS_ToInt32:
if (!ToInt32(cx, v, (int32_t *)datum))
@ -184,7 +181,6 @@ ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleVa
RootedValue v(cx);
if (!GetDataProperty(cx, globalVal, cx->names().Math, &v))
return false;
RootedPropertyName field(cx, global.mathName());
if (!GetDataProperty(cx, v, field, &v))
return false;
@ -230,7 +226,6 @@ ValidateConstant(JSContext *cx, AsmJSModule::Global &global, HandleValue globalV
if (!GetDataProperty(cx, v, field, &v))
return false;
if (!v.isNumber())
return LinkFail(cx, "math / global constant value needs to be a number");

Просмотреть файл

@ -1,5 +1,4 @@
load(libdir + "asm.js");
load(libdir + "asserts.js");
assertAsmTypeFail(USE_ASM + "var i; function f(){} return f");
assertAsmTypeFail(USE_ASM + "const i; function f(){} return f");
@ -118,14 +117,6 @@ assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f() { var i=42; while (1) { break; } g = i; return g|0 } return f"))(), 42);
assertAsmLinkFail(asmCompile('glob','foreign', USE_ASM + 'var i = +foreign.x; function f() {} return f'), null, {x:{valueOf:function() { return 42 }}});
assertAsmLinkFail(asmCompile('glob','foreign', USE_ASM + 'var i = foreign.x|0; function f() {} return f'), null, {x:{valueOf:function() { return 42 }}});
assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var i = foreign.x|0; function f() { return i|0} return f'), null, {x:"blah"})(), 0);
assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var i = +foreign.x; function f() { return +i} return f'), null, {x:"blah"})(), NaN);
assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var tof = glob.Math.fround; var i = tof(foreign.x); function f() { return +i} return f'), this, {x:"blah"})(), NaN);
assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var i = foreign.x|0; function f() { return i|0} return f')(null, {x:Symbol("blah")}), TypeError);
assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var i = +foreign.x; function f() { return +i} return f')(null, {x:Symbol("blah")}), TypeError);
assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var tof = glob.Math.fround; var i = tof(foreign.x); function f() { return +i} return f')(this, {x:Symbol("blah")}), TypeError);
var f1 = asmCompile('global', 'foreign', 'heap', USE_ASM + 'var i32 = new global.Int32Array(heap); function g() { return i32[4]|0 } return g');
var global = this;

Просмотреть файл

@ -686,12 +686,27 @@ class MDefinition : public MNode
public:
// Opcode testing and casts.
template<typename MIRType> bool is() const {
return op() == MIRType::classOpcode;
}
template<typename MIRType> MIRType *to() {
JS_ASSERT(is<MIRType>());
return static_cast<MIRType *>(this);
}
template<typename MIRType> const MIRType *to() const {
JS_ASSERT(is<MIRType>());
return static_cast<const MIRType *>(this);
}
# define OPCODE_CASTS(opcode) \
bool is##opcode() const { \
return op() == Op_##opcode; \
return is<M##opcode>(); \
} \
inline M##opcode *to##opcode(); \
inline const M##opcode *to##opcode() const;
M##opcode *to##opcode() { \
return to<M##opcode>(); \
} \
const M##opcode *to##opcode() const { \
return to<M##opcode>(); \
}
MIR_OPCODE_LIST(OPCODE_CASTS)
# undef OPCODE_CASTS
@ -832,8 +847,9 @@ class MInstruction
};
#define INSTRUCTION_HEADER(opcode) \
static const Opcode classOpcode = MDefinition::Op_##opcode; \
Opcode op() const { \
return MDefinition::Op_##opcode; \
return classOpcode; \
} \
const char *opName() const { \
return #opcode; \
@ -6632,7 +6648,8 @@ class MTypedArrayElements
// Checks whether a typed object is neutered.
class MNeuterCheck
: public MUnaryInstruction
: public MUnaryInstruction,
public SingleObjectPolicy
{
private:
explicit MNeuterCheck(MDefinition *object)
@ -6663,6 +6680,10 @@ class MNeuterCheck
AliasSet getAliasSet() const {
return AliasSet::Load(AliasSet::ObjectFields);
}
TypePolicy *typePolicy() {
return this;
}
};
// Load a binary data object's "elements", which is just its opaque
@ -11247,6 +11268,8 @@ class MAsmJSCall MOZ_FINAL : public MVariadicInstruction
}
};
#undef INSTRUCTION_HEADER
void MUse::init(MDefinition *producer, MNode *consumer)
{
MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
@ -11284,22 +11307,7 @@ void MUse::discardProducer()
producer_ = nullptr;
}
#undef INSTRUCTION_HEADER
// Implement opcode casts now that the compiler can see the inheritance.
#define OPCODE_CASTS(opcode) \
M##opcode *MDefinition::to##opcode() \
{ \
JS_ASSERT(is##opcode()); \
return static_cast<M##opcode *>(this); \
} \
const M##opcode *MDefinition::to##opcode() const \
{ \
JS_ASSERT(is##opcode()); \
return static_cast<const M##opcode *>(this); \
}
MIR_OPCODE_LIST(OPCODE_CASTS)
#undef OPCODE_CASTS
// Implement cast functions now that the compiler can see the inheritance.
MDefinition *MNode::toDefinition()
{

Просмотреть файл

@ -19,6 +19,7 @@
#include "js/CharacterEncoding.h"
#include "js/Class.h"
#include "js/Date.h"
#include "js/DebugAPI.h"
#include "js/GCAPI.h"
#include "js/HashTable.h"
#include "js/HeapAPI.h"

Просмотреть файл

@ -71,6 +71,7 @@ EXPORTS.js += [
'../public/CharacterEncoding.h',
'../public/Class.h',
'../public/Date.h',
'../public/DebugAPI.h',
'../public/GCAPI.h',
'../public/HashTable.h',
'../public/HeapAPI.h',

Просмотреть файл

@ -18,6 +18,7 @@
#include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h"
#include "jit/BaselineJIT.h"
#include "js/DebugAPI.h"
#include "js/GCAPI.h"
#include "js/Vector.h"
#include "vm/ArgumentsObject.h"
@ -35,6 +36,7 @@
using namespace js;
using JS::dbg::Builder;
using js::frontend::IsIdentifier;
using mozilla::ArrayLength;
using mozilla::Maybe;
@ -6276,6 +6278,81 @@ static const JSFunctionSpec DebuggerEnv_methods[] = {
};
/*** JS::dbg::Builder ****************************************************************************/
Builder::Builder(JSContext *cx, js::Debugger *debugger)
: debuggerObject(cx, debugger->toJSObject().get()),
debugger(debugger)
{ }
#if DEBUG
void
Builder::assertBuilt(JSObject *obj)
{
// We can't use assertSameCompartment here, because that is always keyed to
// some JSContext's current compartment, whereas BuiltThings can be
// constructed and assigned to without respect to any particular context;
// the only constraint is that they should be in their debugger's compartment.
MOZ_ASSERT_IF(obj, debuggerObject->compartment() == obj->compartment());
}
#endif
bool
Builder::Object::definePropertyToTrusted(JSContext *cx, const char *name,
JS::MutableHandleValue trusted)
{
// We should have checked for false Objects before calling this.
MOZ_ASSERT(value);
JSAtom *atom = Atomize(cx, name, strlen(name));
if (!atom)
return false;
RootedId id(cx, AtomToId(atom));
return JSObject::defineGeneric(cx, value, id, trusted);
}
bool
Builder::Object::defineProperty(JSContext *cx, const char *name, JS::HandleValue propval_)
{
AutoCompartment ac(cx, debuggerObject());
RootedValue propval(cx, propval_);
if (!debugger()->wrapDebuggeeValue(cx, &propval))
return false;
return definePropertyToTrusted(cx, name, &propval);
}
bool
Builder::Object::defineProperty(JSContext *cx, const char *name, JS::HandleObject propval_)
{
RootedValue propval(cx, ObjectOrNullValue(propval_));
return defineProperty(cx, name, propval);
}
bool
Builder::Object::defineProperty(JSContext *cx, const char *name, Builder::Object &propval_)
{
AutoCompartment ac(cx, debuggerObject());
RootedValue propval(cx, ObjectOrNullValue(propval_.value));
return definePropertyToTrusted(cx, name, &propval);
}
Builder::Object
Builder::newObject(JSContext *cx)
{
AutoCompartment ac(cx, debuggerObject);
RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
// If the allocation failed, this will return a false Object, as the spec promises.
return Object(cx, *this, obj);
}
/*** Glue ****************************************************************************************/

Просмотреть файл

@ -643,6 +643,7 @@ DebuggerMemory::takeCensus(JSContext *cx, unsigned argc, Value *vp)
dbg::DefaultCensusTraversal traversal(cx, handler, noGC);
if (!traversal.init())
return false;
traversal.wantNames = false;
// Walk the debuggee compartments, using it to set the starting points
// (the debuggee globals) for the traversal, and to populate

Просмотреть файл

@ -28,11 +28,11 @@ using JS::ubi::Node;
using JS::ubi::TracerConcrete;
// All operations on null ubi::Nodes crash.
const jschar *Concrete<void>::typeName() const { MOZ_CRASH("null ubi::Node"); }
size_t Concrete<void>::size() const { MOZ_CRASH("null ubi::Node"); }
EdgeRange *Concrete<void>::edges(JSContext *) const { MOZ_CRASH("null ubi::Node"); }
JS::Zone *Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
JSCompartment *Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
const jschar *Concrete<void>::typeName() const { MOZ_CRASH("null ubi::Node"); }
size_t Concrete<void>::size() const { MOZ_CRASH("null ubi::Node"); }
EdgeRange *Concrete<void>::edges(JSContext *, bool) const { MOZ_CRASH("null ubi::Node"); }
JS::Zone *Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
JSCompartment *Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
Node::Node(JSGCTraceKind kind, void *ptr)
{
@ -132,6 +132,9 @@ class SimpleEdgeVectorTracer : public JSTracer {
// The vector to which we add SimpleEdges.
SimpleEdgeVector *vec;
// True if we should populate the edge's names.
bool wantNames;
static void staticCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) {
static_cast<SimpleEdgeVectorTracer *>(trc)->callback(thingp, kind);
}
@ -140,22 +143,25 @@ class SimpleEdgeVectorTracer : public JSTracer {
if (!okay)
return;
// Ask the tracer to compute an edge name for us.
char buffer[1024];
const char *name = getTracingEdgeName(buffer, sizeof(buffer));
jschar *jsname = nullptr;
if (wantNames) {
// Ask the tracer to compute an edge name for us.
char buffer[1024];
const char *name = getTracingEdgeName(buffer, sizeof(buffer));
// Convert the name to jschars.
jschar *jsname = js_pod_malloc<jschar>(strlen(name) + 1);
if (!jsname) {
okay = false;
return;
// Convert the name to jschars.
jsname = js_pod_malloc<jschar>(strlen(name) + 1);
if (!jsname) {
okay = false;
return;
}
size_t i;
for (i = 0; name[i]; i++)
jsname[i] = name[i];
jsname[i] = '\0';
}
size_t i;
for (i = 0; name[i]; i++)
jsname[i] = name[i];
jsname[i] = '\0';
// The simplest code is correct! The temporary SimpleEdge takes
// ownership of name; if the append succeeds, the vector element
// then takes ownership; if the append fails, then the temporary
@ -170,9 +176,12 @@ class SimpleEdgeVectorTracer : public JSTracer {
// True if no errors (OOM, say) have yet occurred.
bool okay;
SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec)
: JSTracer(JS_GetRuntime(cx), staticCallback), vec(vec), okay(true) {
}
SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec, bool wantNames)
: JSTracer(JS_GetRuntime(cx), staticCallback),
vec(vec),
wantNames(wantNames),
okay(true)
{ }
};
@ -189,8 +198,8 @@ class SimpleEdgeRange : public EdgeRange {
public:
explicit SimpleEdgeRange(JSContext *cx) : edges(cx), i(0) { }
bool init(JSContext *cx, void *thing, JSGCTraceKind kind) {
SimpleEdgeVectorTracer tracer(cx, &edges);
bool init(JSContext *cx, void *thing, JSGCTraceKind kind, bool wantNames = true) {
SimpleEdgeVectorTracer tracer(cx, &edges, wantNames);
JS_TraceChildren(&tracer, thing, kind);
settle();
return tracer.okay;
@ -202,12 +211,12 @@ class SimpleEdgeRange : public EdgeRange {
template<typename Referent>
EdgeRange *
TracerConcrete<Referent>::edges(JSContext *cx) const {
TracerConcrete<Referent>::edges(JSContext *cx, bool wantNames) const {
js::ScopedJSDeletePtr<SimpleEdgeRange> r(js_new<SimpleEdgeRange>(cx));
if (!r)
return nullptr;
if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind))
if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind, wantNames))
return nullptr;
return r.forget();

Просмотреть файл

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Drop Shadow Default Color</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#drop-shadow);
background-color: #00f;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blue square with a green drop shadow.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

Просмотреть файл

@ -0,0 +1,31 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Drop Shadow Default Color</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
<link rel="help" href="http://www.w3.org/TR/css3-background/#the-box-shadow">
<link rel="match" href="drop-shadow-default-color-ref.html">
<meta name="assert"
content="If the color is unspecified in a CSS drop-shadow filter
function, it should default to the value of the CSS color
property.">
<style type="text/css">
#target {
filter: drop-shadow(10px 10px 3px);
color: #0f0;
background-color: #00f;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blue square with a green drop shadow.</p>
<div id="target"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,31 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Negative Drop Shadow Offset</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#drop-shadow);
background-color: #00f;
position: relative;
top: 20px;
left: 20px;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blue square with a green drop shadow in its top left corner.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<feDropShadow dx="-10" dy="-10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

Просмотреть файл

@ -0,0 +1,32 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Negative Drop Shadow Offset</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
<link rel="match" href="drop-shadow-negative-offset-ref.html">
<meta name="assert"
content="Given negative shadow offsets, the CSS drop-shadow filter
function should add a drop shadow extending from the top left
corner of an HTML element.">
<style type="text/css">
#target {
filter: drop-shadow(-10px -10px 3px #0f0);
background-color: #00f;
position: relative;
top: 20px;
left: 20px;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blue square with a green drop shadow in its top left corner.</p>
<div id="target"></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Drop Shadow on HTML Element</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<style type="text/css">
#target {
filter: url(#drop-shadow);
background-color: #00f;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blue square with a green drop shadow.</p>
<div id="target"></div>
<svg width="0" height="0">
<filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
<feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
</filter>
</svg>
</body>
</html>

Просмотреть файл

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<html>
<head>
<title>CSS Filters: Drop Shadow on HTML Element</title>
<link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
<link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
<link rel="match" href="drop-shadow-ref.html">
<meta name="assert"
content="The CSS drop-shadow filter function should add a drop shadow to
an HTML element.">
<style type="text/css">
#target {
filter: drop-shadow(10px 10px 3px #0f0);
background-color: #00f;
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<p>You should see a blue square with a green drop shadow.</p>
<div id="target"></div>
</body>
</html>

Просмотреть файл

@ -7,3 +7,6 @@ default-preferences pref(layout.css.filters.enabled,true)
== blur.svg blur-ref.svg
== blur-zero-radius.html blur-zero-radius-ref.html
== blur-zoomed-page.html blur-zoomed-page-ref.html
== drop-shadow.html drop-shadow-ref.html
== drop-shadow-default-color.html drop-shadow-default-color-ref.html
== drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html

Просмотреть файл

@ -3,7 +3,7 @@
fuzzy(110,1802) == additive-1.svg additive-1-ref.svg # bug 981344
== animate-width-1.svg lime.svg
fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,1,1) == paced-1.svg paced-1-ref.svg # bug 981640
fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,4) == paced-1.svg paced-1-ref.svg # bug 981640
== rotate-angle-1.svg rotate-angle-ref.svg
== rotate-angle-2.svg rotate-angle-ref.svg
== rotate-angle-3.svg rotate-angle-ref.svg

Просмотреть файл

@ -9,6 +9,7 @@
// Keep others in (case-insensitive) order:
#include "gfx2DGlue.h"
#include "gfxUtils.h"
#include "nsIFrame.h"
#include "nsStyleStruct.h"
#include "nsTArray.h"
@ -16,9 +17,11 @@ using namespace mozilla;
using namespace mozilla::gfx;
nsCSSFilterInstance::nsCSSFilterInstance(const nsStyleFilter& aFilter,
nsIFrame *aTargetFrame,
const nsIntRect& aTargetBBoxInFilterSpace,
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
: mFilter(aFilter)
, mTargetFrame(aTargetFrame)
, mTargetBBoxInFilterSpace(aTargetBBoxInFilterSpace)
, mFrameSpaceInCSSPxToFilterSpaceTransform(aFrameSpaceInCSSPxToFilterSpaceTransform)
{
@ -38,6 +41,9 @@ nsCSSFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrim
case NS_STYLE_FILTER_BRIGHTNESS:
case NS_STYLE_FILTER_CONTRAST:
case NS_STYLE_FILTER_DROP_SHADOW:
descr = CreatePrimitiveDescription(PrimitiveType::DropShadow, aPrimitiveDescrs);
result = SetAttributesForDropShadow(descr);
break;
case NS_STYLE_FILTER_GRAYSCALE:
case NS_STYLE_FILTER_HUE_ROTATE:
case NS_STYLE_FILTER_INVERT:
@ -78,17 +84,49 @@ nsCSSFilterInstance::CreatePrimitiveDescription(PrimitiveType aType,
nsresult
nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
{
// Get the radius from the style.
nsStyleCoord radiusStyleCoord = mFilter.GetFilterParameter();
if (radiusStyleCoord.GetUnit() != eStyleUnit_Coord) {
const nsStyleCoord& radiusInFrameSpace = mFilter.GetFilterParameter();
if (radiusInFrameSpace.GetUnit() != eStyleUnit_Coord) {
NS_NOTREACHED("unexpected unit");
return NS_ERROR_FAILURE;
}
// Get the radius in frame space.
nscoord radiusInFrameSpace = radiusStyleCoord.GetCoordValue();
Size radiusInFilterSpace = BlurRadiusToFilterSpace(radiusInFrameSpace.GetCoordValue());
aDescr.Attributes().Set(eGaussianBlurStdDeviation, radiusInFilterSpace);
return NS_OK;
}
nsresult
nsCSSFilterInstance::SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr)
{
nsCSSShadowArray* shadows = mFilter.GetDropShadow();
if (!shadows || shadows->Length() != 1) {
NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
return NS_ERROR_FAILURE;
}
nsCSSShadowItem* shadow = shadows->ShadowAt(0);
// Set drop shadow blur radius.
Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
aDescr.Attributes().Set(eDropShadowStdDeviation, radiusInFilterSpace);
// Set offset.
IntPoint offsetInFilterSpace = OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
aDescr.Attributes().Set(eDropShadowOffset, offsetInFilterSpace);
// Set color. If unspecified, use the CSS color property.
nscolor shadowColor = shadow->mHasColor ?
shadow->mColor : mTargetFrame->StyleColor()->mColor;
aDescr.Attributes().Set(eDropShadowColor, ToAttributeColor(shadowColor));
return NS_OK;
}
Size
nsCSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace)
{
float radiusInFrameSpaceInCSSPx =
nsPresContext::AppUnitsToFloatCSSPixels(radiusInFrameSpace);
nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
// Convert the radius to filter space.
gfxSize radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
@ -101,15 +139,40 @@ nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
// Check the radius limits.
if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
NS_NOTREACHED("we shouldn't have parsed a negative radius in the style");
return NS_ERROR_FAILURE;
return Size();
}
gfxFloat maxStdDeviation = (gfxFloat)kMaxStdDeviation;
radiusInFilterSpace.width = std::min(radiusInFilterSpace.width, maxStdDeviation);
radiusInFilterSpace.height = std::min(radiusInFilterSpace.height, maxStdDeviation);
// Set the radius parameter.
aDescr.Attributes().Set(eGaussianBlurStdDeviation, ToSize(radiusInFilterSpace));
return NS_OK;
return ToSize(radiusInFilterSpace);
}
IntPoint
nsCSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
nscoord aYOffsetInFrameSpace)
{
gfxPoint offsetInFilterSpace(nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
// Convert the radius to filter space.
gfxSize frameSpaceInCSSPxToFilterSpaceScale =
mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.width;
offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.height;
return IntPoint(int32_t(offsetInFilterSpace.x), int32_t(offsetInFilterSpace.y));
}
Color
nsCSSFilterInstance::ToAttributeColor(nscolor aColor)
{
return Color(
NS_GET_R(aColor) / 255.0,
NS_GET_G(aColor) / 255.0,
NS_GET_B(aColor) / 255.0,
NS_GET_A(aColor) / 255.0
);
}
int32_t

Просмотреть файл

@ -9,7 +9,11 @@
#include "FilterSupport.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Types.h"
#include "nsColor.h"
class nsIFrame;
struct nsStyleFilter;
template<class T> class nsTArray;
@ -20,8 +24,11 @@ template<class T> class nsTArray;
*/
class nsCSSFilterInstance
{
typedef mozilla::gfx::Color Color;
typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
typedef mozilla::gfx::IntPoint IntPoint;
typedef mozilla::gfx::PrimitiveType PrimitiveType;
typedef mozilla::gfx::Size Size;
public:
/**
@ -34,6 +41,7 @@ public:
* the filtered element's frame space in CSS pixels to filter space.
*/
nsCSSFilterInstance(const nsStyleFilter& aFilter,
nsIFrame *aTargetFrame,
const nsIntRect& mTargetBBoxInFilterSpace,
const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform);
@ -55,6 +63,7 @@ private:
* Sets aDescr's attributes using the style info in mFilter.
*/
nsresult SetAttributesForBlur(FilterPrimitiveDescription& aDescr);
nsresult SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr);
/**
* Returns the index of the last result in the aPrimitiveDescrs, which we'll
@ -71,11 +80,34 @@ private:
void SetBounds(FilterPrimitiveDescription& aDescr,
const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
/**
* Converts an nscolor to a Color, suitable for use as a
* FilterPrimitiveDescription attribute.
*/
Color ToAttributeColor(nscolor aColor);
/**
* Converts a blur radius in frame space to filter space.
*/
Size BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace);
/**
* Converts a point defined by a pair of nscoord x, y coordinates from frame
* space to filter space.
*/
IntPoint OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
nscoord aYOffsetInFrameSpace);
/**
* The CSS filter originally from the style system.
*/
const nsStyleFilter& mFilter;
/**
* The frame for the element that is currently being filtered.
*/
nsIFrame* mTargetFrame;
/**
* The bounding box of the element being filtered, in filter space. Used for
* input bounds if this CSS filter is the first in the filter chain.

Просмотреть файл

@ -260,7 +260,8 @@ nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
}
// Build primitives for a CSS filter.
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetBBoxInFilterSpace,
nsCSSFilterInstance cssFilterInstance(aFilter, mTargetFrame,
mTargetBBoxInFilterSpace,
mFrameSpaceInCSSPxToFilterSpaceTransform);
return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions);
}

Просмотреть файл

@ -119,7 +119,7 @@ nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset)
int
nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset)
{
UINT8 d = htonll(data);
UINT8 d = nr_htonll(data);
if (*offset + sizeof(d) > buflen) {
r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
@ -193,7 +193,7 @@ nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data)
memcpy(&d, &buf[*offset], sizeof(d));
*offset += sizeof(d);
*data = htonll(d);
*data = nr_htonll(d);
return 0;
}

Просмотреть файл

@ -53,7 +53,7 @@ static char *RCSSTRING __UNUSED__ ="$Id: byteorder.c,v 1.2 2007/06/26 22:37:55 a
BYTE((n),(y))=tmp
UINT8
htonll(UINT8 hostlonglong)
nr_htonll(UINT8 hostlonglong)
{
UINT8 netlonglong = hostlonglong;
UCHAR tmp;
@ -69,8 +69,8 @@ htonll(UINT8 hostlonglong)
}
UINT8
ntohll(UINT8 netlonglong)
nr_ntohll(UINT8 netlonglong)
{
return htonll(netlonglong);
return nr_htonll(netlonglong);
}

Просмотреть файл

@ -39,9 +39,9 @@
#ifndef _byteorder_h
#define _byteorder_h
UINT8 htonll(UINT8 hostlonglong);
UINT8 nr_htonll(UINT8 hostlonglong);
UINT8 ntohll(UINT8 netlonglong);
UINT8 nr_ntohll(UINT8 netlonglong);
#endif

Просмотреть файл

@ -592,7 +592,9 @@ static const uint32_t EnabledCiphers[] = {
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
};
// Disalbe all NSS suites modes without PFS or with old and rusty ciphersuites.
// Don't remove suites; TODO(mt@mozilla.com) restore; bug 1052610
#if 0
// Disable all NSS suites modes without PFS or with old and rusty ciphersuites.
// Anything outside this list is governed by the usual combination of policy
// and user preferences.
static const uint32_t DisabledCiphers[] = {
@ -647,6 +649,7 @@ static const uint32_t DisabledCiphers[] = {
TLS_RSA_WITH_NULL_SHA256,
TLS_RSA_WITH_NULL_MD5,
};
#endif // bug 1052610
bool TransportLayerDtls::SetupCipherSuites(PRFileDesc* ssl_fd) const {
SECStatus rv;

Просмотреть файл

@ -458,8 +458,8 @@ pref("apz.zoom_animation_duration_ms", 250);
pref("apz.subframe.enabled", true);
pref("apz.fling_repaint_interval", 16);
pref("apz.pan_repaint_interval", 16);
pref("apz.apz.x_skate_size_multiplier", "2.5");
pref("apz.apz.y_skate_size_multiplier", "3.5");
pref("apz.x_skate_size_multiplier", "2.5");
pref("apz.y_skate_size_multiplier", "3.5");
#else
pref("apz.subframe.enabled", false);
pref("apz.fling_repaint_interval", 75);

Просмотреть файл

@ -47,7 +47,7 @@ namespace mozilla {
#if defined(ANDROID)
#define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args)
#else
#define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt, ## args)
#define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt "\n", ## args)
#endif
#ifdef MOZ_GMP_SANDBOX

Просмотреть файл

@ -54,13 +54,6 @@ class GeckoRuntimeRunner(BaseRunner):
# Bug 775416 - Ensure that binary options are passed in first
command[1:1] = self.cmdargs
# If running on OS X 10.5 or older, wrap |cmd| so that it will
# be executed as an i386 binary, in case it's a 32-bit/64-bit universal
# binary.
if mozinfo.isMac and hasattr(platform, 'mac_ver') and \
platform.mac_ver()[0][:4] < '10.6':
command = ["arch", "-arch", "i386"] + command
if hasattr(self.app_ctx, 'wrap_command'):
command = self.app_ctx.wrap_command(command)
return command

Просмотреть файл

@ -11,6 +11,13 @@
#include "nsAutoPtr.h"
#ifndef MOZ_CALLSTACK_DISABLED
#include "CodeAddressService.h"
#include "nsHashKeys.h"
#include "nsStackWalk.h"
#include "nsTHashtable.h"
#endif
#include "mozilla/CondVar.h"
#include "mozilla/DeadlockDetector.h"
#include "mozilla/ReentrantMonitor.h"
@ -41,6 +48,31 @@ unsigned BlockingResourceBase::sResourceAcqnChainFrontTPI = (unsigned)-1;
BlockingResourceBase::DDT* BlockingResourceBase::sDeadlockDetector;
void
BlockingResourceBase::StackWalkCallback(void* aPc, void* aSp, void* aClosure)
{
#ifndef MOZ_CALLSTACK_DISABLED
AcquisitionState* state = (AcquisitionState*)aClosure;
state->AppendElement(aPc);
#endif
}
void
BlockingResourceBase::GetStackTrace(AcquisitionState& aState)
{
#ifndef MOZ_CALLSTACK_DISABLED
// Skip this function and the calling function.
const uint32_t kSkipFrames = 2;
aState.Clear();
// NB: Ignore the return value, there's nothing useful we can do if this
// this fails.
NS_StackWalk(StackWalkCallback, kSkipFrames,
24, &aState, 0, nullptr);
#endif
}
/**
* PrintCycle
* Append to |aOut| detailed information about the circular
@ -85,6 +117,70 @@ PrintCycle(const BlockingResourceBase::DDT::ResourceAcquisitionArray* aCycle, ns
return maybeImminent;
}
#ifndef MOZ_CALLSTACK_DISABLED
class CodeAddressServiceWriter MOZ_FINAL
{
public:
explicit CodeAddressServiceWriter(nsACString& aOut) : mOut(aOut) {}
void Write(const char* aFmt, ...) const
{
va_list ap;
va_start(ap, aFmt);
const size_t kMaxLength = 4096;
char buffer[kMaxLength];
vsnprintf(buffer, kMaxLength, aFmt, ap);
mOut += buffer;
fprintf(stderr, "%s", buffer);
va_end(ap);
}
private:
nsACString& mOut;
};
struct CodeAddressServiceLock MOZ_FINAL
{
static void Unlock() { }
static void Lock() { }
static bool IsLocked() { return true; }
};
struct CodeAddressServiceStringAlloc MOZ_FINAL
{
static char* copy(const char* aString) { return ::strdup(aString); }
static void free(char* aString) { ::free(aString); }
};
class CodeAddressServiceStringTable MOZ_FINAL
{
public:
CodeAddressServiceStringTable() : mSet(32) {}
const char* Intern(const char* aString)
{
nsCharPtrHashKey* e = mSet.PutEntry(aString);
return e->GetKey();
}
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
return mSet.SizeOfExcludingThis(aMallocSizeOf);
}
private:
typedef nsTHashtable<nsCharPtrHashKey> StringSet;
StringSet mSet;
};
typedef CodeAddressService<CodeAddressServiceStringTable,
CodeAddressServiceStringAlloc,
CodeAddressServiceWriter,
CodeAddressServiceLock> WalkTheStackCodeAddressService;
#endif
bool
BlockingResourceBase::Print(nsACString& aOut) const
@ -95,15 +191,28 @@ BlockingResourceBase::Print(nsACString& aOut) const
aOut += " : ";
aOut += mName;
if (mAcquired) {
bool acquired = IsAcquired();
if (acquired) {
fputs(" (currently acquired)\n", stderr);
aOut += " (currently acquired)\n";
}
fputs(" calling context\n", stderr);
#ifdef MOZ_CALLSTACK_DISABLED
fputs(" [stack trace unavailable]\n", stderr);
#else
const AcquisitionState& state = acquired ? mAcquired : mFirstSeen;
return mAcquired;
WalkTheStackCodeAddressService addressService;
CodeAddressServiceWriter writer(aOut);
for (uint32_t i = 0; i < state.Length(); i++) {
addressService.WriteLocation(writer, state[i]);
}
#endif
return acquired;
}
@ -112,7 +221,11 @@ BlockingResourceBase::BlockingResourceBase(
BlockingResourceBase::BlockingResourceType aType)
: mName(aName)
, mType(aType)
#ifdef MOZ_CALLSTACK_DISABLED
, mAcquired(false)
#else
, mAcquired()
#endif
{
NS_ABORT_IF_FALSE(mName, "Name must be nonnull");
// PR_CallOnce guaranatees that InitStatics is called in a
@ -182,6 +295,11 @@ BlockingResourceBase::CheckAcquire()
return;
}
#ifndef MOZ_CALLSTACK_DISABLED
// Update the current stack before printing.
GetStackTrace(mAcquired);
#endif
fputs("###!!! ERROR: Potential deadlock detected:\n", stderr);
nsAutoCString out("Potential deadlock detected:\n");
bool maybeImminent = PrintCycle(cycle, out);
@ -211,11 +329,20 @@ BlockingResourceBase::Acquire()
"FIXME bug 456272: annots. to allow Acquire()ing condvars");
return;
}
NS_ASSERTION(!mAcquired,
NS_ASSERTION(!IsAcquired(),
"reacquiring already acquired resource");
ResourceChainAppend(ResourceChainFront());
#ifdef MOZ_CALLSTACK_DISABLED
mAcquired = true;
#else
// Take a stack snapshot.
GetStackTrace(mAcquired);
if (mFirstSeen.IsEmpty()) {
mFirstSeen = mAcquired;
}
#endif
}
@ -229,7 +356,7 @@ BlockingResourceBase::Release()
}
BlockingResourceBase* chainFront = ResourceChainFront();
NS_ASSERTION(chainFront && mAcquired,
NS_ASSERTION(chainFront && IsAcquired(),
"Release()ing something that hasn't been Acquire()ed");
if (chainFront == this) {
@ -255,7 +382,7 @@ BlockingResourceBase::Release()
}
}
mAcquired = false;
ClearAcquisitionState();
}
@ -340,10 +467,10 @@ ReentrantMonitor::Wait(PRIntervalTime aInterval)
// save monitor state and reset it to empty
int32_t savedEntryCount = mEntryCount;
bool savedAcquisitionState = GetAcquisitionState();
AcquisitionState savedAcquisitionState = GetAcquisitionState();
BlockingResourceBase* savedChainPrev = mChainPrev;
mEntryCount = 0;
SetAcquisitionState(false);
ClearAcquisitionState();
mChainPrev = 0;
nsresult rv;
@ -377,9 +504,9 @@ CondVar::Wait(PRIntervalTime aInterval)
AssertCurrentThreadOwnsMutex();
// save mutex state and reset to empty
bool savedAcquisitionState = mLock->GetAcquisitionState();
AcquisitionState savedAcquisitionState = mLock->GetAcquisitionState();
BlockingResourceBase* savedChainPrev = mLock->mChainPrev;
mLock->SetAcquisitionState(false);
mLock->ClearAcquisitionState();
mLock->mChainPrev = 0;
// give up mutex until we're back from Wait()

Просмотреть файл

@ -16,9 +16,18 @@
#include "nsISupportsImpl.h"
#ifdef DEBUG
// NB: Comment this out to enable callstack tracking.
#define MOZ_CALLSTACK_DISABLED
#include "prinit.h"
#include "nsStringGlue.h"
#ifndef MOZ_CALLSTACK_DISABLED
#include "nsTArray.h"
#endif
#include "nsXPCOM.h"
#endif
@ -88,6 +97,12 @@ public:
typedef DeadlockDetector<BlockingResourceBase> DDT;
protected:
#ifdef MOZ_CALLSTACK_DISABLED
typedef bool AcquisitionState;
#else
typedef nsAutoTArray<void*, 24> AcquisitionState;
#endif
/**
* BlockingResourceBase
* Initialize this blocking resource. Also hooks the resource into
@ -184,7 +199,7 @@ protected:
*
* *NOT* thread safe. Requires ownership of underlying resource.
*/
bool GetAcquisitionState()
AcquisitionState GetAcquisitionState()
{
return mAcquired;
}
@ -195,11 +210,41 @@ protected:
*
* *NOT* thread safe. Requires ownership of underlying resource.
*/
void SetAcquisitionState(bool aAcquisitionState)
void SetAcquisitionState(const AcquisitionState& aAcquisitionState)
{
mAcquired = aAcquisitionState;
}
/**
* ClearAcquisitionState
* Indicate this resource is not acquired.
*
* *NOT* thread safe. Requires ownership of underlying resource.
*/
void ClearAcquisitionState()
{
#ifdef MOZ_CALLSTACK_DISABLED
mAcquired = false;
#else
mAcquired.Clear();
#endif
}
/**
* IsAcquired
* Indicates if this resource is acquired.
*
* *NOT* thread safe. Requires ownership of underlying resource.
*/
bool IsAcquired() const
{
#ifdef MOZ_CALLSTACK_DISABLED
return mAcquired;
#else
return !mAcquired.IsEmpty();
#endif
}
/**
* mChainPrev
* A series of resource acquisitions creates a chain of orders. This
@ -227,7 +272,15 @@ private:
* mAcquired
* Indicates if this resource is currently acquired.
*/
bool mAcquired;
AcquisitionState mAcquired;
#ifndef MOZ_CALLSTACK_DISABLED
/**
* mFirstSeen
* Inidicates where this resource was first acquired.
*/
AcquisitionState mFirstSeen;
#endif
/**
* sCallOnce
@ -266,6 +319,9 @@ private:
*/
static void Shutdown();
static void StackWalkCallback(void* aPc, void* aSp, void* aClosure);
static void GetStackTrace(AcquisitionState& aState);
# ifdef MOZILLA_INTERNAL_API
// so it can call BlockingResourceBase::Shutdown()
friend void LogTerm();

Просмотреть файл

@ -605,7 +605,10 @@ ThreadStackHelper::FillStackBuffer()
}
#endif
const char* const label = entry->label();
if (mStackToFill->IsSameAsEntry(prevLabel, label)) {
if (mStackToFill->IsSameAsEntry(prevLabel, label) ||
!strcmp(label, "js::RunScript")) {
// Avoid duplicate labels to save space in the stack.
// Avoid js::RunScript labels because we save actual JS frames above.
continue;
}
mStackToFill->infallibleAppend(label);