Bug 1173889 - Strongly type the CallbackTracer dispatch function; r=jonco, r=mccr8

This commit is contained in:
Terrence Cole 2015-06-11 10:03:33 -07:00
parent 631dcc42a9
commit 975243fe86
17 changed files with 194 additions and 157 deletions

View File

@ -534,7 +534,7 @@ struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
: JS::CallbackTracer(rt), ok(false)
{}
void trace(void** thingp, JS::TraceKind kind) override {
void onChild(const JS::GCCellPtr&) override {
// We don't do anything here, we only want to verify that
// TraceProtoAndIfaceCache was called.
}

View File

@ -9,7 +9,9 @@
#include <limits.h>
#include "js/TracingAPI.h"
#include "jspubtd.h"
#include "js/TraceKind.h"
#include "js/Utility.h"
/* These values are private to the JS engine. */
@ -165,6 +167,7 @@ class JS_FRIEND_API(GCCellPtr)
explicit GCCellPtr(JSFunction* fun) : ptr(checkedCast(fun, JS::TraceKind::Object)) { }
explicit GCCellPtr(JSString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { }
explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { }
explicit GCCellPtr(JS::Symbol* sym) : ptr(checkedCast(sym, JS::TraceKind::Symbol)) { }
explicit GCCellPtr(JSScript* script) : ptr(checkedCast(script, JS::TraceKind::Script)) { }
explicit GCCellPtr(const Value& v);

52
js/public/TraceKind.h Normal file
View File

@ -0,0 +1,52 @@
/* -*- 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/. */
#ifndef js_TraceKind_h
#define js_TraceKind_h
namespace JS {
// When tracing a thing, the GC needs to know about the layout of the object it
// is looking at. There are a fixed number of different layouts that the GC
// knows about. The "trace kind" is a static map which tells which layout a GC
// thing has.
//
// Although this map is public, the details are completely hidden. Not all of
// the matching C++ types are exposed, and those that are, are opaque.
//
// See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
enum class TraceKind
{
// These trace kinds have a publicly exposed, although opaque, C++ type.
// Note: The order here is determined by our Value packing. Other users
// should sort alphabetically, for consistency.
Object = 0x00,
String = 0x01,
Symbol = 0x02,
Script = 0x03,
// Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
Shape = 0x04,
// ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
ObjectGroup = 0x05,
// The kind associated with a nullptr.
Null = 0x06,
// The following kinds do not have an exposed C++ idiom.
BaseShape = 0x0F,
JitCode = 0x1F,
LazyScript = 0x2F
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
} // namespace JS
#endif // js_TraceKind_h

View File

@ -8,9 +8,10 @@
#define js_TracingAPI_h
#include "jsalloc.h"
#include "jspubtd.h"
#include "js/HashTable.h"
#include "js/HeapAPI.h"
#include "js/TraceKind.h"
class JS_PUBLIC_API(JSTracer);
@ -19,66 +20,20 @@ class JS_PUBLIC_API(CallbackTracer);
template <typename T> class Heap;
template <typename T> class TenuredHeap;
// When tracing a thing, the GC needs to know about the layout of the object it
// is looking at. There are a fixed number of different layouts that the GC
// knows about. The "trace kind" is a static map which tells which layout a GC
// thing has.
//
// Although this map is public, the details are completely hidden. Not all of
// the matching C++ types are exposed, and those that are, are opaque.
//
// See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
enum class TraceKind
{
// These trace kinds have a publicly exposed, although opaque, C++ type.
// Note: The order here is determined by our Value packing. Other users
// should sort alphabetically, for consistency.
Object = 0x00,
String = 0x01,
Symbol = 0x02,
Script = 0x03,
// Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
Shape = 0x04,
// ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
ObjectGroup = 0x05,
// The kind associated with a nullptr.
Null = 0x06,
// The following kinds do not have an exposed C++ idiom.
BaseShape = 0x0F,
JitCode = 0x1F,
LazyScript = 0x2F
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
// Returns a static string equivalent of |kind|.
JS_FRIEND_API(const char*)
GCTraceKindToAscii(JS::TraceKind kind);
} // namespace JS
// Tracer callback, called for each traceable thing directly referenced by a
// particular object or runtime structure. It is the callback responsibility
// to ensure the traversal of the full object graph via calling eventually
// JS_TraceChildren on the passed thing. In this case the callback must be
// prepared to deal with cycles in the traversal graph.
//
// kind argument is one of JS::TraceKind::Object, JS::TraceKind::String or a
// tag denoting internal implementation-specific traversal kind. In the latter
// case the only operations on thing that the callback can do is to call
// JS_TraceChildren or JS_GetTraceThingInfo.
//
// If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all
// of its mappings. This should be used in cases where the tracer
// wants to use the existing liveness of entries.
typedef void
(* JSTraceCallback)(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind);
namespace js {
class BaseShape;
class LazyScript;
class ObjectGroup;
namespace jit {
class JitCode;
} // namespace jit
} // namespace js
enum WeakMapTraceKind {
DoNotTraceWeakMaps = 0,
@ -132,8 +87,34 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr)
{}
// Override this method to receive notification when an edge is visited.
virtual void trace(void** thing, JS::TraceKind kind) = 0;
// Override these methods to receive notification when an edge is visited
// with the type contained in the callback. The default implementation
// dispatches to the fully-generic onChild implementation, so for cases that
// do not care about boxing overhead and do not need the actual edges,
// just override the generic onChild.
virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
virtual void onShapeEdge(js::Shape** shapep) {
onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
}
virtual void onObjectGroupEdge(js::ObjectGroup** groupp) {
onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup));
}
virtual void onBaseShapeEdge(js::BaseShape** basep) {
onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape));
}
virtual void onJitCodeEdge(js::jit::JitCode** codep) {
onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode));
}
virtual void onLazyScriptEdge(js::LazyScript** lazyp) {
onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript));
}
// Override this method to receive notification when a node in the GC
// heap graph is visited.
virtual void onChild(const JS::GCCellPtr& thing) = 0;
// Access to the tracing context:
// When tracing with a JS::CallbackTracer, we invoke the callback with the
@ -185,6 +166,21 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; }
#endif
// In C++, overriding a method hides all methods in the base class with
// that name, not just methods with that signature. Thus, the typed edge
// methods have to have distinct names to allow us to override them
// individually, which is freqently useful if, for example, we only want to
// process only one type of edge.
void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }
void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); }
void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); }
void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); }
private:
friend class AutoTracingName;
const char* contextName_;

View File

@ -331,7 +331,7 @@ class Node {
// JS::ubi::Node are both essentially tagged references to other sorts of
// objects, so letting conversions happen automatically is appropriate.
MOZ_IMPLICIT Node(JS::HandleValue value);
Node(JS::TraceKind kind, void* ptr);
explicit Node(const JS::GCCellPtr& thing);
// copy construction and copy assignment just use memcpy, since we know
// instances contain nothing but a vtable pointer and a data pointer.

View File

@ -808,8 +808,8 @@ class HasChildTracer : public JS::CallbackTracer
RootedValue child_;
bool found_;
void trace(void** thingp, JS::TraceKind kind) {
if (*thingp == child_.toGCThing())
void onChild(const JS::GCCellPtr& thing) override {
if (thing.asCell() == child_.toGCThing())
found_ = true;
}

View File

@ -138,9 +138,15 @@ void
CheckHashTablesAfterMovingGC(JSRuntime* rt);
#endif
struct MovingTracer : JS::CallbackTracer {
struct MovingTracer : JS::CallbackTracer
{
explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
void trace(void** thingp, JS::TraceKind kind) override;
void onObjectEdge(JSObject** objp) override;
void onChild(const JS::GCCellPtr& thing) override {
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
}
#ifdef DEBUG
TracerKind getTracerKind() const override { return TracerKind::Moving; }
#endif

View File

@ -2278,9 +2278,9 @@ TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name)
#ifdef DEBUG
struct AssertNonGrayTracer : public JS::CallbackTracer {
explicit AssertNonGrayTracer(JSRuntime* rt) : JS::CallbackTracer(rt) {}
void trace(void** thingp, JS::TraceKind kind) override {
DebugOnly<Cell*> thing(static_cast<Cell*>(*thingp));
MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY));
void onChild(const JS::GCCellPtr& thing) override {
MOZ_ASSERT_IF(thing.asCell()->isTenured(),
!thing.asCell()->asTenured().isMarked(js::gc::GRAY));
}
};
#endif
@ -2305,7 +2305,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
unmarkedAny(false)
{}
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
/* True iff we are tracing the immediate children of a shape. */
bool tracingShape;
@ -2348,7 +2348,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer
* containers.
*/
void
UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind)
UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing)
{
int stackDummy;
if (!JS_CHECK_STACK_SIZE(runtime()->mainThread.nativeStackLimit[StackForSystemCode],
@ -2362,14 +2362,14 @@ UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind)
return;
}
Cell* cell = static_cast<Cell*>(*thingp);
Cell* cell = thing.asCell();
// Cells in the nursery cannot be gray, and therefore must necessarily point
// to only black edges.
if (!cell->isTenured()) {
#ifdef DEBUG
AssertNonGrayTracer nongray(runtime());
TraceChildren(&nongray, cell, kind);
TraceChildren(&nongray, cell, thing.kind());
#endif
return;
}
@ -2386,16 +2386,16 @@ UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind)
// The parent will later trace |tenured|. This is done to avoid increasing
// the stack depth during shape tracing. It is safe to do because a shape
// can only have one child that is a shape.
UnmarkGrayTracer childTracer(this, kind == JS::TraceKind::Shape);
UnmarkGrayTracer childTracer(this, thing.kind() == JS::TraceKind::Shape);
if (kind != JS::TraceKind::Shape) {
TraceChildren(&childTracer, &tenured, kind);
if (thing.kind() != JS::TraceKind::Shape) {
TraceChildren(&childTracer, &tenured, thing.kind());
MOZ_ASSERT(!childTracer.previousShape);
unmarkedAny |= childTracer.unmarkedAny;
return;
}
MOZ_ASSERT(kind == JS::TraceKind::Shape);
MOZ_ASSERT(thing.kind() == JS::TraceKind::Shape);
Shape* shape = static_cast<Shape*>(&tenured);
if (tracingShape) {
MOZ_ASSERT(!previousShape);

View File

@ -552,7 +552,7 @@ class BufferGrayRootsTracer : public JS::CallbackTracer
// Set to false if we OOM while buffering gray roots.
bool bufferingGrayRootsFailed;
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
public:
explicit BufferGrayRootsTracer(JSRuntime* rt)
@ -605,24 +605,24 @@ struct SetMaybeAliveFunctor {
};
void
BufferGrayRootsTracer::trace(void** thingp, JS::TraceKind kind)
BufferGrayRootsTracer::onChild(const JS::GCCellPtr& thing)
{
MOZ_ASSERT(runtime()->isHeapBusy());
if (bufferingGrayRootsFailed)
return;
gc::TenuredCell* thing = gc::TenuredCell::fromPointer(*thingp);
gc::TenuredCell* tenured = gc::TenuredCell::fromPointer(thing.asCell());
Zone* zone = thing->zone();
Zone* zone = tenured->zone();
if (zone->isCollecting()) {
// See the comment on SetMaybeAliveFlag to see why we only do this for
// objects and scripts. We rely on gray root buffering for this to work,
// but we only need to worry about uncollected dead compartments during
// incremental GCs (when we do gray root buffering).
CallTyped(SetMaybeAliveFunctor(), thing, kind);
CallTyped(SetMaybeAliveFunctor(), tenured, thing.kind());
if (!zone->gcGrayRoots.append(thing))
if (!zone->gcGrayRoots.append(tenured))
bufferingGrayRootsFailed = true;
}
}

View File

@ -46,9 +46,8 @@ T
DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name)
{
CheckTracedThing(trc, *thingp);
JS::TraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
JS::AutoTracingName ctx(trc, name);
trc->trace(reinterpret_cast<void**>(thingp), kind);
trc->dispatchToOnEdge(thingp);
return *thingp;
}
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \
@ -322,21 +321,19 @@ struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer
innerTracer(innerTracer)
{}
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
JS::CallbackTracer* innerTracer;
Vector<ObjectGroup*, 4, SystemAllocPolicy> seen, worklist;
};
void
ObjectGroupCycleCollectorTracer::trace(void** thingp, JS::TraceKind kind)
ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing)
{
JS::GCCellPtr thing(*thingp, kind);
if (thing.isObject() || thing.isScript()) {
// Invoke the inner cycle collector callback on this child. It will not
// recurse back into TraceChildren.
innerTracer->trace(thingp, kind);
innerTracer->onChild(thing);
return;
}

View File

@ -81,7 +81,7 @@ class js::VerifyPreTracer : public JS::CallbackTracer
{
JS::AutoDisableGenerationalGC noggc;
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
public:
/* The gcNumber when the verification began. */
@ -112,9 +112,9 @@ class js::VerifyPreTracer : public JS::CallbackTracer
* node.
*/
void
VerifyPreTracer::trace(void** thingp, JS::TraceKind kind)
VerifyPreTracer::onChild(const JS::GCCellPtr& thing)
{
MOZ_ASSERT(!IsInsideNursery(*reinterpret_cast<Cell**>(thingp)));
MOZ_ASSERT(!IsInsideNursery(thing.asCell()));
edgeptr += sizeof(EdgeValue);
if (edgeptr >= term) {
@ -125,8 +125,8 @@ VerifyPreTracer::trace(void** thingp, JS::TraceKind kind)
VerifyNode* node = curnode;
uint32_t i = node->count;
node->edges[i].thing = *thingp;
node->edges[i].kind = kind;
node->edges[i].thing = thing.asCell();
node->edges[i].kind = thing.kind();
node->edges[i].label = contextName();
node->count++;
}
@ -252,7 +252,7 @@ IsMarkedOrAllocated(TenuredCell* cell)
struct CheckEdgeTracer : public JS::CallbackTracer {
VerifyNode* node;
explicit CheckEdgeTracer(JSRuntime* rt) : JS::CallbackTracer(rt), node(nullptr) {}
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
};
static const uint32_t MAX_VERIFIER_EDGES = 1000;
@ -265,15 +265,15 @@ static const uint32_t MAX_VERIFIER_EDGES = 1000;
* been modified) must point to marked objects.
*/
void
CheckEdgeTracer::trace(void** thingp, JS::TraceKind kind)
CheckEdgeTracer::onChild(const JS::GCCellPtr& thing)
{
/* Avoid n^2 behavior. */
if (node->count > MAX_VERIFIER_EDGES)
return;
for (uint32_t i = 0; i < node->count; i++) {
if (node->edges[i].thing == *thingp) {
MOZ_ASSERT(node->edges[i].kind == kind);
if (node->edges[i].thing == thing.asCell()) {
MOZ_ASSERT(node->edges[i].kind == thing.kind());
node->edges[i].thing = nullptr;
return;
}

View File

@ -8,16 +8,16 @@
#include "jsapi-tests/tests.h"
class CCWTestTracer : public JS::CallbackTracer {
void trace(void** thingp, JS::TraceKind kind) {
void onChild(const JS::GCCellPtr& thing) override {
numberOfThingsTraced++;
printf("*thingp = %p\n", *thingp);
printf("*thingp = %p\n", thing.asCell());
printf("*expectedThingp = %p\n", *expectedThingp);
printf("kind = %d\n", static_cast<int>(kind));
printf("kind = %d\n", static_cast<int>(thing.kind()));
printf("expectedKind = %d\n", static_cast<int>(expectedKind));
if (*thingp != *expectedThingp || kind != expectedKind)
if (thing.asCell() != *expectedThingp || thing.kind() != expectedKind)
okay = false;
}

View File

@ -904,7 +904,7 @@ struct DumpHeapTracer : public JS::CallbackTracer, public WeakMapTracer
map, key.asCell(), kdelegate, value.asCell());
}
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
};
static char
@ -958,14 +958,14 @@ DumpHeapVisitCell(JSRuntime* rt, void* data, void* thing,
}
void
DumpHeapTracer::trace(void** thingp, JS::TraceKind kind)
DumpHeapTracer::onChild(const JS::GCCellPtr& thing)
{
if (gc::IsInsideNursery((js::gc::Cell*)*thingp))
if (gc::IsInsideNursery(thing.asCell()))
return;
char buffer[1024];
getTracingEdgeName(buffer, sizeof(buffer));
fprintf(output, "%s%p %c %s\n", prefix, *thingp, MarkDescriptor(*thingp), buffer);
fprintf(output, "%s%p %c %s\n", prefix, thing.asCell(), MarkDescriptor(thing.asCell()), buffer);
}
void

View File

@ -2207,19 +2207,10 @@ GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason, SliceBudget&
}
void
MovingTracer::trace(void** thingp, JS::TraceKind kind)
MovingTracer::onObjectEdge(JSObject** objp)
{
TenuredCell* thing = TenuredCell::fromPointer(*thingp);
// Currently we only relocate objects.
if (kind != JS::TraceKind::Object) {
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing));
return;
}
JSObject* obj = reinterpret_cast<JSObject*>(thing);
if (IsForwarded(obj))
*thingp = Forwarded(obj);
if (IsForwarded(*objp))
*objp = Forwarded(*objp);
}
void
@ -3677,7 +3668,7 @@ GCRuntime::shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime,
#ifdef DEBUG
class CompartmentCheckTracer : public JS::CallbackTracer
{
void trace(void** thingp, JS::TraceKind kind) override;
void onChild(const JS::GCCellPtr& thing) override;
public:
explicit CompartmentCheckTracer(JSRuntime* rt)
@ -3720,17 +3711,17 @@ struct MaybeCompartmentFunctor {
};
void
CompartmentCheckTracer::trace(void** thingp, JS::TraceKind kind)
CompartmentCheckTracer::onChild(const JS::GCCellPtr& thing)
{
TenuredCell* thing = TenuredCell::fromPointer(*thingp);
TenuredCell* tenured = TenuredCell::fromPointer(thing.asCell());
JSCompartment* comp = CallTyped(MaybeCompartmentFunctor(), thing, kind);
JSCompartment* comp = CallTyped(MaybeCompartmentFunctor(), tenured, thing.kind());
if (comp && compartment) {
MOZ_ASSERT(comp == compartment || runtime()->isAtomsCompartment(comp) ||
(srcKind == JS::TraceKind::Object &&
InCrossCompartmentMap(static_cast<JSObject*>(src), thing, kind)));
InCrossCompartmentMap(static_cast<JSObject*>(src), tenured, thing.kind())));
} else {
MOZ_ASSERT(thing->zone() == zone || thing->zone()->isAtomsZone());
MOZ_ASSERT(tenured->zone() == zone || tenured->zone()->isAtomsZone());
}
}

View File

@ -31,7 +31,7 @@ with Files('jit/**'):
for gcfile in ['jsgc*', 'devtools/rootAnalysis', 'devtools/gc-ubench', 'devtools/gctrace']:
with Files(gcfile):
BUG_COMPONENT = component_gc
for header in ('GCAPI.h', 'HeapAPI.h', 'RootingAPI.h', 'SliceBudget.h', 'TracingAPI.h', 'WeakMapPtr.h'):
for header in ('GCAPI.h', 'HeapAPI.h', 'RootingAPI.h', 'SliceBudget.h', 'TraceKind.h', 'TracingAPI.h', 'WeakMapPtr.h'):
with Files('../public/' + header):
BUG_COMPONENT = component_gc
@ -122,6 +122,7 @@ EXPORTS.js += [
'../public/RootingAPI.h',
'../public/SliceBudget.h',
'../public/StructuredClone.h',
'../public/TraceKind.h',
'../public/TracingAPI.h',
'../public/TrackedOptimizationInfo.h',
'../public/TypeDecls.h',

View File

@ -65,9 +65,9 @@ struct Node::ConstructFunctor : public js::BoolDefaultAdaptor<Value, false> {
template <typename T> bool operator()(T* t, Node* node) { node->construct(t); return true; }
};
Node::Node(JS::TraceKind kind, void* ptr)
Node::Node(const JS::GCCellPtr &thing)
{
js::gc::CallTyped(ConstructFunctor(), ptr, kind, this);
js::gc::CallTyped(ConstructFunctor(), thing.asCell(), thing.kind(), this);
}
Node::Node(HandleValue value)
@ -111,7 +111,7 @@ class SimpleEdgeVectorTracer : public JS::CallbackTracer {
// True if we should populate the edge's names.
bool wantNames;
void trace(void** thingp, JS::TraceKind kind) {
void onChild(const JS::GCCellPtr& thing) override {
if (!okay)
return;
@ -139,7 +139,7 @@ class SimpleEdgeVectorTracer : public JS::CallbackTracer {
// ownership of name; if the append succeeds, the vector element
// then takes ownership; if the append fails, then the temporary
// retains it, and its destructor will free it.
if (!vec->append(mozilla::Move(SimpleEdge(name16, Node(kind, *thingp))))) {
if (!vec->append(mozilla::Move(SimpleEdge(name16, Node(thing))))) {
okay = false;
return;
}

View File

@ -128,7 +128,7 @@ struct NoteWeakMapChildrenTracer : public JS::CallbackTracer
mKey(nullptr), mKeyDelegate(nullptr)
{
}
void trace(void** aThingp, JS::TraceKind aKind) override;
void onChild(const JS::GCCellPtr& aThing) override;
nsCycleCollectionNoteRootCallback& mCb;
bool mTracedAny;
JSObject* mMap;
@ -137,23 +137,21 @@ struct NoteWeakMapChildrenTracer : public JS::CallbackTracer
};
void
NoteWeakMapChildrenTracer::trace(void** aThingp, JS::TraceKind aKind)
NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing)
{
JS::GCCellPtr thing(*aThingp, aKind);
if (thing.isString()) {
if (aThing.isString()) {
return;
}
if (!JS::GCThingIsMarkedGray(thing) && !mCb.WantAllTraces()) {
if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) {
return;
}
if (AddToCCKind(thing.kind())) {
mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, thing);
if (AddToCCKind(aThing.kind())) {
mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing);
mTracedAny = true;
} else {
JS_TraceChildren(this, thing.asCell(), thing.kind());
JS_TraceChildren(this, aThing.asCell(), aThing.kind());
}
}
@ -359,15 +357,15 @@ struct TraversalTracer : public JS::CallbackTracer
: JS::CallbackTracer(aRt, DoNotTraceWeakMaps), mCb(aCb)
{
}
void trace(void** aThingp, JS::TraceKind aTraceKind) override;
void onChild(const JS::GCCellPtr& aThing) override;
nsCycleCollectionTraversalCallback& mCb;
};
static void
NoteJSChild(TraversalTracer* aTrc, JS::GCCellPtr aThing)
void
TraversalTracer::onChild(const JS::GCCellPtr& aThing)
{
// Don't traverse non-gray objects, unless we want all traces.
if (!JS::GCThingIsMarkedGray(aThing) && !aTrc->mCb.WantAllTraces()) {
if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) {
return;
}
@ -379,42 +377,35 @@ NoteJSChild(TraversalTracer* aTrc, JS::GCCellPtr aThing)
* use special APIs to handle such chains iteratively.
*/
if (AddToCCKind(aThing.kind())) {
if (MOZ_UNLIKELY(aTrc->mCb.WantDebugInfo())) {
if (MOZ_UNLIKELY(mCb.WantDebugInfo())) {
char buffer[200];
aTrc->getTracingEdgeName(buffer, sizeof(buffer));
aTrc->mCb.NoteNextEdgeName(buffer);
getTracingEdgeName(buffer, sizeof(buffer));
mCb.NoteNextEdgeName(buffer);
}
if (aThing.isObject()) {
aTrc->mCb.NoteJSObject(aThing.toObject());
mCb.NoteJSObject(aThing.toObject());
} else {
aTrc->mCb.NoteJSScript(aThing.toScript());
mCb.NoteJSScript(aThing.toScript());
}
} else if (aThing.isShape()) {
// The maximum depth of traversal when tracing a Shape is unbounded, due to
// the parent pointers on the shape.
JS_TraceShapeCycleCollectorChildren(aTrc, aThing);
JS_TraceShapeCycleCollectorChildren(this, aThing);
} else if (aThing.isObjectGroup()) {
// The maximum depth of traversal when tracing an ObjectGroup is unbounded,
// due to information attached to the groups which can lead other groups to
// be traced.
JS_TraceObjectGroupCycleCollectorChildren(aTrc, aThing);
JS_TraceObjectGroupCycleCollectorChildren(this, aThing);
} else if (!aThing.isString()) {
JS_TraceChildren(aTrc, aThing.asCell(), aThing.kind());
JS_TraceChildren(this, aThing.asCell(), aThing.kind());
}
}
void
TraversalTracer::trace(void** aThingp, JS::TraceKind aTraceKind)
{
JS::GCCellPtr thing(*aThingp, aTraceKind);
NoteJSChild(this, thing);
}
static void
NoteJSChildGrayWrapperShim(void* aData, JS::GCCellPtr aThing)
{
TraversalTracer* trc = static_cast<TraversalTracer*>(aData);
NoteJSChild(trc, aThing);
trc->onChild(aThing);
}
/*