mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +00:00
Bug 1464387 - Don't instantiate so many trace functions r=sfink
This commit is contained in:
parent
de4b4b8e83
commit
a253acb336
@ -82,9 +82,9 @@ using mozilla::PodCopy;
|
||||
// |TraceEdge| |TraceRoot| |TraceManuallyBarrieredEdge| ... |TraceRange| ... etc. //
|
||||
// '---------' '---------' '--------------------------' '----------' //
|
||||
// \ \ / / //
|
||||
// \ \ .----------------. / / //
|
||||
// o------------->o-|DispatchToTracer|-o<-----------------------o //
|
||||
// '----------------' //
|
||||
// \ \ .-----------------. / / //
|
||||
// o------------->o-|TraceEdgeInternal|-o<----------------------o //
|
||||
// '-----------------' //
|
||||
// / \ //
|
||||
// / \ //
|
||||
// .---------. .----------. .-----------------. //
|
||||
@ -372,162 +372,38 @@ AssertShouldMarkInZone(JS::Symbol* sym)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
AssertRootMarkingPhase(JSTracer* trc)
|
||||
#ifdef DEBUG
|
||||
void
|
||||
js::gc::AssertRootMarkingPhase(JSTracer* trc)
|
||||
{
|
||||
MOZ_ASSERT_IF(trc->isMarkingTracer(),
|
||||
trc->runtime()->gc.state() == State::NotActive ||
|
||||
trc->runtime()->gc.state() == State::MarkRoots);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*** Tracing Interface ***************************************************************************/
|
||||
|
||||
// The second parameter to BaseGCType is derived automatically based on T. The
|
||||
// relation here is that for any T, the TraceKind will automatically,
|
||||
// statically select the correct Cell layout for marking. Below, we instantiate
|
||||
// each override with a declaration of the most derived layout type.
|
||||
//
|
||||
// The use of TraceKind::Null for the case where the type is not matched
|
||||
// generates a compile error as no template instantiated for that kind.
|
||||
//
|
||||
// Usage:
|
||||
// BaseGCType<T>::type
|
||||
//
|
||||
// Examples:
|
||||
// BaseGCType<JSFunction>::type => JSObject
|
||||
// BaseGCType<UnownedBaseShape>::type => BaseShape
|
||||
// etc.
|
||||
template <typename T, JS::TraceKind =
|
||||
#define EXPAND_MATCH_TYPE(name, type, _) \
|
||||
IsBaseOf<type, T>::value ? JS::TraceKind::name :
|
||||
JS_FOR_EACH_TRACEKIND(EXPAND_MATCH_TYPE)
|
||||
#undef EXPAND_MATCH_TYPE
|
||||
JS::TraceKind::Null>
|
||||
|
||||
struct BaseGCType;
|
||||
#define IMPL_BASE_GC_TYPE(name, type_, _) \
|
||||
template <typename T> struct BaseGCType<T, JS::TraceKind:: name> { typedef type_ type; };
|
||||
JS_FOR_EACH_TRACEKIND(IMPL_BASE_GC_TYPE);
|
||||
#undef IMPL_BASE_GC_TYPE
|
||||
|
||||
// Our barrier templates are parameterized on the pointer types so that we can
|
||||
// share the definitions with Value and jsid. Thus, we need to strip the
|
||||
// pointer before sending the type to BaseGCType and re-add it on the other
|
||||
// side. As such:
|
||||
template <typename T> struct PtrBaseGCType { typedef T type; };
|
||||
template <typename T> struct PtrBaseGCType<T*> { typedef typename BaseGCType<T>::type* type; };
|
||||
|
||||
template <typename T>
|
||||
typename PtrBaseGCType<T>::type*
|
||||
ConvertToBase(T* thingp)
|
||||
{
|
||||
return reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
|
||||
}
|
||||
|
||||
template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name);
|
||||
template <typename T> T DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name);
|
||||
template <typename T> void DoMarking(GCMarker* gcmarker, T* thing);
|
||||
template <typename T> void DoMarking(GCMarker* gcmarker, const T& thing);
|
||||
template <typename T> void NoteWeakEdge(GCMarker* gcmarker, T** thingp);
|
||||
template <typename T> void NoteWeakEdge(GCMarker* gcmarker, T* thingp);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceEdge(JSTracer* trc, WriteBarrieredBase<T>* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceNullableEdge(JSTracer* trc, WriteBarrieredBase<T>* thingp, const char* name)
|
||||
{
|
||||
if (InternalBarrierMethods<T>::isMarkable(thingp->get()))
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceNullableEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
if (InternalBarrierMethods<T>::isMarkable(thingp->unbarrieredGet()))
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JS_PUBLIC_API(void)
|
||||
js::gc::TraceExternalEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
MOZ_ASSERT(InternalBarrierMethods<T>::isMarkable(*thingp));
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
TraceEdgeInternal(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JS_PUBLIC_API(void)
|
||||
js::UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceWeakEdge(JSTracer* trc, WeakRef<T>* thingp, const char* name)
|
||||
{
|
||||
if (!trc->isMarkingTracer()) {
|
||||
// Non-marking tracers can select whether or not they see weak edges.
|
||||
if (trc->traceWeakEdges())
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
|
||||
return;
|
||||
}
|
||||
|
||||
NoteWeakEdge(GCMarker::fromTracer(trc),
|
||||
ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
AssertRootMarkingPhase(trc);
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
TraceRoot(trc, thingp->unsafeGet(), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
AssertRootMarkingPhase(trc);
|
||||
if (InternalBarrierMethods<T>::isMarkable(*thingp))
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
TraceNullableRoot(trc, thingp->unsafeGet(), name);
|
||||
TraceEdgeInternal(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -538,48 +414,7 @@ JS::UnsafeTraceRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
js::TraceNullableRoot(trc, thingp, name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name)
|
||||
{
|
||||
JS::AutoTracingIndex index(trc);
|
||||
for (auto i : IntegerRange(len)) {
|
||||
if (InternalBarrierMethods<T>::isMarkable(vec[i].get()))
|
||||
DispatchToTracer(trc, ConvertToBase(vec[i].unsafeUnbarrieredForTracing()), name);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name)
|
||||
{
|
||||
AssertRootMarkingPhase(trc);
|
||||
JS::AutoTracingIndex index(trc);
|
||||
for (auto i : IntegerRange(len)) {
|
||||
if (InternalBarrierMethods<T>::isMarkable(vec[i]))
|
||||
DispatchToTracer(trc, ConvertToBase(&vec[i]), name);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate a copy of the Tracing templates for each derived type.
|
||||
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \
|
||||
template void js::TraceEdge<type>(JSTracer*, WriteBarrieredBase<type>*, const char*); \
|
||||
template void js::TraceEdge<type>(JSTracer*, ReadBarriered<type>*, const char*); \
|
||||
template void js::TraceNullableEdge<type>(JSTracer*, WriteBarrieredBase<type>*, const char*); \
|
||||
template void js::TraceNullableEdge<type>(JSTracer*, ReadBarriered<type>*, const char*); \
|
||||
template void js::TraceManuallyBarrieredEdge<type>(JSTracer*, type*, const char*); \
|
||||
template void js::TraceWeakEdge<type>(JSTracer*, WeakRef<type>*, const char*); \
|
||||
template void js::TraceRoot<type>(JSTracer*, type*, const char*); \
|
||||
template void js::TraceRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
|
||||
template void js::TraceNullableRoot<type>(JSTracer*, type*, const char*); \
|
||||
template void js::TraceNullableRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
|
||||
template void js::TraceRange<type>(JSTracer*, size_t, WriteBarrieredBase<type>*, const char*); \
|
||||
template void js::TraceRootRange<type>(JSTracer*, size_t, type*, const char*);
|
||||
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
|
||||
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
|
||||
|
||||
// Instantiate a copy of the Tracing templates for each public GC pointer type.
|
||||
#define INSTANTIATE_PUBLIC_TRACE_FUNCTIONS(type) \
|
||||
template JS_PUBLIC_API(void) JS::UnsafeTraceRoot<type>(JSTracer*, type*, const char*); \
|
||||
template JS_PUBLIC_API(void) js::UnsafeTraceManuallyBarrieredEdge<type>(JSTracer*, type*, \
|
||||
@ -589,29 +424,46 @@ FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
|
||||
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
|
||||
#undef INSTANTIATE_PUBLIC_TRACE_FUNCTIONS
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
#define INSTANTIATE_INTERNAL_TRACE_FUNCTIONS(type) \
|
||||
template void TraceEdgeInternal<type>(JSTracer*, type*, const char*); \
|
||||
template void TraceWeakEdgeInternal<type>(JSTracer*, type*, const char*); \
|
||||
template void TraceRangeInternal<type>(JSTracer*, size_t len, type*, const char*);
|
||||
|
||||
#define INSTANTIATE_INTERNAL_TRACE_FUNCTIONS_FROM_TRACEKIND(_1, type, _2) \
|
||||
INSTANTIATE_INTERNAL_TRACE_FUNCTIONS(type*)
|
||||
|
||||
JS_FOR_EACH_TRACEKIND(INSTANTIATE_INTERNAL_TRACE_FUNCTIONS_FROM_TRACEKIND)
|
||||
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_INTERNAL_TRACE_FUNCTIONS)
|
||||
|
||||
#undef INSTANTIATE_INTERNAL_TRACE_FUNCTIONS_FROM_TRACEKIND
|
||||
#undef INSTANTIATE_INTERNAL_TRACE_FUNCTIONS
|
||||
|
||||
} // namespace gc
|
||||
} // namespace js
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceManuallyBarrieredCrossCompartmentEdge(JSTracer* trc, JSObject* src, T* dst,
|
||||
const char* name)
|
||||
{
|
||||
if (ShouldTraceCrossCompartment(trc, src, *dst))
|
||||
DispatchToTracer(trc, dst, name);
|
||||
TraceEdgeInternal(trc, dst, name);
|
||||
}
|
||||
template void js::TraceManuallyBarrieredCrossCompartmentEdge<JSObject*>(JSTracer*, JSObject*,
|
||||
JSObject**, const char*);
|
||||
template void js::TraceManuallyBarrieredCrossCompartmentEdge<JSScript*>(JSTracer*, JSObject*,
|
||||
JSScript**, const char*);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, WriteBarrieredBase<T>* dst,
|
||||
js::TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, WriteBarrieredBase<Value>* dst,
|
||||
const char* name)
|
||||
{
|
||||
if (ShouldTraceCrossCompartment(trc, src, dst->get()))
|
||||
DispatchToTracer(trc, dst->unsafeUnbarrieredForTracing(), name);
|
||||
TraceEdgeInternal(trc, dst->unsafeUnbarrieredForTracing(), name);
|
||||
}
|
||||
template void js::TraceCrossCompartmentEdge<Value>(JSTracer*, JSObject*,
|
||||
WriteBarrieredBase<Value>*, const char*);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
@ -676,7 +528,7 @@ js::TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, Cell** thingp, const
|
||||
// a sufficiently smart C++ compiler may be able to devirtualize some paths.
|
||||
template <typename T>
|
||||
void
|
||||
DispatchToTracer(JSTracer* trc, T* thingp, const char* name)
|
||||
js::gc::TraceEdgeInternal(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
#define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame<type*, T>::value ||
|
||||
static_assert(
|
||||
@ -694,6 +546,32 @@ DispatchToTracer(JSTracer* trc, T* thingp, const char* name)
|
||||
DoCallback(trc->asCallbackTracer(), thingp, name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::gc::TraceWeakEdgeInternal(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
if (!trc->isMarkingTracer()) {
|
||||
// Non-marking tracers can select whether or not they see weak edges.
|
||||
if (trc->traceWeakEdges())
|
||||
TraceEdgeInternal(trc, thingp, name);
|
||||
return;
|
||||
}
|
||||
|
||||
NoteWeakEdge(GCMarker::fromTracer(trc), thingp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::gc::TraceRangeInternal(JSTracer* trc, size_t len, T* vec, const char* name)
|
||||
{
|
||||
JS::AutoTracingIndex index(trc);
|
||||
for (auto i : IntegerRange(len)) {
|
||||
if (InternalBarrierMethods<T>::isMarkable(vec[i]))
|
||||
TraceEdgeInternal(trc, &vec[i], name);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** GC Marking Interface *************************************************************************/
|
||||
|
||||
@ -3361,27 +3239,25 @@ IsMarkedInternalCommon(T* thingp)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool
|
||||
IsMarkedInternal(JSRuntime* rt, T** thingp)
|
||||
struct MightBeNurseryAllocated
|
||||
{
|
||||
static const bool value = mozilla::IsBaseOf<JSObject, T>::value ||
|
||||
mozilla::IsBaseOf<JSString, T>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
js::gc::IsMarkedInternal(JSRuntime* rt, T** thingp)
|
||||
{
|
||||
if (IsOwnedByOtherRuntime(rt, *thingp))
|
||||
return true;
|
||||
|
||||
return IsMarkedInternalCommon(thingp);
|
||||
}
|
||||
|
||||
template <>
|
||||
/* static */ bool
|
||||
IsMarkedInternal(JSRuntime* rt, JSObject** thingp)
|
||||
{
|
||||
if (IsOwnedByOtherRuntime(rt, *thingp))
|
||||
return true;
|
||||
|
||||
if (IsInsideNursery(*thingp)) {
|
||||
if (MightBeNurseryAllocated<T>::value && IsInsideNursery(*thingp)) {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
Cell** cellp = reinterpret_cast<Cell**>(thingp);
|
||||
return Nursery::getForwardedPointer(cellp);
|
||||
}
|
||||
|
||||
return IsMarkedInternalCommon(thingp);
|
||||
}
|
||||
|
||||
@ -3394,8 +3270,8 @@ struct IsMarkedFunctor : public IdentityDefaultAdaptor<S> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static bool
|
||||
IsMarkedInternal(JSRuntime* rt, T* thingp)
|
||||
bool
|
||||
js::gc::IsMarkedInternal(JSRuntime* rt, T* thingp)
|
||||
{
|
||||
bool rv = true;
|
||||
*thingp = DispatchTyped(IsMarkedFunctor<T>(), *thingp, rt, &rv);
|
||||
@ -3411,8 +3287,8 @@ js::gc::IsAboutToBeFinalizedDuringSweep(TenuredCell& tenured)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool
|
||||
IsAboutToBeFinalizedInternal(T** thingp)
|
||||
bool
|
||||
js::gc::IsAboutToBeFinalizedInternal(T** thingp)
|
||||
{
|
||||
CheckIsMarkedThing(thingp);
|
||||
T* thing = *thingp;
|
||||
@ -3447,8 +3323,8 @@ struct IsAboutToBeFinalizedInternalFunctor : public IdentityDefaultAdaptor<S> {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static bool
|
||||
IsAboutToBeFinalizedInternal(T* thingp)
|
||||
bool
|
||||
js::gc::IsAboutToBeFinalizedInternal(T* thingp)
|
||||
{
|
||||
bool rv = false;
|
||||
*thingp = DispatchTyped(IsAboutToBeFinalizedInternalFunctor<T>(), *thingp, &rv);
|
||||
@ -3458,41 +3334,6 @@ IsAboutToBeFinalizedInternal(T* thingp)
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsMarkedUnbarriered(JSRuntime* rt, T* thingp)
|
||||
{
|
||||
return IsMarkedInternal(rt, ConvertToBase(thingp));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsMarked(JSRuntime* rt, WriteBarrieredBase<T>* thingp)
|
||||
{
|
||||
return IsMarkedInternal(rt, ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsAboutToBeFinalizedUnbarriered(T* thingp)
|
||||
{
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsAboutToBeFinalized(WriteBarrieredBase<T>* thingp)
|
||||
{
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsAboutToBeFinalized(ReadBarrieredBase<T>* thingp)
|
||||
{
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JS_PUBLIC_API(bool)
|
||||
EdgeNeedsSweep(JS::Heap<T>* thingp)
|
||||
@ -3507,20 +3348,25 @@ EdgeNeedsSweepUnbarrieredSlow(T* thingp)
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp));
|
||||
}
|
||||
|
||||
// Instantiate a copy of the Tracing templates for each derived type.
|
||||
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \
|
||||
template bool IsMarkedUnbarriered<type>(JSRuntime*, type*); \
|
||||
template bool IsMarked<type>(JSRuntime*, WriteBarrieredBase<type>*); \
|
||||
template bool IsAboutToBeFinalizedUnbarriered<type>(type*); \
|
||||
template bool IsAboutToBeFinalized<type>(WriteBarrieredBase<type>*); \
|
||||
template bool IsAboutToBeFinalized<type>(ReadBarrieredBase<type>*);
|
||||
// Instantiate a copy of the Tracing templates for each public GC type.
|
||||
#define INSTANTIATE_ALL_VALID_HEAP_TRACE_FUNCTIONS(type) \
|
||||
template JS_PUBLIC_API(bool) EdgeNeedsSweep<type>(JS::Heap<type>*); \
|
||||
template JS_PUBLIC_API(bool) EdgeNeedsSweepUnbarrieredSlow<type>(type*);
|
||||
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
|
||||
FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_HEAP_TRACE_FUNCTIONS)
|
||||
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_HEAP_TRACE_FUNCTIONS)
|
||||
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
|
||||
|
||||
#define INSTANTIATE_INTERNAL_MARKING_FUNCTIONS(type) \
|
||||
template bool IsMarkedInternal(JSRuntime* rt, type* thing); \
|
||||
template bool IsAboutToBeFinalizedInternal(type* thingp);
|
||||
|
||||
#define INSTANTIATE_INTERNAL_MARKING_FUNCTIONS_FROM_TRACEKIND(_1, type, _2) \
|
||||
INSTANTIATE_INTERNAL_MARKING_FUNCTIONS(type*)
|
||||
|
||||
JS_FOR_EACH_TRACEKIND(INSTANTIATE_INTERNAL_MARKING_FUNCTIONS_FROM_TRACEKIND)
|
||||
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(INSTANTIATE_INTERNAL_MARKING_FUNCTIONS)
|
||||
|
||||
#undef INSTANTIATE_INTERNAL_MARKING_FUNCTIONS_FROM_TRACEKIND
|
||||
#undef INSTANTIATE_INTERNAL_MARKING_FUNCTIONS
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
@ -55,31 +55,66 @@ PushArena(GCMarker* gcmarker, Arena* arena);
|
||||
|
||||
/*** Liveness ***/
|
||||
|
||||
// Report whether a thing has been marked. Things which are in zones that are
|
||||
// not currently being collected or are owned by another runtime are always
|
||||
// reported as being marked.
|
||||
// The IsMarkedInternal and IsAboutToBeFinalizedInternal function templates are
|
||||
// used to implement the IsMarked and IsAboutToBeFinalized set of functions.
|
||||
// These internal functions are instantiated for the base GC types and should
|
||||
// not be called directly.
|
||||
//
|
||||
// Note that there are two function templates declared for each, not one
|
||||
// template and a specialization. This is necessary so that pointer arguments
|
||||
// (e.g. JSObject**) and tagged value arguments (e.g. JS::Value*) are routed to
|
||||
// separate implementations.
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsMarkedUnbarriered(JSRuntime* rt, T* thingp);
|
||||
bool IsMarkedInternal(JSRuntime* rt, T* thing);
|
||||
template <typename T>
|
||||
bool IsMarkedInternal(JSRuntime* rt, T** thing);
|
||||
|
||||
template <typename T>
|
||||
bool IsAboutToBeFinalizedInternal(T* thingp);
|
||||
template <typename T>
|
||||
bool IsAboutToBeFinalizedInternal(T** thingp);
|
||||
|
||||
// Report whether a thing has been marked. Things which are in zones that are
|
||||
// not currently being collected or are owned by another runtime are always
|
||||
// reported as being marked.
|
||||
template <typename T>
|
||||
bool
|
||||
IsMarked(JSRuntime* rt, WriteBarrieredBase<T>* thingp);
|
||||
inline bool
|
||||
IsMarkedUnbarriered(JSRuntime* rt, T* thingp)
|
||||
{
|
||||
return IsMarkedInternal(rt, ConvertToBase(thingp));
|
||||
}
|
||||
|
||||
// Report whether a thing has been marked. Things which are in zones that are
|
||||
// not currently being collected or are owned by another runtime are always
|
||||
// reported as being marked.
|
||||
template <typename T>
|
||||
inline bool
|
||||
IsMarked(JSRuntime* rt, WriteBarrieredBase<T>* thingp)
|
||||
{
|
||||
return IsMarkedInternal(rt, ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsAboutToBeFinalizedUnbarriered(T* thingp);
|
||||
inline bool
|
||||
IsAboutToBeFinalizedUnbarriered(T* thingp)
|
||||
{
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsAboutToBeFinalized(WriteBarrieredBase<T>* thingp);
|
||||
inline bool
|
||||
IsAboutToBeFinalized(WriteBarrieredBase<T>* thingp)
|
||||
{
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
IsAboutToBeFinalized(ReadBarrieredBase<T>* thingp);
|
||||
inline bool
|
||||
IsAboutToBeFinalized(ReadBarrieredBase<T>* thingp)
|
||||
{
|
||||
return IsAboutToBeFinalizedInternal(ConvertToBase(thingp->unsafeUnbarrieredForTracing()));
|
||||
}
|
||||
|
||||
bool
|
||||
IsAboutToBeFinalizedDuringSweep(TenuredCell& tenured);
|
||||
|
@ -14,107 +14,6 @@
|
||||
#include "gc/Marking.h"
|
||||
#include "js/GCPolicyAPI.h"
|
||||
|
||||
// Forward declare the types we're defining policies for. This file is
|
||||
// included in all places that define GC things, so the real definitions
|
||||
// will be available when we do template expansion, allowing for use of
|
||||
// static members in the underlying types. We cannot, however, use
|
||||
// static_assert to verify relations between types.
|
||||
class JSLinearString;
|
||||
namespace js {
|
||||
class AccessorShape;
|
||||
class ArgumentsObject;
|
||||
class ArrayBufferObject;
|
||||
class ArrayBufferObjectMaybeShared;
|
||||
class ArrayBufferViewObject;
|
||||
class ArrayObject;
|
||||
class BaseShape;
|
||||
class DebugEnvironmentProxy;
|
||||
class DebuggerFrame;
|
||||
class ExportEntryObject;
|
||||
class EnvironmentObject;
|
||||
class GlobalObject;
|
||||
class ImportEntryObject;
|
||||
class LazyScript;
|
||||
class LexicalEnvironmentObject;
|
||||
class ModuleEnvironmentObject;
|
||||
class ModuleNamespaceObject;
|
||||
class ModuleObject;
|
||||
class NativeObject;
|
||||
class ObjectGroup;
|
||||
class PlainObject;
|
||||
class PropertyName;
|
||||
class RegExpObject;
|
||||
class SavedFrame;
|
||||
class Scope;
|
||||
class EnvironmentObject;
|
||||
class RequestedModuleObject;
|
||||
class ScriptSourceObject;
|
||||
class Shape;
|
||||
class SharedArrayBufferObject;
|
||||
class StructTypeDescr;
|
||||
class UnownedBaseShape;
|
||||
class WasmGlobalObject;
|
||||
class WasmFunctionScope;
|
||||
class WasmMemoryObject;
|
||||
namespace jit {
|
||||
class JitCode;
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
// Expand the given macro D for each valid GC reference type.
|
||||
#define FOR_EACH_INTERNAL_GC_POINTER_TYPE(D) \
|
||||
D(JSFlatString*) \
|
||||
D(JSLinearString*) \
|
||||
D(js::AccessorShape*) \
|
||||
D(js::ArgumentsObject*) \
|
||||
D(js::ArrayBufferObject*) \
|
||||
D(js::ArrayBufferObjectMaybeShared*) \
|
||||
D(js::ArrayBufferViewObject*) \
|
||||
D(js::ArrayObject*) \
|
||||
D(js::BaseShape*) \
|
||||
D(js::DebugEnvironmentProxy*) \
|
||||
D(js::DebuggerFrame*) \
|
||||
D(js::ExportEntryObject*) \
|
||||
D(js::EnvironmentObject*) \
|
||||
D(js::GlobalObject*) \
|
||||
D(js::ImportEntryObject*) \
|
||||
D(js::LazyScript*) \
|
||||
D(js::LexicalEnvironmentObject*) \
|
||||
D(js::ModuleEnvironmentObject*) \
|
||||
D(js::ModuleNamespaceObject*) \
|
||||
D(js::ModuleObject*) \
|
||||
D(js::NativeObject*) \
|
||||
D(js::ObjectGroup*) \
|
||||
D(js::PlainObject*) \
|
||||
D(js::PropertyName*) \
|
||||
D(js::RegExpObject*) \
|
||||
D(js::RegExpShared*) \
|
||||
D(js::RequestedModuleObject*) \
|
||||
D(js::SavedFrame*) \
|
||||
D(js::Scope*) \
|
||||
D(js::ScriptSourceObject*) \
|
||||
D(js::Shape*) \
|
||||
D(js::SharedArrayBufferObject*) \
|
||||
D(js::StructTypeDescr*) \
|
||||
D(js::UnownedBaseShape*) \
|
||||
D(js::WasmFunctionScope*) \
|
||||
D(js::WasmInstanceObject*) \
|
||||
D(js::WasmMemoryObject*) \
|
||||
D(js::WasmTableObject*) \
|
||||
D(js::WasmGlobalObject*) \
|
||||
D(js::jit::JitCode*)
|
||||
|
||||
// Expand the given macro D for each internal tagged GC pointer type.
|
||||
#define FOR_EACH_INTERNAL_TAGGED_GC_POINTER_TYPE(D) \
|
||||
D(js::TaggedProto)
|
||||
|
||||
// Expand the macro D for every GC reference type that we know about.
|
||||
#define FOR_EACH_GC_POINTER_TYPE(D) \
|
||||
FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
|
||||
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(D) \
|
||||
FOR_EACH_INTERNAL_GC_POINTER_TYPE(D) \
|
||||
FOR_EACH_INTERNAL_TAGGED_GC_POINTER_TYPE(D)
|
||||
|
||||
namespace js {
|
||||
|
||||
// Define the GCPolicy for all internal pointers.
|
||||
|
@ -48,13 +48,27 @@ struct ConcreteTraceable {
|
||||
void trace(JSTracer*) {}
|
||||
};
|
||||
|
||||
template <typename T, TraceFunction<T> TraceFn = TraceNullableRoot>
|
||||
template <typename T>
|
||||
static inline void
|
||||
TraceStackOrPersistentRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
TraceNullableRoot(trc, thingp, name);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void
|
||||
TraceStackOrPersistentRoot(JSTracer* trc, ConcreteTraceable* thingp, const char* name)
|
||||
{
|
||||
js::DispatchWrapper<ConcreteTraceable>::TraceWrapped(trc, thingp, name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void
|
||||
TraceExactStackRootList(JSTracer* trc, JS::Rooted<void*>* rooter, const char* name)
|
||||
{
|
||||
while (rooter) {
|
||||
T* addr = reinterpret_cast<JS::Rooted<T>*>(rooter)->address();
|
||||
TraceFn(trc, addr, name);
|
||||
TraceStackOrPersistentRoot(trc, addr, name);
|
||||
rooter = rooter->previous();
|
||||
}
|
||||
}
|
||||
@ -68,8 +82,7 @@ JS_FOR_EACH_TRACEKIND(TRACE_ROOTS)
|
||||
#undef TRACE_ROOTS
|
||||
TraceExactStackRootList<jsid>(trc, stackRoots[JS::RootKind::Id], "exact-id");
|
||||
TraceExactStackRootList<Value>(trc, stackRoots[JS::RootKind::Value], "exact-value");
|
||||
TraceExactStackRootList<ConcreteTraceable,
|
||||
js::DispatchWrapper<ConcreteTraceable>::TraceWrapped>(
|
||||
TraceExactStackRootList<ConcreteTraceable>(
|
||||
trc, stackRoots[JS::RootKind::Traceable], "Traceable");
|
||||
}
|
||||
|
||||
@ -85,13 +98,13 @@ TraceExactStackRoots(JSContext* cx, JSTracer* trc)
|
||||
cx->traceStackRoots(trc);
|
||||
}
|
||||
|
||||
template <typename T, TraceFunction<T> TraceFn = TraceNullableRoot>
|
||||
template <typename T>
|
||||
static inline void
|
||||
TracePersistentRootedList(JSTracer* trc, mozilla::LinkedList<PersistentRooted<void*>>& list,
|
||||
const char* name)
|
||||
{
|
||||
for (PersistentRooted<void*>* r : list)
|
||||
TraceFn(trc, reinterpret_cast<PersistentRooted<T>*>(r)->address(), name);
|
||||
TraceStackOrPersistentRoot(trc, reinterpret_cast<PersistentRooted<T>*>(r)->address(), name);
|
||||
}
|
||||
|
||||
void
|
||||
@ -103,9 +116,8 @@ JS_FOR_EACH_TRACEKIND(TRACE_ROOTS)
|
||||
#undef TRACE_ROOTS
|
||||
TracePersistentRootedList<jsid>(trc, heapRoots.ref()[JS::RootKind::Id], "persistent-id");
|
||||
TracePersistentRootedList<Value>(trc, heapRoots.ref()[JS::RootKind::Value], "persistent-value");
|
||||
TracePersistentRootedList<ConcreteTraceable,
|
||||
js::DispatchWrapper<ConcreteTraceable>::TraceWrapped>(trc,
|
||||
heapRoots.ref()[JS::RootKind::Traceable], "persistent-traceable");
|
||||
TracePersistentRootedList<ConcreteTraceable>(
|
||||
trc, heapRoots.ref()[JS::RootKind::Traceable], "persistent-traceable");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -49,76 +49,175 @@ namespace js {
|
||||
// called "tracing" forever and changing it would be extremely difficult at
|
||||
// this point.
|
||||
|
||||
namespace gc {
|
||||
|
||||
// Map from all trace kinds to the base GC type.
|
||||
template <JS::TraceKind kind>
|
||||
struct MapTraceKindToType {};
|
||||
|
||||
#define DEFINE_TRACE_KIND_MAP(name, type, _) \
|
||||
template <> struct MapTraceKindToType<JS::TraceKind::name> { \
|
||||
using Type = type; \
|
||||
};
|
||||
JS_FOR_EACH_TRACEKIND(DEFINE_TRACE_KIND_MAP);
|
||||
#undef DEFINE_TRACE_KIND_MAP
|
||||
|
||||
// Map from a possibly-derived type to the base GC type.
|
||||
template <typename T>
|
||||
struct BaseGCType
|
||||
{
|
||||
using type = typename MapTraceKindToType<JS::MapTypeToTraceKind<T>::kind>::Type;
|
||||
static_assert(mozilla::IsBaseOf<type, T>::value, "Failed to find base type");
|
||||
};
|
||||
|
||||
// Our barrier templates are parameterized on the pointer types so that we can
|
||||
// share the definitions with Value and jsid. Thus, we need to strip the
|
||||
// pointer before sending the type to BaseGCType and re-add it on the other
|
||||
// side. As such:
|
||||
template <typename T> struct PtrBaseGCType { using type = T; };
|
||||
template <typename T> struct PtrBaseGCType<T*> { using type = typename BaseGCType<T>::type* ; };
|
||||
|
||||
// Cast a possibly-derived T** pointer to a base class pointer.
|
||||
template <typename T>
|
||||
typename PtrBaseGCType<T>::type*
|
||||
ConvertToBase(T* thingp)
|
||||
{
|
||||
return reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
|
||||
}
|
||||
|
||||
// Internal methods to trace edges.
|
||||
template <typename T> void TraceEdgeInternal(JSTracer* trc, T* thingp, const char* name);
|
||||
template <typename T> void TraceWeakEdgeInternal(JSTracer* trc, T* thingp, const char* name);
|
||||
template <typename T> void TraceRangeInternal(JSTracer* trc, size_t len, T* vec, const char* name);
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertRootMarkingPhase(JSTracer* trc);
|
||||
#else
|
||||
inline void AssertRootMarkingPhase(JSTracer* trc) {}
|
||||
#endif
|
||||
|
||||
} // namespace gc
|
||||
|
||||
// Trace through an edge in the live object graph on behalf of tracing. The
|
||||
// effect of tracing the edge depends on the JSTracer being used. For pointer
|
||||
// types, |*thingp| must not be null.
|
||||
template <typename T>
|
||||
void
|
||||
TraceEdge(JSTracer* trc, WriteBarrieredBase<T>* thingp, const char* name);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
|
||||
|
||||
// Trace through an edge in the live object graph on behalf of tracing.
|
||||
template <typename T>
|
||||
void
|
||||
TraceNullableEdge(JSTracer* trc, WriteBarrieredBase<T>* thingp, const char* name);
|
||||
inline void
|
||||
TraceEdge(JSTracer* trc, WriteBarrieredBase<T>* thingp, const char* name)
|
||||
{
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceNullableEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
|
||||
inline void
|
||||
TraceEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp->unsafeGet()), name);
|
||||
}
|
||||
|
||||
// Trace through a possibly-null edge in the live object graph on behalf of
|
||||
// tracing.
|
||||
|
||||
template <typename T>
|
||||
inline void
|
||||
TraceNullableEdge(JSTracer* trc, WriteBarrieredBase<T>* thingp, const char* name)
|
||||
{
|
||||
if (InternalBarrierMethods<T>::isMarkable(thingp->get()))
|
||||
TraceEdge(trc, thingp, name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void
|
||||
TraceNullableEdge(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
if (InternalBarrierMethods<T>::isMarkable(thingp->unbarrieredGet()))
|
||||
TraceEdge(trc, thingp, name);
|
||||
}
|
||||
|
||||
// Trace through a "root" edge. These edges are the initial edges in the object
|
||||
// graph traversal. Root edges are asserted to only be traversed in the initial
|
||||
// phase of a GC.
|
||||
template <typename T>
|
||||
void
|
||||
TraceRoot(JSTracer* trc, T* thingp, const char* name);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
|
||||
inline void
|
||||
TraceRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
gc::AssertRootMarkingPhase(trc);
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void
|
||||
TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
TraceRoot(trc, thingp->unsafeGet(), name);
|
||||
}
|
||||
|
||||
// Idential to TraceRoot, except that this variant will not crash if |*thingp|
|
||||
// is null.
|
||||
template <typename T>
|
||||
void
|
||||
TraceNullableRoot(JSTracer* trc, T* thingp, const char* name);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name);
|
||||
inline void
|
||||
TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
gc::AssertRootMarkingPhase(trc);
|
||||
if (InternalBarrierMethods<T>::isMarkable(*thingp))
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void
|
||||
TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
|
||||
{
|
||||
TraceNullableRoot(trc, thingp->unsafeGet(), name);
|
||||
}
|
||||
|
||||
// Like TraceEdge, but for edges that do not use one of the automatic barrier
|
||||
// classes and, thus, must be treated specially for moving GC. This method is
|
||||
// separate from TraceEdge to make accidental use of such edges more obvious.
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name);
|
||||
inline void
|
||||
TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
gc::TraceEdgeInternal(trc, gc::ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
// Visits a WeakRef, but does not trace its referents. If *thingp is not marked
|
||||
// at the end of marking, it is replaced by nullptr. This method records
|
||||
// thingp, so the edge location must not change after this function is called.
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceWeakEdge(JSTracer* trc, WeakRef<T>* thingp, const char* name);
|
||||
inline void
|
||||
TraceWeakEdge(JSTracer* trc, WeakRef<T>* thingp, const char* name)
|
||||
{
|
||||
gc::TraceWeakEdgeInternal(trc, gc::ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
|
||||
}
|
||||
|
||||
// Trace all edges contained in the given array.
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name);
|
||||
TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name)
|
||||
{
|
||||
gc::TraceRangeInternal(trc, len, gc::ConvertToBase(vec[0].unsafeUnbarrieredForTracing()), name);
|
||||
}
|
||||
|
||||
// Trace all root edges in the given array.
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name);
|
||||
TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name)
|
||||
{
|
||||
gc::AssertRootMarkingPhase(trc);
|
||||
gc::TraceRangeInternal(trc, len, gc::ConvertToBase(vec), name);
|
||||
}
|
||||
|
||||
// Trace an edge that crosses compartment boundaries. If the compartment of the
|
||||
// destination thing is not being GC'd, then the edge will not be traced.
|
||||
template <typename T>
|
||||
void
|
||||
TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, WriteBarrieredBase<T>* dst,
|
||||
TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, WriteBarrieredBase<Value>* dst,
|
||||
const char* name);
|
||||
|
||||
// As above but with manual barriers.
|
||||
|
Loading…
Reference in New Issue
Block a user