mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1173889 - Strongly type the CallbackTracer dispatch function; r=jonco, r=mccr8
This commit is contained in:
parent
631dcc42a9
commit
975243fe86
@ -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.
|
||||
}
|
||||
|
@ -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
52
js/public/TraceKind.h
Normal 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
|
@ -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_;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user