[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:
Clemens Backes 2020-03-09 12:04:51 +01:00 committed by Commit Bot
parent 11da29a745
commit 42f2e1fcc0

View File

@ -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_