From 7cd3e66374113df0e5217cbd4ffc7251dc5ec1bf Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Thu, 31 Oct 2019 11:00:25 +0000 Subject: [PATCH] Bug 1590694 - Make it possible to use const GC wrappers r=jandem The main change is to make BarrieredBase::unsafeUnbarrieredForTracing() const and use const_cast to get return the non-const pointer. This makes sense because the GC is allowed to update the pointer used while preseving the logical value of the cell, e.g. when compacting. Differential Revision: https://phabricator.services.mozilla.com/D50618 --HG-- extra : moz-landing-system : lando --- js/src/gc/Barrier.h | 2 +- js/src/gc/Marking.cpp | 11 ++- js/src/gc/Marking.h | 2 +- js/src/gc/Tracer.h | 6 +- js/src/jsapi-tests/testGCHeapPostBarriers.cpp | 96 ++++++++++++------- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 887f67aae994..01ae6cc89198 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -418,7 +418,7 @@ class MOZ_NON_MEMMOVABLE BarrieredBase { // instantiation. Friending to the generic template leads to a number of // unintended consequences, including template resolution ambiguity and a // circular dependency with Tracing.h. - T* unsafeUnbarrieredForTracing() { return &value; } + T* unsafeUnbarrieredForTracing() const { return const_cast(&value); } }; // Base class for barriered pointer types that intercept only writes. diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 12fdf6a80700..84a9b71c58d6 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -497,17 +497,18 @@ template void js::TraceManuallyBarrieredCrossCompartmentEdge( template void js::TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, - WriteBarriered* dst, const char* name) { + const WriteBarriered* dst, + const char* name) { if (ShouldTraceCrossCompartment(trc, src, dst->get())) { TraceEdgeInternal(trc, dst->unsafeUnbarrieredForTracing(), name); } } -template void js::TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, - WriteBarriered* dst, - const char* name); +template void js::TraceCrossCompartmentEdge( + JSTracer* trc, JSObject* src, const WriteBarriered* dst, + const char* name); template void js::TraceCrossCompartmentEdge( - JSTracer* trc, JSObject* src, WriteBarriered* dst, + JSTracer* trc, JSObject* src, const WriteBarriered* dst, const char* name); template diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index 824ed7237558..88fd18e0537d 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -109,7 +109,7 @@ inline bool IsAboutToBeFinalizedUnbarriered(T* thingp) { } template -inline bool IsAboutToBeFinalized(WriteBarriered* thingp) { +inline bool IsAboutToBeFinalized(const WriteBarriered* thingp) { return IsAboutToBeFinalizedInternal( ConvertToBase(thingp->unsafeUnbarrieredForTracing())); } diff --git a/js/src/gc/Tracer.h b/js/src/gc/Tracer.h index b4b763dbcae8..9d0a792b8547 100644 --- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -119,7 +119,7 @@ inline void AssertRootMarkingPhase(JSTracer* trc) {} // wrapped in the WeakCache<> template to perform the appropriate sweeping. template -inline void TraceEdge(JSTracer* trc, WriteBarriered* thingp, +inline void TraceEdge(JSTracer* trc, const WriteBarriered* thingp, const char* name) { gc::TraceEdgeInternal( trc, gc::ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name); @@ -134,7 +134,7 @@ inline void TraceEdge(JSTracer* trc, WeakHeapPtr* thingp, const char* name) { // tracing. template -inline void TraceNullableEdge(JSTracer* trc, WriteBarriered* thingp, +inline void TraceNullableEdge(JSTracer* trc, const WriteBarriered* thingp, const char* name) { if (InternalBarrierMethods::isMarkable(thingp->get())) { TraceEdge(trc, thingp, name); @@ -228,7 +228,7 @@ void TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name) { // destination thing is not being GC'd, then the edge will not be traced. template void TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, - WriteBarriered* dst, const char* name); + const WriteBarriered* dst, const char* name); // As above but with manual barriers. template diff --git a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp index 420bfe3eb2de..786453e36aa5 100644 --- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp +++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp @@ -17,26 +17,29 @@ // A heap-allocated structure containing one of our barriered pointer wrappers // to test. -template +template struct TestStruct { W wrapper; -}; - -// A specialized version for GCPtr that adds a zone() method. -template -struct TestStruct> { - js::GCPtr wrapper; void trace(JSTracer* trc) { TraceNullableEdge(trc, &wrapper, "TestStruct::wrapper"); } + + TestStruct() {} + explicit TestStruct(T init) : wrapper(init) {} }; // Give the GCPtr version GCManagedDeletePolicy as required. namespace JS { + template -struct DeletePolicy>> - : public js::GCManagedDeletePolicy>> {}; +struct DeletePolicy, T>> + : public js::GCManagedDeletePolicy, T>> {}; + +template +struct DeletePolicy, T>> + : public js::GCManagedDeletePolicy, T>> {}; + } // namespace JS template @@ -77,7 +80,7 @@ BEGIN_TEST(testGCHeapPostBarriers) { CHECK(!js::gc::IsInsideNursery(obj.get())); JS::RootedObject tenuredObject(cx, obj); - /* Currently JSObject and JSFunction objects are nursery allocated. */ + /* JSObject and JSFunction objects are nursery allocated. */ CHECK(TestHeapPostBarriersForType()); CHECK(TestHeapPostBarriersForType()); @@ -95,20 +98,49 @@ bool CanAccessObject(JSObject* obj) { template bool TestHeapPostBarriersForType() { - CHECK((TestHeapPostBarriersForWrapper>())); - CHECK((TestHeapPostBarriersForWrapper>())); - CHECK((TestHeapPostBarriersForWrapper>())); + CHECK((TestHeapPostBarriersForWrapper())); + CHECK((TestHeapPostBarriersForWrapper())); + CHECK((TestHeapPostBarriersForWrapper())); return true; } -template +template