diff options
author | Jeremy Andrews <athenian200@outlook.com> | 2022-05-26 18:57:18 -0500 |
---|---|---|
committer | Jeremy Andrews <athenian200@outlook.com> | 2022-05-27 07:21:59 -0500 |
commit | 64ea1e09c2dfd09bf71738f08e15ec3d7d80e33b (patch) | |
tree | ea35d0e6ea0d4e4a20a131224c48e8d3bf844f97 /js/src | |
parent | cd55d0fbe4e5dddfc7e0bcc97ffa8a5a9febaff2 (diff) | |
download | uxp-64ea1e09c2dfd09bf71738f08e15ec3d7d80e33b.tar.gz |
Issue #1742 - Part 4: Don't trigger read barriers when comparing wrapped pointers types
This is actually an undocumented dependency of Bug 1325406 for Linux and
SunOS.
Ref: BZ 1308236
Diffstat (limited to 'js/src')
-rw-r--r-- | js/src/gc/Barrier.h | 46 | ||||
-rw-r--r-- | js/src/jsapi-tests/testGCHeapPostBarriers.cpp | 108 | ||||
-rw-r--r-- | js/src/vm/SharedMem.h | 4 |
3 files changed, 148 insertions, 10 deletions
diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 25f153207f..1ec269abf3 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -356,7 +356,8 @@ class WriteBarrieredBase : public BarrieredBase<T>, explicit WriteBarrieredBase(const T& v) : BarrieredBase<T>(v) {} public: - DECLARE_POINTER_COMPARISON_OPS(T); + using ElementType = T; + DECLARE_POINTER_CONSTREF_OPS(T); // Use this if the automatic coercion to T isn't working. @@ -611,14 +612,13 @@ class ReadBarriered : public ReadBarrieredBase<T>, return *this; } - const T get() const { - if (!InternalBarrierMethods<T>::isMarkable(this->value)) - return JS::GCPolicy<T>::initial(); - this->read(); + const T& get() const { + if (InternalBarrierMethods<T>::isMarkable(this->value)) + this->read(); return this->value; } - const T unbarrieredGet() const { + const T& unbarrieredGet() const { return this->value; } @@ -626,9 +626,9 @@ class ReadBarriered : public ReadBarrieredBase<T>, return bool(this->value); } - operator const T() const { return get(); } + operator const T&() const { return get(); } - const T operator->() const { return get(); } + const T& operator->() const { return get(); } T* unsafeGet() { return &this->value; } T const* unsafeGet() const { return &this->value; } @@ -934,6 +934,36 @@ typedef ReadBarriered<WasmTableObject*> ReadBarrieredWasmTableObject; typedef ReadBarriered<Value> ReadBarrieredValue; +namespace detail { + +template <typename T> +struct DefineComparisonOps<PreBarriered<T>> : mozilla::TrueType { + static const T& get(const PreBarriered<T>& v) { return v.get(); } +}; + +template <typename T> +struct DefineComparisonOps<GCPtr<T>> : mozilla::TrueType { + static const T& get(const GCPtr<T>& v) { return v.get(); } +}; + +template <typename T> +struct DefineComparisonOps<HeapPtr<T>> : mozilla::TrueType { + static const T& get(const HeapPtr<T>& v) { return v.get(); } +}; + +template <typename T> +struct DefineComparisonOps<ReadBarriered<T>> : mozilla::TrueType { + static const T& get(const ReadBarriered<T>& v) { return v.unbarrieredGet(); } +}; + +template <> +struct DefineComparisonOps<HeapSlot> : mozilla::TrueType { + static const Value& get(const HeapSlot& v) { return v.get(); } +}; + +} /* namespace detail */ + + } /* namespace js */ #endif /* gc_Barrier_h */ diff --git a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp index ccc9869724..2353f9ae46 100644 --- a/js/src/jsapi-tests/testGCHeapPostBarriers.cpp +++ b/js/src/jsapi-tests/testGCHeapPostBarriers.cpp @@ -4,6 +4,7 @@ * 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/. */ +#include "mozilla/TypeTraits.h" #include "mozilla/UniquePtr.h" #include "js/RootingAPI.h" @@ -146,3 +147,110 @@ TestHeapPostBarrierInitFailure() } END_TEST(testGCHeapPostBarriers) + +BEGIN_TEST(testUnbarrieredEquality) +{ + // Use ArrayBuffers because they have finalizers, which allows using them + // in ObjectPtr without awkward conversations about nursery allocatability. + JS::RootedObject robj(cx, JS_NewArrayBuffer(cx, 20)); + JS::RootedObject robj2(cx, JS_NewArrayBuffer(cx, 30)); + cx->gc.evictNursery(); // Need tenured objects + + // Need some bare pointers to compare against. + JSObject* obj = robj; + JSObject* obj2 = robj2; + const JSObject* constobj = robj; + const JSObject* constobj2 = robj2; + + // Make them gray. We will make sure they stay gray. (For most reads, the + // barrier will unmark gray.) + using namespace js::gc; + TenuredCell* cell = &obj->asTenured(); + TenuredCell* cell2 = &obj2->asTenured(); + cell->markIfUnmarked(GRAY); + cell2->markIfUnmarked(GRAY); + MOZ_ASSERT(cell->isMarked(GRAY)); + MOZ_ASSERT(cell2->isMarked(GRAY)); + + { + JS::Heap<JSObject*> heap(obj); + JS::Heap<JSObject*> heap2(obj2); + CHECK(TestWrapper(obj, obj2, heap, heap2)); + CHECK(TestWrapper(constobj, constobj2, heap, heap2)); + } + + { + JS::TenuredHeap<JSObject*> heap(obj); + JS::TenuredHeap<JSObject*> heap2(obj2); + CHECK(TestWrapper(obj, obj2, heap, heap2)); + CHECK(TestWrapper(constobj, constobj2, heap, heap2)); + } + + { + JS::ObjectPtr objptr(obj); + JS::ObjectPtr objptr2(obj2); + CHECK(TestWrapper(obj, obj2, objptr, objptr2)); + CHECK(TestWrapper(constobj, constobj2, objptr, objptr2)); + objptr.finalize(cx); + objptr2.finalize(cx); + } + // Sanity check that the barriers normally mark things black. + { + JS::Heap<JSObject*> heap(obj); + JS::Heap<JSObject*> heap2(obj2); + heap.get(); + heap2.get(); + CHECK(cell->isMarked(BLACK)); + CHECK(cell2->isMarked(BLACK)); + } + + return true; +} + +template <typename ObjectT, typename WrapperT> +bool +TestWrapper(ObjectT obj, ObjectT obj2, WrapperT& wrapper, WrapperT& wrapper2) +{ + using namespace js::gc; + + const TenuredCell& cell = obj->asTenured(); + const TenuredCell& cell2 = obj2->asTenured(); + + int x = 0; + + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += obj == obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += obj == wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper == obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper == wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + + CHECK(x == 0); + + x += obj != obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += obj != wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper != obj2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + x += wrapper != wrapper2; + CHECK(cell.isMarked(GRAY)); + CHECK(cell2.isMarked(GRAY)); + + CHECK(x == 4); + + return true; +} + +END_TEST(testUnbarrieredEquality) diff --git a/js/src/vm/SharedMem.h b/js/src/vm/SharedMem.h index fe8dad304d..8e5bae492a 100644 --- a/js/src/vm/SharedMem.h +++ b/js/src/vm/SharedMem.h @@ -11,8 +11,8 @@ template<typename T> class SharedMem { - static_assert(mozilla::IsPointer<T>::value, - "SharedMem encapsulates pointer types"); + // static_assert(mozilla::IsPointer<T>::value, + // "SharedMem encapsulates pointer types"); enum Sharedness { IsUnshared, |