зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1618038 - Implement support for wrapper-class comparisons in the innermost namespace containing each wrapper class, as ADL intended. Also simplify the operator implementations in certain minor ways. r=sfink
Differential Revision: https://phabricator.services.mozilla.com/D64242 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
0186cbe565
Коммит
4ab1c168ae
|
@ -0,0 +1,197 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
/*
|
||||
* Support comparison operations on wrapper types -- e.g. |JS::Rooted<T>|,
|
||||
* |JS::Handle<T>|, and so on -- against raw |T| values, against pointers or
|
||||
* |nullptr| if the wrapper is a pointer wrapper, and against other wrappers
|
||||
* around compatible types.
|
||||
*/
|
||||
|
||||
#ifndef js_ComparisonOperators_h
|
||||
#define js_ComparisonOperators_h
|
||||
|
||||
#include <type_traits> // std::false_type, std::true_type, std::enable_if_t, std::is_pointer_v, std::remove_pointer_t
|
||||
|
||||
// To define |operator==| and |operator!=| for a wrapper class |W| (which may
|
||||
// or may not be a template class) that contains a |T|:
|
||||
//
|
||||
// * Specialize |JS::detail::DefineComparisonOps| for |W|:
|
||||
// - Make it inherit from |std::true_type|.
|
||||
// - Include within your specialization a |static get(const W& v)| function
|
||||
// that returns the value (which may be an lvalue reference) of the |T| in
|
||||
// |W|.
|
||||
// * If needed, add |using JS::detail::wrapper_comparison::operator==;| and
|
||||
// |using JS::detail::wrapper_comparison::operator!=;| to the namespace
|
||||
// directly containing |W| at the end of this header. (If you are not in
|
||||
// SpiderMonkey code and have questionably decided to define your own
|
||||
// wrapper class, add these to its namespace somewhere in your code.)
|
||||
//
|
||||
// The first step opts the wrapper class into comparison support and defines a
|
||||
// generic means of extracting a comparable |T| out of an instance.
|
||||
//
|
||||
// The second step ensures that symmetric |operator==| and |operator!=| are
|
||||
// exposed for the wrapper, accepting two wrappers or a wrapper and a suitable
|
||||
// raw value.
|
||||
//
|
||||
// Failure to perform *both* steps will likely result in errors like
|
||||
// 'invalid operands to binary expression' or 'no match for operator=='
|
||||
// when comparing an instance of your wrapper.
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// By default, comparison ops are not supported for types.
|
||||
template <typename T>
|
||||
struct DefineComparisonOps : std::false_type {};
|
||||
|
||||
// Define functions for the core equality operations, that the actual operators
|
||||
// can all invoke.
|
||||
|
||||
// Compare two wrapper types. Assumes both wrapper types support comparison
|
||||
// operators.
|
||||
template <typename W, typename OW>
|
||||
inline bool WrapperEqualsWrapper(const W& wrapper, const OW& other) {
|
||||
return JS::detail::DefineComparisonOps<W>::get(wrapper) ==
|
||||
JS::detail::DefineComparisonOps<OW>::get(other);
|
||||
}
|
||||
|
||||
// Compare a wrapper against a value of its unwrapped element type (or against a
|
||||
// value that implicitly converts to that unwrapped element type). Assumes its
|
||||
// wrapper argument supports comparison operators.
|
||||
template <typename W>
|
||||
inline bool WrapperEqualsUnwrapped(const W& wrapper,
|
||||
const typename W::ElementType& value) {
|
||||
return JS::detail::DefineComparisonOps<W>::get(wrapper) == value;
|
||||
}
|
||||
|
||||
// Compare a wrapper containing a pointer against a pointer to const element
|
||||
// type. Assumes its wrapper argument supports comparison operators.
|
||||
template <typename W>
|
||||
inline bool WrapperEqualsPointer(
|
||||
const W& wrapper,
|
||||
const typename std::remove_pointer_t<typename W::ElementType>* ptr) {
|
||||
return JS::detail::DefineComparisonOps<W>::get(wrapper) == ptr;
|
||||
}
|
||||
|
||||
// It is idiomatic C++ to define operators on user-defined types in the
|
||||
// namespace of their operands' types (not at global scope, which isn't examined
|
||||
// if at point of operator use another operator definition shadows the global
|
||||
// definition). But our wrappers live in *multiple* namespaces (|namespace js|
|
||||
// and |namespace JS| in SpiderMonkey), so we can't literally do that without
|
||||
// defining ambiguous overloads.
|
||||
//
|
||||
// Instead, we define the operators *once* in a namespace containing nothing
|
||||
// else at all. Then we |using| the operators into each namespace containing
|
||||
// a wrapper type. |using| creates *aliases*, so two |using|s of the same
|
||||
// operator contribute only one overload to overload resolution.
|
||||
namespace wrapper_comparison {
|
||||
|
||||
// Comparisons between potentially-differing wrappers.
|
||||
template <typename W, typename OW>
|
||||
inline typename std::enable_if_t<JS::detail::DefineComparisonOps<W>::value &&
|
||||
JS::detail::DefineComparisonOps<OW>::value,
|
||||
bool>
|
||||
operator==(const W& wrapper, const OW& other) {
|
||||
return JS::detail::WrapperEqualsWrapper(wrapper, other);
|
||||
}
|
||||
|
||||
template <typename W, typename OW>
|
||||
inline typename std::enable_if_t<JS::detail::DefineComparisonOps<W>::value &&
|
||||
JS::detail::DefineComparisonOps<OW>::value,
|
||||
bool>
|
||||
operator!=(const W& wrapper, const OW& other) {
|
||||
return !JS::detail::WrapperEqualsWrapper(wrapper, other);
|
||||
}
|
||||
|
||||
// Comparisons between a wrapper and its unwrapped element type.
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value, bool>
|
||||
operator==(const W& wrapper, const typename W::ElementType& value) {
|
||||
return WrapperEqualsUnwrapped(wrapper, value);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value, bool>
|
||||
operator!=(const W& wrapper, const typename W::ElementType& value) {
|
||||
return !WrapperEqualsUnwrapped(wrapper, value);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value, bool>
|
||||
operator==(const typename W::ElementType& value, const W& wrapper) {
|
||||
return WrapperEqualsUnwrapped(wrapper, value);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value, bool>
|
||||
operator!=(const typename W::ElementType& value, const W& wrapper) {
|
||||
return !WrapperEqualsUnwrapped(wrapper, value);
|
||||
}
|
||||
|
||||
// For wrappers around a pointer type, comparisons between a wrapper object
|
||||
// and a const element pointer (including against |nullptr|).
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value &&
|
||||
std::is_pointer_v<typename W::ElementType>,
|
||||
bool>
|
||||
operator==(const W& wrapper,
|
||||
const typename std::remove_pointer_t<typename W::ElementType>* ptr) {
|
||||
return WrapperEqualsPointer(wrapper, ptr);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value &&
|
||||
std::is_pointer_v<typename W::ElementType>,
|
||||
bool>
|
||||
operator!=(const W& wrapper,
|
||||
const typename std::remove_pointer_t<typename W::ElementType>* ptr) {
|
||||
return !WrapperEqualsPointer(wrapper, ptr);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value &&
|
||||
std::is_pointer_v<typename W::ElementType>,
|
||||
bool>
|
||||
operator==(const typename std::remove_pointer_t<typename W::ElementType>* ptr,
|
||||
const W& wrapper) {
|
||||
return WrapperEqualsPointer(wrapper, ptr);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
inline typename std::enable_if_t<DefineComparisonOps<W>::value &&
|
||||
std::is_pointer_v<typename W::ElementType>,
|
||||
bool>
|
||||
operator!=(const typename std::remove_pointer_t<typename W::ElementType>* ptr,
|
||||
const W& wrapper) {
|
||||
return !WrapperEqualsPointer(wrapper, ptr);
|
||||
}
|
||||
|
||||
} // namespace wrapper_comparison
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
// Expose wrapper-supporting |operator==| and |operator!=| in the namespaces of
|
||||
// all SpiderMonkey's wrapper classes that support comparisons.
|
||||
|
||||
namespace JS {
|
||||
|
||||
using JS::detail::wrapper_comparison::operator==;
|
||||
using JS::detail::wrapper_comparison::operator!=;
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
using JS::detail::wrapper_comparison::operator==;
|
||||
using JS::detail::wrapper_comparison::operator!=;
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // js_ComparisonOperators_h
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "js/ComparisonOperators.h" // JS::detail::DefineComparisonOps
|
||||
#include "js/GCAnnotations.h"
|
||||
#include "js/GCPolicyAPI.h"
|
||||
#include "js/GCTypeMacros.h" // JS_FOR_EACH_PUBLIC_{,TAGGED_}GC_POINTER_TYPE
|
||||
|
@ -199,11 +200,6 @@ struct PersistentRootedMarker;
|
|||
|
||||
namespace JS {
|
||||
|
||||
template <typename T>
|
||||
class Rooted;
|
||||
template <typename T>
|
||||
class PersistentRooted;
|
||||
|
||||
JS_FRIEND_API void HeapObjectPostWriteBarrier(JSObject** objp, JSObject* prev,
|
||||
JSObject* next);
|
||||
JS_FRIEND_API void HeapStringPostWriteBarrier(JSString** objp, JSString* prev,
|
||||
|
@ -372,6 +368,15 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>> {
|
|||
T ptr;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<Heap<T>> : std::true_type {
|
||||
static const T& get(const Heap<T>& v) { return v.unbarrieredGet(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool ObjectIsTenured(JSObject* obj) {
|
||||
return !js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(obj));
|
||||
}
|
||||
|
@ -525,6 +530,15 @@ class TenuredHeap : public js::HeapBase<T, TenuredHeap<T>> {
|
|||
uintptr_t bits;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<TenuredHeap<T>> : std::true_type {
|
||||
static const T get(const TenuredHeap<T>& v) { return v.unbarrieredGetPtr(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// std::swap uses a stack temporary, which prevents classes like Heap<T>
|
||||
// from being declared MOZ_HEAP_CLASS.
|
||||
template <typename T>
|
||||
|
@ -546,6 +560,13 @@ static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(
|
|||
return ObjectIsMarkedGray(obj.unbarrieredGetPtr());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class MutableHandle;
|
||||
template <typename T>
|
||||
class Rooted;
|
||||
template <typename T>
|
||||
class PersistentRooted;
|
||||
|
||||
/**
|
||||
* Reference to a T that has been rooted elsewhere. This is most useful
|
||||
* as a parameter type, which guarantees that the T lvalue is properly
|
||||
|
@ -556,7 +577,7 @@ static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(
|
|||
*/
|
||||
template <typename T>
|
||||
class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T, Handle<T>> {
|
||||
friend class JS::MutableHandle<T>;
|
||||
friend class MutableHandle<T>;
|
||||
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
@ -638,6 +659,15 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T, Handle<T>> {
|
|||
const T* ptr;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<Handle<T>> : std::true_type {
|
||||
static const T& get(const Handle<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Similar to a handle, but the underlying storage can be changed. This is
|
||||
* useful for outparams.
|
||||
|
@ -693,6 +723,15 @@ class MOZ_STACK_CLASS MutableHandle
|
|||
T* ptr;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<MutableHandle<T>> : std::true_type {
|
||||
static const T& get(const MutableHandle<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
@ -1116,6 +1155,15 @@ class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>> {
|
|||
Rooted(const Rooted&) = delete;
|
||||
} JS_HAZ_ROOTED;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<Rooted<T>> : std::true_type {
|
||||
static const T& get(const Rooted<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
@ -1389,6 +1437,15 @@ class PersistentRooted
|
|||
detail::MaybeWrapped<T> ptr;
|
||||
} JS_HAZ_ROOTED;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<PersistentRooted<T>> : std::true_type {
|
||||
static const T& get(const PersistentRooted<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
@ -1435,192 +1492,6 @@ void CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks,
|
|||
|
||||
} /* namespace gc */
|
||||
|
||||
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 <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(); }
|
||||
};
|
||||
|
||||
} /* 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);
|
||||
}
|
||||
|
||||
#endif /* js_RootingAPI_h */
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
#ifndef gc_Barrier_h
|
||||
#define gc_Barrier_h
|
||||
|
||||
#include <type_traits> // std::true_type
|
||||
|
||||
#include "NamespaceImports.h"
|
||||
|
||||
#include "gc/Cell.h"
|
||||
#include "gc/StoreBuffer.h"
|
||||
#include "js/ComparisonOperators.h" // JS::detail::DefineComparisonOps
|
||||
#include "js/HeapAPI.h"
|
||||
#include "js/Id.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
@ -516,6 +519,23 @@ class PreBarriered : public WriteBarriered<T> {
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<js::PreBarriered<T>> : std::true_type {
|
||||
static const T& get(const js::PreBarriered<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* A pre- and post-barriered heap pointer, for use inside the JS engine.
|
||||
*
|
||||
|
@ -591,6 +611,23 @@ class GCPtr : public WriteBarriered<T> {
|
|||
GCPtr<T>& operator=(GCPtr<T>&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<js::GCPtr<T>> : std::true_type {
|
||||
static const T& get(const js::GCPtr<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* A pre- and post-barriered heap pointer, for use inside the JS engine. These
|
||||
* heap pointers can be stored in C++ containers like GCVector and GCHashMap.
|
||||
|
@ -673,6 +710,23 @@ class HeapPtr : public WriteBarriered<T> {
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<js::HeapPtr<T>> : std::true_type {
|
||||
static const T& get(const js::HeapPtr<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
// Base class for barriered pointer types that intercept reads and writes.
|
||||
template <typename T>
|
||||
class ReadBarriered : public BarrieredBase<T> {
|
||||
|
@ -766,6 +820,25 @@ class WeakHeapPtr : public ReadBarriered<T>,
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<js::WeakHeapPtr<T>> : std::true_type {
|
||||
static const T& get(const js::WeakHeapPtr<T>& v) {
|
||||
return v.unbarrieredGet();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
// A WeakRef pointer does not hold its target live and is automatically nulled
|
||||
// out when the GC discovers that it is not reachable from any other path.
|
||||
template <typename T>
|
||||
|
@ -816,6 +889,23 @@ class HeapSlot : public WriteBarriered<Value> {
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <>
|
||||
struct DefineComparisonOps<js::HeapSlot> : std::true_type {
|
||||
static const Value& get(const js::HeapSlot& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
class HeapSlotArray {
|
||||
HeapSlot* array;
|
||||
|
||||
|
@ -1096,35 +1186,6 @@ using HeapPtrObject = HeapPtr<JSObject*>;
|
|||
using HeapPtrRegExpShared = HeapPtr<RegExpShared*>;
|
||||
using HeapPtrValue = HeapPtr<Value>;
|
||||
|
||||
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<WeakHeapPtr<T>> : mozilla::TrueType {
|
||||
static const T& get(const WeakHeapPtr<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 */
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
#ifndef gc_MaybeRooted_h
|
||||
#define gc_MaybeRooted_h
|
||||
|
||||
#include "mozilla/Assertions.h" // MOZ_CRASH
|
||||
#include "mozilla/Attributes.h" // MOZ_IMPLICIT, MOZ_RAII
|
||||
|
||||
#include <type_traits> // std::true_type
|
||||
|
||||
#include "gc/Allocator.h" // js::AllowGC, js::CanGC, js::NoGC
|
||||
#include "js/RootingAPI.h" // js::{Rooted,MutableHandle}Base, js::detail::DefineComparisonOps, JS::SafelyInitialized, DECLARE_POINTER_{CONSTREF,ASSIGN}_OPS, DECLARE_NONPOINTER_{,MUTABLE_}ACCESSOR_METHODS, JS::Rooted, JS::{,Mutable}Handle
|
||||
#include "js/ComparisonOperators.h" // JS::detail::DefineComparisonOps
|
||||
#include "js/RootingAPI.h" // js::{Rooted,MutableHandle}Base, JS::SafelyInitialized, DECLARE_POINTER_{CONSTREF,ASSIGN}_OPS, DECLARE_NONPOINTER_{,MUTABLE_}ACCESSOR_METHODS, JS::Rooted, JS::{,Mutable}Handle
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -51,15 +51,23 @@ class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>> {
|
|||
FakeRooted(const FakeRooted&) = delete;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<FakeRooted<T>> : std::true_type {
|
||||
static const T& get(const FakeRooted<T>& v) { return v.get(); }
|
||||
struct DefineComparisonOps<js::FakeRooted<T>> : std::true_type {
|
||||
static const T& get(const js::FakeRooted<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
/**
|
||||
* Interface substitute for MutableHandle<T> which is not required to point to
|
||||
* rooted memory.
|
||||
|
@ -87,15 +95,23 @@ class FakeMutableHandle
|
|||
T* ptr;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<FakeMutableHandle<T>> : std::true_type {
|
||||
static const T& get(const FakeMutableHandle<T>& v) { return v.get(); }
|
||||
struct DefineComparisonOps<js::FakeMutableHandle<T>> : std::true_type {
|
||||
static const T& get(const js::FakeMutableHandle<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
/**
|
||||
* Types for a variable that either should or shouldn't be rooted, depending on
|
||||
* the template parameter allowGC. Used for implementing functions that can
|
||||
|
|
|
@ -132,6 +132,7 @@ EXPORTS.js += [
|
|||
'../public/CallNonGenericMethod.h',
|
||||
'../public/CharacterEncoding.h',
|
||||
'../public/Class.h',
|
||||
'../public/ComparisonOperators.h',
|
||||
'../public/CompilationAndEvaluation.h',
|
||||
'../public/CompileOptions.h',
|
||||
'../public/ContextOptions.h',
|
||||
|
|
Загрузка…
Ссылка в новой задаче