diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 142293152fd8..d94b97a9b128 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -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. } diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 61fdcfc026f6..8b6487b84d9a 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -9,7 +9,9 @@ #include -#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); diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h new file mode 100644 index 000000000000..272f577399eb --- /dev/null +++ b/js/public/TraceKind.h @@ -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 diff --git a/js/public/TracingAPI.h b/js/public/TracingAPI.h index 7a2ba8441e3f..af0182112e36 100644 --- a/js/public/TracingAPI.h +++ b/js/public/TracingAPI.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 class Heap; template 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_; diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 595badb21aee..3bda6e33e5c9 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -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. diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 9883f63486ee..ff0038358a7e 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -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; } diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index 7ba99885d3b3..0c07eace0195 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -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 diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 39134f362b30..1239671bbd29 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -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 thing(static_cast(*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(*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(&tenured); if (tracingShape) { MOZ_ASSERT(!previousShape); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index bb0681fc402b..7be17d2b755c 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -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; } } diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index de204785d502..4a4aeb8e72ea 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -46,9 +46,8 @@ T DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name) { CheckTracedThing(trc, *thingp); - JS::TraceKind kind = MapTypeToTraceKind::Type>::kind; JS::AutoTracingName ctx(trc, name); - trc->trace(reinterpret_cast(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 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; } diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index 0225d9c7f871..363c666133de 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -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(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; } diff --git a/js/src/jsapi-tests/testGCMarking.cpp b/js/src/jsapi-tests/testGCMarking.cpp index 980ee09391fd..fd3eea1449f8 100644 --- a/js/src/jsapi-tests/testGCMarking.cpp +++ b/js/src/jsapi-tests/testGCMarking.cpp @@ -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(kind)); + printf("kind = %d\n", static_cast(thing.kind())); printf("expectedKind = %d\n", static_cast(expectedKind)); - if (*thingp != *expectedThingp || kind != expectedKind) + if (thing.asCell() != *expectedThingp || thing.kind() != expectedKind) okay = false; } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 32b36d43b15a..cd625e1edd3e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -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 diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index eafd362940f3..971b65ca9923 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -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(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(src), thing, kind))); + InCrossCompartmentMap(static_cast(src), tenured, thing.kind()))); } else { - MOZ_ASSERT(thing->zone() == zone || thing->zone()->isAtomsZone()); + MOZ_ASSERT(tenured->zone() == zone || tenured->zone()->isAtomsZone()); } } diff --git a/js/src/moz.build b/js/src/moz.build index d7c93b679419..ff0efa4ae8e3 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -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', diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 53efbc41eea8..c2d25e55b42f 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -65,9 +65,9 @@ struct Node::ConstructFunctor : public js::BoolDefaultAdaptor { template 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; } diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 57aeb51b45fc..00d8f10b52b3 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -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(aData); - NoteJSChild(trc, aThing); + trc->onChild(aThing); } /*