diff -up firefox-55.0/dom/plugins/base/nsJSNPRuntime.cpp.1337988 firefox-55.0/dom/plugins/base/nsJSNPRuntime.cpp --- firefox-55.0/dom/plugins/base/nsJSNPRuntime.cpp.1337988 2017-07-31 18:20:53.000000000 +0200 +++ firefox-55.0/dom/plugins/base/nsJSNPRuntime.cpp 2017-08-02 14:33:41.736715482 +0200 @@ -1766,7 +1766,7 @@ NPObjWrapper_ObjectMoved(JSObject *obj, auto entry = static_cast(sNPObjWrappers->Search(npobj)); MOZ_ASSERT(entry && entry->mJSObj); - MOZ_ASSERT(entry->mJSObj == old); + MOZ_ASSERT(entry->mJSObj.unbarrieredGetPtr() == old); entry->mJSObj = obj; } diff -up firefox-55.0/js/ipc/JavaScriptShared.cpp.1337988 firefox-55.0/js/ipc/JavaScriptShared.cpp --- firefox-55.0/js/ipc/JavaScriptShared.cpp.1337988 2017-07-31 18:20:47.000000000 +0200 +++ firefox-55.0/js/ipc/JavaScriptShared.cpp 2017-08-02 14:33:41.736715482 +0200 @@ -101,7 +101,7 @@ IdToObjectMap::has(const ObjectId& id, c auto p = table_.lookup(id); if (!p) return false; - return p->value() == obj; + return p->value().unbarrieredGet() == obj; } #endif diff -up firefox-55.0/js/public/RootingAPI.h.1337988 firefox-55.0/js/public/RootingAPI.h --- firefox-55.0/js/public/RootingAPI.h.1337988 2017-07-31 18:20:47.000000000 +0200 +++ firefox-55.0/js/public/RootingAPI.h 2017-08-02 15:20:44.873663128 +0200 @@ -148,6 +148,10 @@ template struct PersistentRootedMarker; } /* namespace gc */ +#define DECLARE_POINTER_COMPARISON_OPS(T) \ + bool operator==(const T& other) const { return get() == other; } \ + bool operator!=(const T& other) const { return get() != other; } + // Important: Return a reference so passing a Rooted, etc. to // something that takes a |const T&| is not a GC hazard. #define DECLARE_POINTER_CONSTREF_OPS(T) \ @@ -237,8 +241,6 @@ class Heap : public js::HeapBase::value, "Type T must be a public GC pointer type"); public: - using ElementType = T; - Heap() { static_assert(sizeof(T) == sizeof(Heap), "Heap must be binary compatible with T."); @@ -385,8 +387,6 @@ template class TenuredHeap : public js::HeapBase> { public: - using ElementType = T; - TenuredHeap() : bits(0) { static_assert(sizeof(T) == sizeof(TenuredHeap), "TenuredHeap must be binary compatible with T."); @@ -394,6 +394,9 @@ class TenuredHeap : public js::HeapBase< explicit TenuredHeap(T p) : bits(0) { setPtr(p); } explicit TenuredHeap(const TenuredHeap& p) : bits(0) { setPtr(p.getPtr()); } + bool operator==(const TenuredHeap& other) { return bits == other.bits; } + bool operator!=(const TenuredHeap& other) { return bits != other.bits; } + void setPtr(T newPtr) { MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); if (newPtr) @@ -470,8 +473,6 @@ class MOZ_NONHEAP_CLASS Handle : public friend class JS::MutableHandle; public: - using ElementType = T; - /* Creates a handle from a handle of a type convertible to T. */ template MOZ_IMPLICIT Handle(Handle handle, @@ -533,6 +534,7 @@ class MOZ_NONHEAP_CLASS Handle : public MOZ_IMPLICIT Handle(MutableHandle& root, typename mozilla::EnableIf::value, int>::Type dummy = 0); + DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); @@ -559,8 +561,6 @@ template class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase> { public: - using ElementType = T; - inline MOZ_IMPLICIT MutableHandle(Rooted* root); inline MOZ_IMPLICIT MutableHandle(PersistentRooted* root); @@ -589,6 +589,7 @@ class MOZ_STACK_CLASS MutableHandle : pu return h; } + DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr); DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr); @@ -805,8 +806,6 @@ class MOZ_RAII Rooted : public js::Roote } public: - using ElementType = T; - template explicit Rooted(const RootingContext& cx) : ptr(GCPolicy::initial()) @@ -839,6 +838,7 @@ class MOZ_RAII Rooted : public js::Roote ptr = mozilla::Move(value); } + DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(Rooted, T); DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); @@ -903,14 +903,13 @@ template class MOZ_RAII FakeRooted : public RootedBase> { public: - using ElementType = T; - template explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy::initial()) {} template FakeRooted(CX* cx, T initial) : ptr(initial) {} + DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T); DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); @@ -931,8 +930,6 @@ template class FakeMutableHandle : public js::MutableHandleBase> { public: - using ElementType = T; - MOZ_IMPLICIT FakeMutableHandle(T* t) { ptr = t; } @@ -1124,8 +1121,6 @@ class PersistentRooted : public js::Root } public: - using ElementType = T; - PersistentRooted() : ptr(GCPolicy::initial()) {} explicit PersistentRooted(RootingContext* cx) @@ -1203,6 +1198,7 @@ class PersistentRooted : public js::Root } } + DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); @@ -1234,8 +1230,6 @@ class JS_PUBLIC_API(ObjectPtr) Heap value; public: - using ElementType = JSObject*; - ObjectPtr() : value(nullptr) {} explicit ObjectPtr(JSObject* obj) : value(obj) {} @@ -1342,177 +1336,6 @@ Swap(JS::TenuredHeap& aX, JS::Tenured } /* namespace mozilla */ -namespace js { -namespace detail { - -// DefineComparisonOps is a trait which selects which wrapper classes to define -// operator== and operator!= for. It supplies a getter function to extract the -// value to compare. This is used to avoid triggering the automatic read -// barriers where appropriate. -// -// If DefineComparisonOps is not specialized for a particular wrapper you may -// get errors such as 'invalid operands to binary expression' or 'no match for -// operator==' when trying to compare against instances of the wrapper. - -template -struct DefineComparisonOps : mozilla::FalseType {}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const JS::Heap& v) { return v.unbarrieredGet(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T get(const JS::TenuredHeap& v) { return v.unbarrieredGetPtr(); } -}; - -template <> -struct DefineComparisonOps : mozilla::TrueType { - static const JSObject* get(const JS::ObjectPtr& v) { return v.unbarrieredGet(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const JS::Rooted& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const JS::Handle& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const JS::MutableHandle& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const JS::PersistentRooted& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const js::FakeRooted& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const js::FakeMutableHandle& v) { return v.get(); } -}; - -} /* namespace detail */ -} /* namespace js */ - -// Overload operator== and operator!= for all types with the DefineComparisonOps -// trait using the supplied getter. -// -// There are four cases: - -// Case 1: comparison between two wrapper objects. - -template -typename mozilla::EnableIf::value && - js::detail::DefineComparisonOps::value, bool>::Type -operator==(const T& a, const U& b) { - return js::detail::DefineComparisonOps::get(a) == js::detail::DefineComparisonOps::get(b); -} - -template -typename mozilla::EnableIf::value && - js::detail::DefineComparisonOps::value, bool>::Type -operator!=(const T& a, const U& b) { - return !(a == b); -} - -// Case 2: comparison between a wrapper object and its unwrapped element type. - -template -typename mozilla::EnableIf::value, bool>::Type -operator==(const T& a, const typename T::ElementType& b) { - return js::detail::DefineComparisonOps::get(a) == b; -} - -template -typename mozilla::EnableIf::value, bool>::Type -operator!=(const T& a, const typename T::ElementType& b) { - return !(a == b); -} - -template -typename mozilla::EnableIf::value, bool>::Type -operator==(const typename T::ElementType& a, const T& b) { - return a == js::detail::DefineComparisonOps::get(b); -} - -template -typename mozilla::EnableIf::value, bool>::Type -operator!=(const typename T::ElementType& a, const T& b) { - return !(a == b); -} - -// Case 3: For pointer wrappers, comparison between the wrapper and a const -// element pointer. - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator==(const typename mozilla::RemovePointer::Type* a, const T& b) { - return a == js::detail::DefineComparisonOps::get(b); -} - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator!=(const typename mozilla::RemovePointer::Type* a, const T& b) { - return !(a == b); -} - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator==(const T& a, const typename mozilla::RemovePointer::Type* b) { - return js::detail::DefineComparisonOps::get(a) == b; -} - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator!=(const T& a, const typename mozilla::RemovePointer::Type* b) { - return !(a == b); -} - -// Case 4: For pointer wrappers, comparison between the wrapper and nullptr. - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator==(std::nullptr_t a, const T& b) { - return a == js::detail::DefineComparisonOps::get(b); -} - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator!=(std::nullptr_t a, const T& b) { - return !(a == b); -} - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator==(const T& a, std::nullptr_t b) { - return js::detail::DefineComparisonOps::get(a) == b; -} - -template -typename mozilla::EnableIf::value && - mozilla::IsPointer::value, bool>::Type -operator!=(const T& a, std::nullptr_t b) { - return !(a == b); -} - #undef DELETE_ASSIGNMENT_OPS #endif /* js_RootingAPI_h */ diff -up firefox-55.0/js/src/gc/Barrier.h.1337988 firefox-55.0/js/src/gc/Barrier.h --- firefox-55.0/js/src/gc/Barrier.h.1337988 2017-07-31 18:20:47.000000000 +0200 +++ firefox-55.0/js/src/gc/Barrier.h 2017-08-02 14:33:41.737715470 +0200 @@ -353,8 +353,8 @@ class WriteBarrieredBase : public Barrie explicit WriteBarrieredBase(const T& v) : BarrieredBase(v) {} public: - using ElementType = T; + DECLARE_POINTER_COMPARISON_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T); // Use this if the automatic coercion to T isn't working. @@ -605,13 +605,14 @@ class ReadBarriered : public ReadBarrier return *this; } - const T& get() const { - if (InternalBarrierMethods::isMarkable(this->value)) - this->read(); + const T get() const { + if (!InternalBarrierMethods::isMarkable(this->value)) + return JS::GCPolicy::initial(); + this->read(); return this->value; } - const T& unbarrieredGet() const { + const T unbarrieredGet() const { return this->value; } @@ -619,9 +620,9 @@ class ReadBarriered : public ReadBarrier 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; } @@ -948,35 +949,6 @@ typedef ReadBarriered typedef ReadBarriered ReadBarrieredValue; -namespace detail { - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const PreBarriered& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const GCPtr& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const HeapPtr& v) { return v.get(); } -}; - -template -struct DefineComparisonOps> : mozilla::TrueType { - static const T& get(const ReadBarriered& v) { return v.unbarrieredGet(); } -}; - -template <> -struct DefineComparisonOps : mozilla::TrueType { - static const Value& get(const HeapSlot& v) { return v.get(); } -}; - -} /* namespace detail */ - } /* namespace js */ #endif /* gc_Barrier_h */ diff -up firefox-55.0/js/src/jsapi-tests/testGCHeapPostBarriers.cpp.1337988 firefox-55.0/js/src/jsapi-tests/testGCHeapPostBarriers.cpp --- firefox-55.0/js/src/jsapi-tests/testGCHeapPostBarriers.cpp.1337988 2017-07-31 18:20:48.000000000 +0200 +++ firefox-55.0/js/src/jsapi-tests/testGCHeapPostBarriers.cpp 2017-08-02 15:23:03.544362400 +0200 @@ -5,7 +5,6 @@ * 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" @@ -178,117 +177,3 @@ TestHeapPostBarrierInitFailure() return true; } - -END_TEST(testGCHeapPostBarriers) - -BEGIN_TEST(testUnbarrieredEquality) -{ -#ifdef JS_GC_ZEAL - AutoLeaveZeal nozeal(cx); -#endif /* JS_GC_ZEAL */ - - // 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->runtime()->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 heap(obj); - JS::Heap heap2(obj2); - CHECK(TestWrapper(obj, obj2, heap, heap2)); - CHECK(TestWrapper(constobj, constobj2, heap, heap2)); - } - - { - JS::TenuredHeap heap(obj); - JS::TenuredHeap 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 heap(obj); - JS::Heap heap2(obj2); - heap.get(); - heap2.get(); - CHECK(cell->isMarked(BLACK)); - CHECK(cell2->isMarked(BLACK)); - } - - return true; -} - -template -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 -up firefox-55.0/js/src/vm/SharedMem.h.1337988 firefox-55.0/js/src/vm/SharedMem.h --- firefox-55.0/js/src/vm/SharedMem.h.1337988 2017-06-15 22:52:29.000000000 +0200 +++ firefox-55.0/js/src/vm/SharedMem.h 2017-08-02 14:33:41.737715470 +0200 @@ -12,8 +12,8 @@ template class SharedMem { - // static_assert(mozilla::IsPointer::value, - // "SharedMem encapsulates pointer types"); + static_assert(mozilla::IsPointer::value, + "SharedMem encapsulates pointer types"); enum Sharedness { IsUnshared, diff -up firefox-55.0/js/xpconnect/src/XPCInlines.h.1337988 firefox-55.0/js/xpconnect/src/XPCInlines.h --- firefox-55.0/js/xpconnect/src/XPCInlines.h.1337988 2017-07-31 18:20:46.000000000 +0200 +++ firefox-55.0/js/xpconnect/src/XPCInlines.h 2017-08-02 14:33:41.738715458 +0200 @@ -471,7 +471,7 @@ inline void XPCWrappedNativeTearOff::JSObjectMoved(JSObject* obj, const JSObject* old) { MOZ_ASSERT(!IsMarked()); - MOZ_ASSERT(mJSObject == old); + MOZ_ASSERT(mJSObject.unbarrieredGetPtr() == old); mJSObject = obj; } diff -up firefox-55.0/js/xpconnect/src/XPCWrappedNative.cpp.1337988 firefox-55.0/js/xpconnect/src/XPCWrappedNative.cpp --- firefox-55.0/js/xpconnect/src/XPCWrappedNative.cpp.1337988 2017-08-02 14:33:41.738715458 +0200 +++ firefox-55.0/js/xpconnect/src/XPCWrappedNative.cpp 2017-08-02 15:25:43.749014973 +0200 @@ -874,7 +874,7 @@ void XPCWrappedNative::FlatJSObjectMoved(JSObject* obj, const JSObject* old) { JS::AutoAssertGCCallback inCallback; - MOZ_ASSERT(mFlatJSObject == old); + MOZ_ASSERT(mFlatJSObject.unbarrieredGetPtr() == old); nsWrapperCache* cache = nullptr; CallQueryInterface(mIdentity, &cache); diff -up firefox-55.0/js/xpconnect/src/XPCWrappedNativeProto.cpp.1337988 firefox-55.0/js/xpconnect/src/XPCWrappedNativeProto.cpp --- firefox-55.0/js/xpconnect/src/XPCWrappedNativeProto.cpp.1337988 2017-07-31 18:20:47.000000000 +0200 +++ firefox-55.0/js/xpconnect/src/XPCWrappedNativeProto.cpp 2017-08-02 15:24:15.153207106 +0200 @@ -101,7 +101,7 @@ XPCWrappedNativeProto::CallPostCreatePro void XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj) { - MOZ_ASSERT(obj == mJSProtoObject, "huh?"); + MOZ_ASSERT(obj == mJSProtoObject.unbarrieredGet(), "huh?"); #ifdef DEBUG // Check that this object has already been swept from the map. @@ -117,7 +117,7 @@ XPCWrappedNativeProto::JSProtoObjectFina void XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj, const JSObject* old) { - MOZ_ASSERT(mJSProtoObject == old); + MOZ_ASSERT(mJSProtoObject.unbarrieredGet() == old); mJSProtoObject.init(obj); // Update without triggering barriers. }