summaryrefslogtreecommitdiff
path: root/js/public
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2022-05-29 00:47:25 -0500
committerMatt A. Tobin <email@mattatobin.com>2022-05-29 00:47:25 -0500
commitf11b40c3ab4a5a766b0b71ab1e9a6199b23bbfeb (patch)
tree7b10fdf57c04235448662d0256ef76fa48a1d076 /js/public
parent5310bcfbad6c8687d0bdbe5e49fb73858dcc1631 (diff)
downloadaura-central-f11b40c3ab4a5a766b0b71ab1e9a6199b23bbfeb.tar.gz
[JS:Engine] Remove the use of tagged shape pointers
Diffstat (limited to 'js/public')
-rw-r--r--js/public/Class.h113
-rw-r--r--js/public/GCHashTable.h76
-rw-r--r--js/public/GCVariant.h36
-rw-r--r--js/public/GCVector.h36
-rw-r--r--js/public/RootingAPI.h283
-rw-r--r--js/public/SweepingAPI.h7
-rw-r--r--js/public/Value.h52
7 files changed, 384 insertions, 219 deletions
diff --git a/js/public/Class.h b/js/public/Class.h
index 6f1960a30..1dd03a182 100644
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -271,8 +271,119 @@ class ObjectOpResult
}
};
+class PropertyResult
+{
+ union {
+ js::Shape* shape_;
+ uintptr_t bits_;
+ };
+
+ static const uintptr_t NotFound = 0;
+ static const uintptr_t NonNativeProperty = 1;
+ static const uintptr_t DenseOrTypedArrayElement = 1;
+
+ public:
+ PropertyResult() : bits_(NotFound) {}
+
+ explicit PropertyResult(js::Shape* propertyShape)
+ : shape_(propertyShape)
+ {
+ MOZ_ASSERT(!isFound() || isNativeProperty());
+ }
+
+ explicit operator bool() const {
+ return isFound();
+ }
+
+ bool isFound() const {
+ return bits_ != NotFound;
+ }
+
+ bool isNonNativeProperty() const {
+ return bits_ == NonNativeProperty;
+ }
+
+ bool isDenseOrTypedArrayElement() const {
+ return bits_ == DenseOrTypedArrayElement;
+ }
+
+ bool isNativeProperty() const {
+ return isFound() && !isNonNativeProperty();
+ }
+
+ js::Shape* maybeShape() const {
+ MOZ_ASSERT(!isNonNativeProperty());
+ return isFound() ? shape_ : nullptr;
+ }
+
+ js::Shape* shape() const {
+ MOZ_ASSERT(isNativeProperty());
+ return shape_;
+ }
+
+ void setNotFound() {
+ bits_ = NotFound;
+ }
+
+ void setNativeProperty(js::Shape* propertyShape) {
+ shape_ = propertyShape;
+ MOZ_ASSERT(isNativeProperty());
+ }
+
+ void setNonNativeProperty() {
+ bits_ = NonNativeProperty;
+ }
+
+ void setDenseOrTypedArrayElement() {
+ bits_ = DenseOrTypedArrayElement;
+ }
+
+ void trace(JSTracer* trc);
+};
+
} // namespace JS
+namespace js {
+
+template <class Wrapper>
+class WrappedPtrOperations<JS::PropertyResult, Wrapper>
+{
+ const JS::PropertyResult& value() const { return static_cast<const Wrapper*>(this)->get(); }
+
+ public:
+ bool isFound() const { return value().isFound(); }
+ explicit operator bool() const { return bool(value()); }
+ js::Shape* maybeShape() const { return value().maybeShape(); }
+ js::Shape* shape() const { return value().shape(); }
+ bool isNativeProperty() const { return value().isNativeProperty(); }
+ bool isNonNativeProperty() const { return value().isNonNativeProperty(); }
+ bool isDenseOrTypedArrayElement() const { return value().isDenseOrTypedArrayElement(); }
+ js::Shape* asTaggedShape() const { return value().asTaggedShape(); }
+};
+
+template <class Wrapper>
+class MutableWrappedPtrOperations<JS::PropertyResult, Wrapper>
+ : public WrappedPtrOperations<JS::PropertyResult, Wrapper>
+{
+ JS::PropertyResult& value() { return static_cast<Wrapper*>(this)->get(); }
+
+ public:
+ void setNotFound() {
+ value().setNotFound();
+ }
+ void setNativeProperty(js::Shape* shape) {
+ value().setNativeProperty(shape);
+ }
+ void setNonNativeProperty() {
+ value().setNonNativeProperty();
+ }
+ void setDenseOrTypedArrayElement() {
+ value().setDenseOrTypedArrayElement();
+ }
+};
+
+} // namespace js
+
// JSClass operation signatures.
/**
@@ -428,7 +539,7 @@ namespace js {
typedef bool
(* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
- JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
+ JS::MutableHandleObject objp, JS::MutableHandle<JS::PropertyResult> propp);
typedef bool
(* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
JS::Handle<JS::PropertyDescriptor> desc,
diff --git a/js/public/GCHashTable.h b/js/public/GCHashTable.h
index 4de1c39a8..3e647ed10 100644
--- a/js/public/GCHashTable.h
+++ b/js/public/GCHashTable.h
@@ -133,13 +133,13 @@ class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy, AllocPol
}
};
-template <typename Outer, typename... Args>
-class GCHashMapOperations
+template <typename Wrapper, typename... Args>
+class WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
{
using Map = JS::GCHashMap<Args...>;
using Lookup = typename Map::Lookup;
- const Map& map() const { return static_cast<const Outer*>(this)->get(); }
+ const Map& map() const { return static_cast<const Wrapper*>(this)->get(); }
public:
using AddPtr = typename Map::AddPtr;
@@ -162,18 +162,18 @@ class GCHashMapOperations
}
};
-template <typename Outer, typename... Args>
-class MutableGCHashMapOperations
- : public GCHashMapOperations<Outer, Args...>
+template <typename Wrapper, typename... Args>
+class MutableWrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
+ : public WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
{
using Map = JS::GCHashMap<Args...>;
using Lookup = typename Map::Lookup;
- Map& map() { return static_cast<Outer*>(this)->get(); }
+ Map& map() { return static_cast<Wrapper*>(this)->get(); }
public:
using AddPtr = typename Map::AddPtr;
- struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} };
+ struct Enum : public Map::Enum { explicit Enum(Wrapper& o) : Map::Enum(o.map()) {} };
using Ptr = typename Map::Ptr;
using Range = typename Map::Range;
@@ -210,26 +210,6 @@ class MutableGCHashMapOperations
}
};
-template <typename A, typename B, typename C, typename D, typename E>
-class RootedBase<JS::GCHashMap<A,B,C,D,E>>
- : public MutableGCHashMapOperations<JS::Rooted<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
-template <typename A, typename B, typename C, typename D, typename E>
-class MutableHandleBase<JS::GCHashMap<A,B,C,D,E>>
- : public MutableGCHashMapOperations<JS::MutableHandle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
-template <typename A, typename B, typename C, typename D, typename E>
-class HandleBase<JS::GCHashMap<A,B,C,D,E>>
- : public GCHashMapOperations<JS::Handle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
-template <typename A, typename B, typename C, typename D, typename E>
-class WeakCacheBase<JS::GCHashMap<A,B,C,D,E>>
- : public MutableGCHashMapOperations<JS::WeakCache<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
-{};
-
} // namespace js
namespace JS {
@@ -291,13 +271,13 @@ class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
namespace js {
-template <typename Outer, typename... Args>
-class GCHashSetOperations
+template <typename Wrapper, typename... Args>
+class WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
{
using Set = JS::GCHashSet<Args...>;
using Lookup = typename Set::Lookup;
- const Set& set() const { return static_cast<const Outer*>(this)->get(); }
+ const Set& set() const { return static_cast<const Wrapper*>(this)->get(); }
public:
using AddPtr = typename Set::AddPtr;
@@ -321,19 +301,19 @@ class GCHashSetOperations
}
};
-template <typename Outer, typename... Args>
-class MutableGCHashSetOperations
- : public GCHashSetOperations<Outer, Args...>
+template <typename Wrapper, typename... Args>
+class MutableWrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
+ : public WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
{
using Set = JS::GCHashSet<Args...>;
using Lookup = typename Set::Lookup;
- Set& set() { return static_cast<Outer*>(this)->get(); }
+ Set& set() { return static_cast<Wrapper*>(this)->get(); }
public:
using AddPtr = typename Set::AddPtr;
using Entry = typename Set::Entry;
- struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} };
+ struct Enum : public Set::Enum { explicit Enum(Wrapper& o) : Set::Enum(o.set()) {} };
using Ptr = typename Set::Ptr;
using Range = typename Set::Range;
@@ -369,30 +349,6 @@ class MutableGCHashSetOperations
}
};
-template <typename T, typename HP, typename AP>
-class RootedBase<JS::GCHashSet<T, HP, AP>>
- : public MutableGCHashSetOperations<JS::Rooted<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
-template <typename T, typename HP, typename AP>
-class MutableHandleBase<JS::GCHashSet<T, HP, AP>>
- : public MutableGCHashSetOperations<JS::MutableHandle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
-template <typename T, typename HP, typename AP>
-class HandleBase<JS::GCHashSet<T, HP, AP>>
- : public GCHashSetOperations<JS::Handle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
-template <typename T, typename HP, typename AP>
-class WeakCacheBase<JS::GCHashSet<T, HP, AP>>
- : public MutableGCHashSetOperations<JS::WeakCache<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
-{
-};
-
} /* namespace js */
#endif /* GCHashTable_h */
diff --git a/js/public/GCVariant.h b/js/public/GCVariant.h
index 43f2957fe..3ec40df5c 100644
--- a/js/public/GCVariant.h
+++ b/js/public/GCVariant.h
@@ -123,13 +123,13 @@ struct GCPolicy<mozilla::Variant<Ts...>>
namespace js {
-template <typename Outer, typename... Ts>
-class GCVariantOperations
+template <typename Wrapper, typename... Ts>
+class WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
{
using Impl = JS::detail::GCVariantImplementation<Ts...>;
using Variant = mozilla::Variant<Ts...>;
- const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
+ const Variant& variant() const { return static_cast<const Wrapper*>(this)->get(); }
public:
template <typename T>
@@ -149,15 +149,15 @@ class GCVariantOperations
}
};
-template <typename Outer, typename... Ts>
-class MutableGCVariantOperations
- : public GCVariantOperations<Outer, Ts...>
+template <typename Wrapper, typename... Ts>
+class MutableWrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
+ : public WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
{
using Impl = JS::detail::GCVariantImplementation<Ts...>;
using Variant = mozilla::Variant<Ts...>;
- const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
- Variant& variant() { return static_cast<Outer*>(this)->get(); }
+ const Variant& variant() const { return static_cast<const Wrapper*>(this)->get(); }
+ Variant& variant() { return static_cast<Wrapper*>(this)->get(); }
public:
template <typename T>
@@ -172,26 +172,6 @@ class MutableGCVariantOperations
}
};
-template <typename... Ts>
-class RootedBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
-template <typename... Ts>
-class MutableHandleBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
-template <typename... Ts>
-class HandleBase<mozilla::Variant<Ts...>>
- : public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
-template <typename... Ts>
-class PersistentRootedBase<mozilla::Variant<Ts...>>
- : public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
-{ };
-
} // namespace js
#endif // js_GCVariant_h
diff --git a/js/public/GCVector.h b/js/public/GCVector.h
index 1c9925261..4acf0d1fc 100644
--- a/js/public/GCVector.h
+++ b/js/public/GCVector.h
@@ -134,11 +134,11 @@ class GCVector
namespace js {
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
-class GCVectorOperations
+template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
+class WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
{
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
- const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
+ const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
public:
const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
@@ -154,13 +154,13 @@ class GCVectorOperations
}
};
-template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
-class MutableGCVectorOperations
- : public GCVectorOperations<Outer, T, Capacity, AllocPolicy>
+template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
+class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
+ : public WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
{
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
- const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
- Vec& vec() { return static_cast<Outer*>(this)->get(); }
+ const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
+ Vec& vec() { return static_cast<Wrapper*>(this)->get(); }
public:
const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
@@ -223,26 +223,6 @@ class MutableGCVectorOperations
void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
};
-template <typename T, size_t N, typename AP>
-class RootedBase<JS::GCVector<T,N,AP>>
- : public MutableGCVectorOperations<JS::Rooted<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
-template <typename T, size_t N, typename AP>
-class MutableHandleBase<JS::GCVector<T,N,AP>>
- : public MutableGCVectorOperations<JS::MutableHandle<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
-template <typename T, size_t N, typename AP>
-class HandleBase<JS::GCVector<T,N,AP>>
- : public GCVectorOperations<JS::Handle<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
-template <typename T, size_t N, typename AP>
-class PersistentRootedBase<JS::GCVector<T,N,AP>>
- : public MutableGCVectorOperations<JS::PersistentRooted<JS::GCVector<T,N,AP>>, T,N,AP>
-{};
-
} // namespace js
#endif // js_GCVector_h
diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h
index 5f0740d53..aec25b0ff 100644
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -112,17 +112,23 @@ template <typename T>
struct BarrierMethods {
};
-template <typename T>
-class RootedBase {};
+template <typename Element, typename Wrapper>
+class WrappedPtrOperations {};
-template <typename T>
-class HandleBase {};
+template <typename Element, typename Wrapper>
+class MutableWrappedPtrOperations : public WrappedPtrOperations<Element, Wrapper> {};
-template <typename T>
-class MutableHandleBase {};
+template <typename T, typename Wrapper>
+class RootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
-template <typename T>
-class HeapBase {};
+template <typename T, typename Wrapper>
+class HandleBase : public WrappedPtrOperations<T, Wrapper> {};
+
+template <typename T, typename Wrapper>
+class MutableHandleBase : public MutableWrappedPtrOperations<T, Wrapper> {};
+
+template <typename T, typename Wrapper>
+class HeapBase : public MutableWrappedPtrOperations<T, Wrapper> {};
// Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many macros into scope
template <typename T> struct IsHeapConstructibleType { static constexpr bool value = false; };
@@ -132,8 +138,8 @@ FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE
-template <typename T>
-class PersistentRootedBase {};
+template <typename T, typename Wrapper>
+class PersistentRootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
static void* const ConstNullValue = nullptr;
@@ -143,10 +149,6 @@ template<typename T>
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<T>, etc. to
// something that takes a |const T&| is not a GC hazard.
#define DECLARE_POINTER_CONSTREF_OPS(T) \
@@ -230,12 +232,14 @@ AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {}
* Type T must be a public GC pointer type.
*/
template <typename T>
-class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
+class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
{
// Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for legacy reasons.
static_assert(js::IsHeapConstructibleType<T>::value,
"Type T must be a public GC pointer type");
public:
+ using ElementType = T;
+
Heap() {
static_assert(sizeof(T) == sizeof(Heap<T>),
"Heap<T> must be binary compatible with T.");
@@ -367,9 +371,11 @@ ScriptIsMarkedGray(const Heap<JSScript*>& script)
* - It is not possible to store flag bits in a Heap<T>.
*/
template <typename T>
-class TenuredHeap : public js::HeapBase<T>
+class TenuredHeap : public js::HeapBase<T, TenuredHeap<T>>
{
public:
+ using ElementType = T;
+
TenuredHeap() : bits(0) {
static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
"TenuredHeap<T> must be binary compatible with T.");
@@ -377,9 +383,6 @@ class TenuredHeap : public js::HeapBase<T>
explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) { setPtr(p.getPtr()); }
- bool operator==(const TenuredHeap<T>& other) { return bits == other.bits; }
- bool operator!=(const TenuredHeap<T>& other) { return bits != other.bits; }
-
void setPtr(T newPtr) {
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
if (newPtr)
@@ -451,11 +454,13 @@ class TenuredHeap : public js::HeapBase<T>
* specialization, define a HandleBase<T> specialization containing them.
*/
template <typename T>
-class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
+class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T, Handle<T>>
{
friend class JS::MutableHandle<T>;
public:
+ using ElementType = T;
+
/* Creates a handle from a handle of a type convertible to T. */
template <typename S>
MOZ_IMPLICIT Handle(Handle<S> handle,
@@ -516,7 +521,6 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
MOZ_IMPLICIT Handle(MutableHandle<S>& root,
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
- DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
@@ -540,9 +544,11 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
* them.
*/
template <typename T>
-class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
+class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T, MutableHandle<T>>
{
public:
+ using ElementType = T;
+
inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
@@ -753,7 +759,7 @@ namespace JS {
* specialization, define a RootedBase<T> specialization containing them.
*/
template <typename T>
-class MOZ_RAII Rooted : public js::RootedBase<T>
+class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>>
{
inline void registerWithRootLists(js::RootedListHeads& roots) {
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
@@ -775,6 +781,8 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
}
public:
+ using ElementType = T;
+
template <typename RootingContext>
explicit Rooted(const RootingContext& cx)
: ptr(GCPolicy<T>::initial())
@@ -807,7 +815,6 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
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);
@@ -853,8 +860,8 @@ namespace js {
* Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
* Handle<StringObject*> h = rooted;
*/
-template <>
-class RootedBase<JSObject*>
+template <typename Container>
+class RootedBase<JSObject*, Container> : public MutableWrappedPtrOperations<JSObject*, Container>
{
public:
template <class U>
@@ -871,8 +878,8 @@ class RootedBase<JSObject*>
* Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
* Handle<StringObject*> h = rooted;
*/
-template <>
-class HandleBase<JSObject*>
+template <typename Container>
+class HandleBase<JSObject*, Container> : public WrappedPtrOperations<JSObject*, Container>
{
public:
template <class U>
@@ -881,16 +888,17 @@ class HandleBase<JSObject*>
/** Interface substitute for Rooted<T> which does not root the variable's memory. */
template <typename T>
-class MOZ_RAII FakeRooted : public RootedBase<T>
+class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>>
{
public:
+ using ElementType = T;
+
template <typename CX>
explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy<T>::initial()) {}
template <typename CX>
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);
@@ -908,9 +916,11 @@ class MOZ_RAII FakeRooted : public RootedBase<T>
/** Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
template <typename T>
-class FakeMutableHandle : public js::MutableHandleBase<T>
+class FakeMutableHandle : public js::MutableHandleBase<T, FakeMutableHandle<T>>
{
public:
+ using ElementType = T;
+
MOZ_IMPLICIT FakeMutableHandle(T* t) {
ptr = t;
}
@@ -1075,7 +1085,7 @@ MutableHandle<T>::MutableHandle(PersistentRooted<T>* root)
* marked when the object itself is marked.
*/
template<typename T>
-class PersistentRooted : public js::PersistentRootedBase<T>,
+class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
private mozilla::LinkedListElement<PersistentRooted<T>>
{
using ListBase = mozilla::LinkedListElement<PersistentRooted<T>>;
@@ -1101,6 +1111,8 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
js::RootLists& rootLists(js::ContextFriendFields* cx) = delete;
public:
+ using ElementType = T;
+
PersistentRooted() : ptr(GCPolicy<T>::initial()) {}
template <typename RootingContext>
@@ -1154,7 +1166,6 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
}
}
- DECLARE_POINTER_COMPARISON_OPS(T);
DECLARE_POINTER_CONSTREF_OPS(T);
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
@@ -1191,6 +1202,8 @@ class JS_PUBLIC_API(ObjectPtr)
Heap<JSObject*> value;
public:
+ using ElementType = JSObject*;
+
ObjectPtr() : value(nullptr) {}
explicit ObjectPtr(JSObject* obj) : value(obj) {}
@@ -1240,10 +1253,10 @@ class JS_PUBLIC_API(ObjectPtr)
namespace js {
-template <typename Outer, typename T, typename D>
-class UniquePtrOperations
+template <typename T, typename D, typename Container>
+class WrappedPtrOperations<UniquePtr<T, D>, Container>
{
- const UniquePtr<T, D>& uniquePtr() const { return static_cast<const Outer*>(this)->get(); }
+ const UniquePtr<T, D>& uniquePtr() const { return static_cast<const Container*>(this)->get(); }
public:
explicit operator bool() const { return !!uniquePtr(); }
@@ -1252,36 +1265,17 @@ class UniquePtrOperations
T& operator*() const { return *uniquePtr(); }
};
-template <typename Outer, typename T, typename D>
-class MutableUniquePtrOperations : public UniquePtrOperations<Outer, T, D>
+template <typename T, typename D, typename Container>
+class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
+ : public WrappedPtrOperations<UniquePtr<T, D>, Container>
{
- UniquePtr<T, D>& uniquePtr() { return static_cast<Outer*>(this)->get(); }
+ UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
public:
MOZ_MUST_USE typename UniquePtr<T, D>::Pointer release() { return uniquePtr().release(); }
void reset(T* ptr = T()) { uniquePtr().reset(ptr); }
};
-template <typename T, typename D>
-class RootedBase<UniquePtr<T, D>>
- : public MutableUniquePtrOperations<JS::Rooted<UniquePtr<T, D>>, T, D>
-{ };
-
-template <typename T, typename D>
-class MutableHandleBase<UniquePtr<T, D>>
- : public MutableUniquePtrOperations<JS::MutableHandle<UniquePtr<T, D>>, T, D>
-{ };
-
-template <typename T, typename D>
-class HandleBase<UniquePtr<T, D>>
- : public UniquePtrOperations<JS::Handle<UniquePtr<T, D>>, T, D>
-{ };
-
-template <typename T, typename D>
-class PersistentRootedBase<UniquePtr<T, D>>
- : public MutableUniquePtrOperations<JS::PersistentRooted<UniquePtr<T, D>>, T, D>
-{ };
-
namespace gc {
template <typename T, typename TraceCallbacks>
@@ -1324,6 +1318,177 @@ Swap(JS::TenuredHeap<T>& aX, JS::TenuredHeap<T>& aY)
} /* 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 <typename T>
+struct DefineComparisonOps : mozilla::FalseType {};
+
+template <typename T>
+struct DefineComparisonOps<JS::Heap<T>> : mozilla::TrueType {
+ static const T& get(const JS::Heap<T>& v) { return v.unbarrieredGet(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::TenuredHeap<T>> : mozilla::TrueType {
+ static const T get(const JS::TenuredHeap<T>& v) { return v.unbarrieredGetPtr(); }
+};
+
+template <>
+struct DefineComparisonOps<JS::ObjectPtr> : mozilla::TrueType {
+ static const JSObject* get(const JS::ObjectPtr& v) { return v.unbarrieredGet(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::Rooted<T>> : mozilla::TrueType {
+ static const T& get(const JS::Rooted<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::Handle<T>> : mozilla::TrueType {
+ static const T& get(const JS::Handle<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::MutableHandle<T>> : mozilla::TrueType {
+ static const T& get(const JS::MutableHandle<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<JS::PersistentRooted<T>> : mozilla::TrueType {
+ static const T& get(const JS::PersistentRooted<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<js::FakeRooted<T>> : mozilla::TrueType {
+ static const T& get(const js::FakeRooted<T>& v) { return v.get(); }
+};
+
+template <typename T>
+struct DefineComparisonOps<js::FakeMutableHandle<T>> : mozilla::TrueType {
+ static const T& get(const js::FakeMutableHandle<T>& 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 T, typename U>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ js::detail::DefineComparisonOps<U>::value, bool>::Type
+operator==(const T& a, const U& b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == js::detail::DefineComparisonOps<U>::get(b);
+}
+
+template <typename T, typename U>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ js::detail::DefineComparisonOps<U>::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 T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator==(const T& a, const typename T::ElementType& b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == b;
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator!=(const T& a, const typename T::ElementType& b) {
+ return !(a == b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
+operator==(const typename T::ElementType& a, const T& b) {
+ return a == js::detail::DefineComparisonOps<T>::get(b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::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 T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(const typename mozilla::RemovePointer<typename T::ElementType>::Type* a, const T& b) {
+ return a == js::detail::DefineComparisonOps<T>::get(b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(const typename mozilla::RemovePointer<typename T::ElementType>::Type* a, const T& b) {
+ return !(a == b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(const T& a, const typename mozilla::RemovePointer<typename T::ElementType>::Type* b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == b;
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(const T& a, const typename mozilla::RemovePointer<typename T::ElementType>::Type* b) {
+ return !(a == b);
+}
+
+// Case 4: For pointer wrappers, comparison between the wrapper and nullptr.
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(std::nullptr_t a, const T& b) {
+ return a == js::detail::DefineComparisonOps<T>::get(b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(std::nullptr_t a, const T& b) {
+ return !(a == b);
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator==(const T& a, std::nullptr_t b) {
+ return js::detail::DefineComparisonOps<T>::get(a) == b;
+}
+
+template <typename T>
+typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
+ mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
+operator!=(const T& a, std::nullptr_t b) {
+ return !(a == b);
+}
+
#undef DELETE_ASSIGNMENT_OPS
#endif /* js_RootingAPI_h */
diff --git a/js/public/SweepingAPI.h b/js/public/SweepingAPI.h
index 39abb0fc0..bbc1ec279 100644
--- a/js/public/SweepingAPI.h
+++ b/js/public/SweepingAPI.h
@@ -8,11 +8,6 @@
#include "js/HeapAPI.h"
-namespace js {
-template <typename T>
-class WeakCacheBase {};
-} // namespace js
-
namespace JS {
template <typename T> class WeakCache;
@@ -24,7 +19,7 @@ RegisterWeakCache(JS::Zone* zone, JS::WeakCache<void*>* cachep);
// A WeakCache stores the given Sweepable container and links itself into a
// list of such caches that are swept during each GC.
template <typename T>
-class WeakCache : public js::WeakCacheBase<T>,
+class WeakCache : public js::MutableWrappedPtrOperations<T, WeakCache<T>>,
private mozilla::LinkedListElement<WeakCache<T>>
{
friend class mozilla::LinkedListElement<WeakCache<T>>;
diff --git a/js/public/Value.h b/js/public/Value.h
index 087d178ef..c645f0773 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1340,20 +1340,18 @@ struct BarrierMethods<JS::Value>
}
};
-template <class Outer> class MutableValueOperations;
+template <class Wrapper> class MutableValueOperations;
/**
* A class designed for CRTP use in implementing the non-mutating parts of the
- * Value interface in Value-like classes. Outer must be a class inheriting
- * ValueOperations<Outer> with a visible get() method returning a const
- * reference to the Value abstracted by Outer.
+ * Value interface in Value-like classes. Wrapper must be a class inheriting
+ * ValueOperations<Wrapper> with a visible get() method returning a const
+ * reference to the Value abstracted by Wrapper.
*/
-template <class Outer>
-class ValueOperations
+template <class Wrapper>
+class WrappedPtrOperations<JS::Value, Wrapper>
{
- friend class MutableValueOperations<Outer>;
-
- const JS::Value& value() const { return static_cast<const Outer*>(this)->get(); }
+ const JS::Value& value() const { return static_cast<const Wrapper*>(this)->get(); }
public:
bool isUndefined() const { return value().isUndefined(); }
@@ -1398,17 +1396,17 @@ class ValueOperations
/**
* A class designed for CRTP use in implementing all the mutating parts of the
- * Value interface in Value-like classes. Outer must be a class inheriting
- * MutableValueOperations<Outer> with visible get() methods returning const and
- * non-const references to the Value abstracted by Outer.
+ * Value interface in Value-like classes. Wrapper must be a class inheriting
+ * MutableWrappedPtrOperations<Wrapper> with visible get() methods returning const and
+ * non-const references to the Value abstracted by Wrapper.
*/
-template <class Outer>
-class MutableValueOperations : public ValueOperations<Outer>
+template <class Wrapper>
+class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperations<JS::Value, Wrapper>
{
protected:
void set(const JS::Value& v) {
// Call Outer::set to trigger any barriers.
- static_cast<Outer*>(this)->set(v);
+ static_cast<Wrapper*>(this)->set(v);
}
public:
@@ -1434,13 +1432,9 @@ class MutableValueOperations : public ValueOperations<Outer>
* Augment the generic Heap<T> interface when T = Value with
* type-querying, value-extracting, and mutating operations.
*/
-template <>
-class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
+template <typename Wrapper>
+class HeapBase<JS::Value, Wrapper> : public MutableWrappedPtrOperations<JS::Value, Wrapper>
{
- typedef JS::Heap<JS::Value> Outer;
-
- friend class ValueOperations<Outer>;
-
public:
void setNumber(uint32_t ui) {
if (ui > JSVAL_INT_MAX) {
@@ -1460,22 +1454,6 @@ class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
}
};
-template <>
-class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> >
-{};
-
-template <>
-class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> >
-{};
-
-template <>
-class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> >
-{};
-
-template <>
-class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::PersistentRooted<JS::Value>>
-{};
-
/*
* If the Value is a GC pointer type, convert to that type and call |f| with
* the pointer. If the Value is not a GC type, calls F::defaultValue.