[API] Use proper C++ methods to implement type checks
The {TYPE_CHECK} macro used an ancient pattern to check for assignability, by assigning to a static_casted nullptrs of the respective types. C++11 introduced standard library helpers to express this more naturally. The most direct translation would have been to use {std::is_assignable} or {std::is_convertible} on the pointer types, but in most cases we can be even more strict and force one type to be a proper subtype of the other. The only exception is {ReturnValue}, which allows to assign anything if it's void. R=ulan@chromium.org Bug: v8:10155 Change-Id: I41c1103e0206514c8700c47a0bf107ad704cfc47 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2093497 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Commit-Queue: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#66695}
This commit is contained in:
parent
11da29a745
commit
42f2e1fcc0
80
include/v8.h
80
include/v8.h
@ -151,11 +151,6 @@ class ConsoleCallArguments;
|
||||
|
||||
// --- Handles ---
|
||||
|
||||
#define TYPE_CHECK(T, S) \
|
||||
while (false) { \
|
||||
*(static_cast<T* volatile*>(0)) = static_cast<S*>(0); \
|
||||
}
|
||||
|
||||
/**
|
||||
* An object reference managed by the v8 garbage collector.
|
||||
*
|
||||
@ -199,7 +194,7 @@ class Local {
|
||||
* handles. For example, converting from a Local<String> to a
|
||||
* Local<Number>.
|
||||
*/
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -365,7 +360,7 @@ class MaybeLocal {
|
||||
template <class S>
|
||||
V8_INLINE MaybeLocal(Local<S> that)
|
||||
: val_(reinterpret_cast<T*>(*that)) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
V8_INLINE bool IsEmpty() const { return val_ == nullptr; }
|
||||
@ -625,11 +620,8 @@ class NonCopyablePersistentTraits {
|
||||
template<class S, class M>
|
||||
V8_INLINE static void Copy(const Persistent<S, M>& source,
|
||||
NonCopyablePersistent* dest) {
|
||||
Uncompilable<Object>();
|
||||
}
|
||||
// TODO(dcarney): come up with a good compile error here.
|
||||
template<class O> V8_INLINE static void Uncompilable() {
|
||||
TYPE_CHECK(O, Primitive);
|
||||
static_assert(sizeof(S) < 0,
|
||||
"NonCopyablePersistentTraits::Copy is not instantiable");
|
||||
}
|
||||
};
|
||||
|
||||
@ -672,7 +664,7 @@ template <class T, class M> class Persistent : public PersistentBase<T> {
|
||||
template <class S>
|
||||
V8_INLINE Persistent(Isolate* isolate, Local<S> that)
|
||||
: PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
/**
|
||||
* Construct a Persistent from a Persistent.
|
||||
@ -682,7 +674,7 @@ template <class T, class M> class Persistent : public PersistentBase<T> {
|
||||
template <class S, class M2>
|
||||
V8_INLINE Persistent(Isolate* isolate, const Persistent<S, M2>& that)
|
||||
: PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
/**
|
||||
* The copy constructors and assignment operator create a Persistent
|
||||
@ -767,7 +759,7 @@ class Global : public PersistentBase<T> {
|
||||
template <class S>
|
||||
V8_INLINE Global(Isolate* isolate, Local<S> that)
|
||||
: PersistentBase<T>(PersistentBase<T>::New(isolate, *that)) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -778,7 +770,7 @@ class Global : public PersistentBase<T> {
|
||||
template <class S>
|
||||
V8_INLINE Global(Isolate* isolate, const PersistentBase<S>& that)
|
||||
: PersistentBase<T>(PersistentBase<T>::New(isolate, that.val_)) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -958,7 +950,7 @@ class TracedGlobal : public TracedReferenceBase<T> {
|
||||
TracedGlobal(Isolate* isolate, Local<S> that) : TracedReferenceBase<T>() {
|
||||
this->val_ = this->New(isolate, that.val_, &this->val_,
|
||||
TracedReferenceBase<T>::kWithDestructor);
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1081,7 +1073,7 @@ class TracedReference : public TracedReferenceBase<T> {
|
||||
TracedReference(Isolate* isolate, Local<S> that) : TracedReferenceBase<T>() {
|
||||
this->val_ = this->New(isolate, that.val_, &this->val_,
|
||||
TracedReferenceBase<T>::kWithoutDestructor);
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4215,7 +4207,7 @@ class ReturnValue {
|
||||
public:
|
||||
template <class S> V8_INLINE ReturnValue(const ReturnValue<S>& that)
|
||||
: value_(that.value_) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
}
|
||||
// Local setters
|
||||
template <typename S>
|
||||
@ -10700,7 +10692,7 @@ Local<T> Local<T>::New(Isolate* isolate, T* that) {
|
||||
template<class T>
|
||||
template<class S>
|
||||
void Eternal<T>::Set(Isolate* isolate, Local<S> handle) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
val_ = reinterpret_cast<T*>(
|
||||
V8::Eternalize(isolate, reinterpret_cast<Value*>(*handle)));
|
||||
}
|
||||
@ -10744,7 +10736,7 @@ T* PersistentBase<T>::New(Isolate* isolate, T* that) {
|
||||
template <class T, class M>
|
||||
template <class S, class M2>
|
||||
void Persistent<T, M>::Copy(const Persistent<S, M2>& that) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
this->Reset();
|
||||
if (that.IsEmpty()) return;
|
||||
internal::Address* p = reinterpret_cast<internal::Address*>(that.val_);
|
||||
@ -10772,7 +10764,7 @@ void PersistentBase<T>::Reset() {
|
||||
template <class T>
|
||||
template <class S>
|
||||
void PersistentBase<T>::Reset(Isolate* isolate, const Local<S>& other) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
Reset();
|
||||
if (other.IsEmpty()) return;
|
||||
this->val_ = New(isolate, other.val_);
|
||||
@ -10783,7 +10775,7 @@ template <class T>
|
||||
template <class S>
|
||||
void PersistentBase<T>::Reset(Isolate* isolate,
|
||||
const PersistentBase<S>& other) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
Reset();
|
||||
if (other.IsEmpty()) return;
|
||||
this->val_ = New(isolate, other.val_);
|
||||
@ -10849,7 +10841,7 @@ Global<T>::Global(Global&& other) : PersistentBase<T>(other.val_) {
|
||||
template <class T>
|
||||
template <class S>
|
||||
Global<T>& Global<T>::operator=(Global<S>&& rhs) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
if (this != &rhs) {
|
||||
this->Reset();
|
||||
if (rhs.val_ != nullptr) {
|
||||
@ -10884,7 +10876,7 @@ void TracedReferenceBase<T>::Reset() {
|
||||
template <class T>
|
||||
template <class S>
|
||||
void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
Reset();
|
||||
if (other.IsEmpty()) return;
|
||||
this->val_ = this->New(isolate, other.val_, &this->val_,
|
||||
@ -10894,7 +10886,7 @@ void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) {
|
||||
template <class T>
|
||||
template <class S>
|
||||
TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal<S>&& rhs) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
*this = std::move(rhs.template As<T>());
|
||||
return *this;
|
||||
}
|
||||
@ -10902,7 +10894,7 @@ TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal<S>&& rhs) {
|
||||
template <class T>
|
||||
template <class S>
|
||||
TracedGlobal<T>& TracedGlobal<T>::operator=(const TracedGlobal<S>& rhs) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
*this = rhs.template As<T>();
|
||||
return *this;
|
||||
}
|
||||
@ -10933,7 +10925,7 @@ TracedGlobal<T>& TracedGlobal<T>::operator=(const TracedGlobal& rhs) {
|
||||
template <class T>
|
||||
template <class S>
|
||||
void TracedReference<T>::Reset(Isolate* isolate, const Local<S>& other) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
Reset();
|
||||
if (other.IsEmpty()) return;
|
||||
this->val_ = this->New(isolate, other.val_, &this->val_,
|
||||
@ -10943,7 +10935,7 @@ void TracedReference<T>::Reset(Isolate* isolate, const Local<S>& other) {
|
||||
template <class T>
|
||||
template <class S>
|
||||
TracedReference<T>& TracedReference<T>::operator=(TracedReference<S>&& rhs) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
*this = std::move(rhs.template As<T>());
|
||||
return *this;
|
||||
}
|
||||
@ -10952,7 +10944,7 @@ template <class T>
|
||||
template <class S>
|
||||
TracedReference<T>& TracedReference<T>::operator=(
|
||||
const TracedReference<S>& rhs) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
*this = rhs.template As<T>();
|
||||
return *this;
|
||||
}
|
||||
@ -11011,7 +11003,7 @@ ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
|
||||
template <typename T>
|
||||
template <typename S>
|
||||
void ReturnValue<T>::Set(const Global<S>& handle) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
if (V8_UNLIKELY(handle.IsEmpty())) {
|
||||
*value_ = GetDefaultValue();
|
||||
} else {
|
||||
@ -11022,7 +11014,7 @@ void ReturnValue<T>::Set(const Global<S>& handle) {
|
||||
template <typename T>
|
||||
template <typename S>
|
||||
void ReturnValue<T>::Set(const TracedReferenceBase<S>& handle) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_base_of<T, S>::value, "type check");
|
||||
if (V8_UNLIKELY(handle.IsEmpty())) {
|
||||
*value_ = GetDefaultValue();
|
||||
} else {
|
||||
@ -11033,7 +11025,8 @@ void ReturnValue<T>::Set(const TracedReferenceBase<S>& handle) {
|
||||
template <typename T>
|
||||
template <typename S>
|
||||
void ReturnValue<T>::Set(const Local<S> handle) {
|
||||
TYPE_CHECK(T, S);
|
||||
static_assert(std::is_void<T>::value || std::is_base_of<T, S>::value,
|
||||
"type check");
|
||||
if (V8_UNLIKELY(handle.IsEmpty())) {
|
||||
*value_ = GetDefaultValue();
|
||||
} else {
|
||||
@ -11043,13 +11036,13 @@ void ReturnValue<T>::Set(const Local<S> handle) {
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::Set(double i) {
|
||||
TYPE_CHECK(T, Number);
|
||||
static_assert(std::is_base_of<T, Number>::value, "type check");
|
||||
Set(Number::New(GetIsolate(), i));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::Set(int32_t i) {
|
||||
TYPE_CHECK(T, Integer);
|
||||
static_assert(std::is_base_of<T, Integer>::value, "type check");
|
||||
typedef internal::Internals I;
|
||||
if (V8_LIKELY(I::IsValidSmi(i))) {
|
||||
*value_ = I::IntToSmi(i);
|
||||
@ -11060,7 +11053,7 @@ void ReturnValue<T>::Set(int32_t i) {
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::Set(uint32_t i) {
|
||||
TYPE_CHECK(T, Integer);
|
||||
static_assert(std::is_base_of<T, Integer>::value, "type check");
|
||||
// Can't simply use INT32_MAX here for whatever reason.
|
||||
bool fits_into_int32_t = (i & (1U << 31)) == 0;
|
||||
if (V8_LIKELY(fits_into_int32_t)) {
|
||||
@ -11072,7 +11065,7 @@ void ReturnValue<T>::Set(uint32_t i) {
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::Set(bool value) {
|
||||
TYPE_CHECK(T, Boolean);
|
||||
static_assert(std::is_base_of<T, Boolean>::value, "type check");
|
||||
typedef internal::Internals I;
|
||||
int root_index;
|
||||
if (value) {
|
||||
@ -11085,21 +11078,21 @@ void ReturnValue<T>::Set(bool value) {
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::SetNull() {
|
||||
TYPE_CHECK(T, Primitive);
|
||||
static_assert(std::is_base_of<T, Primitive>::value, "type check");
|
||||
typedef internal::Internals I;
|
||||
*value_ = *I::GetRoot(GetIsolate(), I::kNullValueRootIndex);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::SetUndefined() {
|
||||
TYPE_CHECK(T, Primitive);
|
||||
static_assert(std::is_base_of<T, Primitive>::value, "type check");
|
||||
typedef internal::Internals I;
|
||||
*value_ = *I::GetRoot(GetIsolate(), I::kUndefinedValueRootIndex);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void ReturnValue<T>::SetEmptyString() {
|
||||
TYPE_CHECK(T, String);
|
||||
static_assert(std::is_base_of<T, String>::value, "type check");
|
||||
typedef internal::Internals I;
|
||||
*value_ = *I::GetRoot(GetIsolate(), I::kEmptyStringRootIndex);
|
||||
}
|
||||
@ -11121,8 +11114,7 @@ Local<Value> ReturnValue<T>::Get() const {
|
||||
template <typename T>
|
||||
template <typename S>
|
||||
void ReturnValue<T>::Set(S* whatever) {
|
||||
// Uncompilable to prevent inadvertent misuse.
|
||||
TYPE_CHECK(S*, Primitive);
|
||||
static_assert(sizeof(S) < 0, "incompilable to prevent inadvertent misuse");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -12033,8 +12025,4 @@ size_t SnapshotCreator::AddData(Local<T> object) {
|
||||
|
||||
} // namespace v8
|
||||
|
||||
|
||||
#undef TYPE_CHECK
|
||||
|
||||
|
||||
#endif // INCLUDE_V8_H_
|
||||
|
Loading…
Reference in New Issue
Block a user