Bug 1254376 - Add a read barrier to the global's debugger vector r=jimb

This commit is contained in:
Jon Coppeard 2016-03-18 10:14:30 +00:00
Родитель e8da73b559
Коммит 7ed132a5e3
7 изменённых файлов: 30 добавлений и 51 удалений

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

@ -23,21 +23,6 @@ namespace js {
#ifdef DEBUG
template <typename T>
void
BarrieredBase<T>::assertTypeConstraints() const
{
static_assert(mozilla::IsBaseOf<gc::Cell, typename mozilla::RemovePointer<T>::Type>::value ||
mozilla::IsSame<JS::Value, T>::value ||
mozilla::IsSame<jsid, T>::value ||
mozilla::IsSame<TaggedProto, T>::value,
"ensure only supported types are instantiated with barriers");
}
#define INSTANTIATE_ALL_VALID_TYPES(type) \
template void BarrieredBase<type>::assertTypeConstraints() const;
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TYPES)
#undef INSTANTIATE_ALL_VALID_TYPES
bool
HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot)
{

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

@ -173,6 +173,11 @@
* Barriers designed to be used externally are provided in js/RootingAPI.h.
* These external barriers call into the same post-barrier implementations at
* InternalBarrierMethods<T>::post via an indirect call to Heap(.+)Barrier.
*
* These clases are designed to be used to wrap GC thing pointers or values that
* act like them (i.e. JS::Value and jsid). It is possible to use them for
* other types by supplying the necessary barrier implementations but this
* is not usually necessary and should be done with caution.
*/
class JSAtom;
@ -322,11 +327,7 @@ class BarrieredBase : public BarrieredBaseMixins<T>
{
protected:
// BarrieredBase is not directly instantiable.
explicit BarrieredBase(T v) : value(v) {
#ifdef DEBUG
assertTypeConstraints();
#endif
}
explicit BarrieredBase(T v) : value(v) {}
// Storage for all barrier classes. |value| must be a GC thing reference
// type: either a direct pointer to a GC thing or a supported tagged
@ -339,13 +340,6 @@ class BarrieredBase : public BarrieredBaseMixins<T>
// Friending to the generic template leads to a number of unintended consequences, including
// template resolution ambiguity and a circular dependency with Tracing.h.
T* unsafeUnbarrieredForTracing() { return &value; }
private:
#ifdef DEBUG
// Static type assertions about T must be moved out of line to avoid
// circular dependencies between Barrier classes and GC memory definitions.
void assertTypeConstraints() const;
#endif
};
// Base class for barriered pointer types that intercept only writes.

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

@ -1015,7 +1015,7 @@ JSCompartment::updateDebuggerObservesFlag(unsigned flag)
? unsafeUnbarrieredMaybeGlobal()
: maybeGlobal();
const GlobalObject::DebuggerVector* v = global->getDebuggers();
for (Debugger * const* p = v->begin(); p != v->end(); p++) {
for (auto p = v->begin(); p != v->end(); p++) {
Debugger* dbg = *p;
if (flag == DebuggerObservesAllExecution ? dbg->observesAllExecution() :
flag == DebuggerObservesCoverage ? dbg->observesCoverage() :

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

@ -646,7 +646,7 @@ Debugger::getScriptFrameWithIter(JSContext* cx, AbstractFramePtr frame,
Debugger::hasLiveHook(GlobalObject* global, Hook which)
{
if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
for (Debugger** p = debuggers->begin(); p != debuggers->end(); p++) {
for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
Debugger* dbg = *p;
if (dbg->enabled && dbg->getHook(which))
return true;
@ -1572,7 +1572,7 @@ Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFu
AutoValueVector triggered(cx);
Handle<GlobalObject*> global = cx->global();
if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
for (Debugger** p = debuggers->begin(); p != debuggers->end(); p++) {
for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
Debugger* dbg = *p;
if (dbg->enabled && hookIsEnabled(dbg)) {
if (!triggered.append(ObjectValue(*dbg->toJSObject())))
@ -1753,7 +1753,7 @@ Debugger::onSingleStep(JSContext* cx, MutableHandleValue vp)
JSScript* trappingScript = iter.script();
GlobalObject* global = cx->global();
if (GlobalObject::DebuggerVector* debuggers = global->getDebuggers()) {
for (Debugger** p = debuggers->begin(); p != debuggers->end(); p++) {
for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
Debugger* dbg = *p;
for (FrameMap::Range r = dbg->frames.all(); !r.empty(); r.popFront()) {
AbstractFramePtr frame = r.front().key();
@ -1890,7 +1890,7 @@ Debugger::slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj, HandleSav
double when, GlobalObject::DebuggerVector& dbgs)
{
MOZ_ASSERT(!dbgs.empty());
mozilla::DebugOnly<Debugger**> begin = dbgs.begin();
mozilla::DebugOnly<ReadBarriered<Debugger*>*> begin = dbgs.begin();
// Root all the Debuggers while we're iterating over them;
// appendAllocationSite calls JSCompartment::wrap, and thus can GC.
@ -1900,17 +1900,12 @@ Debugger::slowPathOnLogAllocationSite(JSContext* cx, HandleObject obj, HandleSav
// Handle), but in this case, we're iterating over a global's list of
// Debuggers, and globals only hold their Debuggers weakly.
Rooted<GCVector<JSObject*>> activeDebuggers(cx, GCVector<JSObject*>(cx));
for (Debugger** dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) {
// Since we're pulling these Debugger objects out of the GlobalObject's
// debugger array, which holds them only weakly, we need to let the
// incremental GC know that a possibly previously unreachable Debugger
// object just became reachable.
InternalBarrierMethods<JSObject*>::readBarrier((*dbgp)->object);
for (auto dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) {
if (!activeDebuggers.append((*dbgp)->object))
return false;
}
for (Debugger** dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) {
for (auto dbgp = dbgs.begin(); dbgp < dbgs.end(); dbgp++) {
// The set of debuggers had better not change while we're iterating,
// such that the vector gets reallocated.
MOZ_ASSERT(dbgs.begin() == begin);
@ -2517,8 +2512,7 @@ Debugger::cannotTrackAllocations(const GlobalObject& global)
Debugger::isObservedByDebuggerTrackingAllocations(const GlobalObject& debuggee)
{
if (auto* v = debuggee.getDebuggers()) {
Debugger** p;
for (p = v->begin(); p != v->end(); p++) {
for (auto p = v->begin(); p != v->end(); p++) {
if ((*p)->trackingAllocationSites && (*p)->enabled) {
return true;
}
@ -2686,7 +2680,7 @@ Debugger::markAllIteratively(GCMarker* trc)
*/
const GlobalObject::DebuggerVector* debuggers = global->getDebuggers();
MOZ_ASSERT(debuggers);
for (Debugger * const* p = debuggers->begin(); p != debuggers->end(); p++) {
for (auto p = debuggers->begin(); p != debuggers->end(); p++) {
Debugger* dbg = *p;
/*
@ -3551,7 +3545,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
*/
if (c->isDebuggee()) {
GlobalObject::DebuggerVector* v = c->maybeGlobal()->getDebuggers();
for (Debugger** p = v->begin(); p != v->end(); p++) {
for (auto p = v->begin(); p != v->end(); p++) {
JSCompartment* next = (*p)->object->compartment();
if (Find(visited, next) == visited.end() && !visited.append(next))
return false;
@ -3659,11 +3653,11 @@ Debugger::recomputeDebuggeeZoneSet()
}
}
template<typename V>
static Debugger**
findDebuggerInVector(Debugger* dbg, V* vec)
template <typename T>
static T*
findDebuggerInVector(Debugger* dbg, Vector<T, 0, js::SystemAllocPolicy>* vec)
{
Debugger** p;
T* p;
for (p = vec->begin(); p != vec->end(); p++) {
if (*p == dbg)
break;

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

@ -345,6 +345,12 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
}
};
// Barrier methods so we can have ReadBarriered<Debugger*>.
static void readBarrier(Debugger* dbg) {
InternalBarrierMethods<JSObject*>::readBarrier(dbg->object);
}
static void writeBarrierPost(Debugger** vp, Debugger* prev, Debugger* next) {}
private:
HeapPtrNativeObject object; /* The Debugger object. Strong reference. */
WeakGlobalObjectSet debuggees; /* Debuggee globals. Cross-compartment weak references. */
@ -353,7 +359,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
bool enabled;
bool allowUnobservedAsmJS;
// Wether to enable code coverage on the Debuggee.
// Whether to enable code coverage on the Debuggee.
bool collectCoverageInfo;
JSCList breakpoints; /* Circular list of all js::Breakpoints in this debugger */

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

@ -745,7 +745,7 @@ class GlobalObject : public NativeObject
static bool initSelfHostingBuiltins(JSContext* cx, Handle<GlobalObject*> global,
const JSFunctionSpec* builtins);
typedef js::Vector<js::Debugger*, 0, js::SystemAllocPolicy> DebuggerVector;
typedef js::Vector<js::ReadBarriered<js::Debugger*>, 0, js::SystemAllocPolicy> DebuggerVector;
/*
* The collection of Debugger objects debugging this global. If this global

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

@ -1385,11 +1385,11 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
if (!dbgs || dbgs->empty())
return;
mozilla::DebugOnly<Debugger**> begin = dbgs->begin();
mozilla::DebugOnly<ReadBarriered<Debugger*>*> begin = dbgs->begin();
mozilla::DebugOnly<bool> foundAnyDebuggers = false;
double probability = 0;
for (Debugger** dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
for (auto dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
// The set of debuggers had better not change while we're iterating,
// such that the vector gets reallocated.
MOZ_ASSERT(dbgs->begin() == begin);