Commit 60d10b99 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

cppgc: Replace JSMember by TracedReference

cppgc must support the same feature set as the existing unified heap
system, which requires support for wrapper-specific handling (drop on
Scavenge, merge in snapshot).

Replace JSMember by TracedReference to support IsRootForNonTracingGC()
optimizations out of the box. cppgc support for wrapper/wrappable
pairs will be added as followup.

Change-Id: I3c6eff2b8dce5b71b04b2bd75182eb8672079a64
Bug: chromium:1056170
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2498685
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70801}
parent f88fd7c5
...@@ -11,233 +11,11 @@ ...@@ -11,233 +11,11 @@
namespace v8 { namespace v8 {
class Isolate;
template <typename T>
class JSMember;
class JSVisitor;
template <typename T>
class Local;
namespace internal {
class JSMemberBaseExtractor;
class V8_EXPORT JSMemberBase {
public:
/**
* Returns true if the reference is empty, i.e., has not been assigned
* object.
*/
bool IsEmpty() const { return val_ == nullptr; }
/**
* Clears the reference. IsEmpty() will return true after this call.
*/
inline void Reset();
inline v8::Local<v8::Value> Get(v8::Isolate* isolate) const;
private:
static internal::Address* New(v8::Isolate* isolate,
internal::Address* object_slot,
internal::Address** this_slot);
static void Delete(internal::Address* object);
static void Copy(const internal::Address* const* from_slot,
internal::Address** to_slot);
static void Move(internal::Address** from_slot, internal::Address** to_slot);
JSMemberBase() = default;
JSMemberBase(v8::Isolate* isolate, internal::Address* object_slot)
: val_(New(isolate, object_slot, &val_)) {}
inline JSMemberBase& CopyImpl(const JSMemberBase& other);
inline JSMemberBase& MoveImpl(JSMemberBase&& other);
void SetSlotThreadSafe(void* value) {
reinterpret_cast<std::atomic<void*>*>(&val_)->store(
value, std::memory_order_relaxed);
}
bool IsEmptyThreadSafe() const {
return reinterpret_cast<std::atomic<const void*> const*>(&val_)->load(
std::memory_order_relaxed) == nullptr;
}
// val_ points to a GlobalHandles node.
internal::Address* val_ = nullptr;
template <typename T>
friend class v8::JSMember;
friend class v8::JSVisitor;
friend class v8::internal::JSMemberBaseExtractor;
template <typename U>
friend bool operator==(const internal::JSMemberBase&, const Local<U>&);
};
JSMemberBase& JSMemberBase::CopyImpl(const JSMemberBase& other) {
if (this != &other) {
Reset();
if (!other.IsEmpty()) {
Copy(&other.val_, &val_);
}
}
return *this;
}
JSMemberBase& JSMemberBase::MoveImpl(JSMemberBase&& other) {
if (this != &other) {
// No call to Reset() as Move() will conditionally reset itself when needed,
// and otherwise reuse the internal meta data.
Move(&other.val_, &val_);
}
return *this;
}
void JSMemberBase::Reset() {
if (IsEmpty()) return;
Delete(val_);
SetSlotThreadSafe(nullptr);
}
v8::Local<v8::Value> JSMemberBase::Get(v8::Isolate* isolate) const {
if (IsEmpty()) return Local<Value>();
return Local<Value>::New(isolate, reinterpret_cast<Value*>(val_));
}
template <typename U>
inline bool operator==(const v8::internal::JSMemberBase& lhs,
const v8::Local<U>& rhs) {
v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(lhs.val_);
v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(*rhs);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
}
template <typename U>
inline bool operator!=(const v8::internal::JSMemberBase& lhs, const U& rhs) {
return !(lhs == rhs);
}
} // namespace internal
/**
* A traced handle without destructor that clears the handle. The handle may
* only be used in GarbageCollected objects and must be processed in a Trace()
* method.
*/
template <typename T>
class V8_EXPORT JSMember : public internal::JSMemberBase {
static_assert(std::is_base_of<v8::Value, T>::value,
"JSMember only supports references to v8::Value");
public:
JSMember() = default;
template <typename U,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
JSMember(Isolate* isolate, Local<U> that)
: internal::JSMemberBase(isolate,
reinterpret_cast<internal::Address*>(*that)) {}
JSMember(const JSMember& other) { CopyImpl(other); }
template <typename U,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
JSMember(const JSMember<U>& other) { // NOLINT
CopyImpl(other);
}
JSMember(JSMember&& other) { MoveImpl(std::move(other)); }
template <typename U,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
JSMember(JSMember<U>&& other) { // NOLINT
MoveImpl(std::move(other));
}
JSMember& operator=(const JSMember& other) { return CopyImpl(other); }
template <typename U,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
JSMember& operator=(const JSMember<U>& other) {
return CopyImpl(other);
}
JSMember& operator=(JSMember&& other) { return MoveImpl(other); }
template <typename U,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
JSMember& operator=(JSMember<U>&& other) {
return MoveImpl(other);
}
T* operator->() const { return reinterpret_cast<T*>(val_); }
T* operator*() const { return reinterpret_cast<T*>(val_); }
using internal::JSMemberBase::Reset;
template <typename U,
typename = std::enable_if_t<std::is_base_of<T, U>::value>>
void Set(v8::Isolate* isolate, Local<U> that) {
Reset();
SetSlotThreadSafe(
New(isolate, reinterpret_cast<internal::Address*>(*that), &val_));
}
};
template <typename T1, typename T2,
typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
std::is_base_of<T1, T2>::value>>
inline bool operator==(const JSMember<T1>& lhs, const JSMember<T2>& rhs) {
v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(*lhs);
v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(*rhs);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
}
template <typename T1, typename T2,
typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
std::is_base_of<T1, T2>::value>>
inline bool operator!=(const JSMember<T1>& lhs, const JSMember<T2>& rhs) {
return !(lhs == rhs);
}
template <typename T1, typename T2,
typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
std::is_base_of<T1, T2>::value>>
inline bool operator==(const JSMember<T1>& lhs, const Local<T2>& rhs) {
v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(*lhs);
v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(*rhs);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
}
template <typename T1, typename T2,
typename = std::enable_if_t<std::is_base_of<T2, T1>::value ||
std::is_base_of<T1, T2>::value>>
inline bool operator==(const Local<T1>& lhs, const JSMember<T2> rhs) {
return rhs == lhs;
}
template <typename T1, typename T2>
inline bool operator!=(const JSMember<T1>& lhs, const T2& rhs) {
return !(lhs == rhs);
}
template <typename T1, typename T2>
inline bool operator!=(const T1& lhs, const JSMember<T2>& rhs) {
return !(lhs == rhs);
}
class JSVisitor : public cppgc::Visitor { class JSVisitor : public cppgc::Visitor {
public: public:
explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {} explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
void Trace(const internal::JSMemberBase& ref) { void Trace(const TracedReferenceBase& ref) {
if (ref.IsEmptyThreadSafe()) return; if (ref.IsEmptyThreadSafe()) return;
Visit(ref); Visit(ref);
} }
...@@ -245,7 +23,7 @@ class JSVisitor : public cppgc::Visitor { ...@@ -245,7 +23,7 @@ class JSVisitor : public cppgc::Visitor {
protected: protected:
using cppgc::Visitor::Visit; using cppgc::Visitor::Visit;
virtual void Visit(const internal::JSMemberBase& ref) {} virtual void Visit(const TracedReferenceBase& ref) {}
}; };
} // namespace v8 } // namespace v8
...@@ -253,8 +31,8 @@ class JSVisitor : public cppgc::Visitor { ...@@ -253,8 +31,8 @@ class JSVisitor : public cppgc::Visitor {
namespace cppgc { namespace cppgc {
template <typename T> template <typename T>
struct TraceTrait<v8::JSMember<T>> { struct TraceTrait<v8::TracedReference<T>> {
static void Trace(Visitor* visitor, const v8::JSMember<T>* self) { static void Trace(Visitor* visitor, const v8::TracedReference<T>* self) {
static_cast<v8::JSVisitor*>(visitor)->Trace(*self); static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
} }
}; };
......
...@@ -83,6 +83,7 @@ class String; ...@@ -83,6 +83,7 @@ class String;
class StringObject; class StringObject;
class Symbol; class Symbol;
class SymbolObject; class SymbolObject;
class TracedReferenceBase;
class PrimitiveArray; class PrimitiveArray;
class Private; class Private;
class Uint32; class Uint32;
...@@ -104,7 +105,7 @@ class TracedGlobal; ...@@ -104,7 +105,7 @@ class TracedGlobal;
template <class T> template <class T>
class TracedReference; class TracedReference;
template <class T> template <class T>
class TracedReferenceBase; class BasicTracedReference;
template<class K, class V, class T> class PersistentValueMap; template<class K, class V, class T> class PersistentValueMap;
template <class K, class V, class T> template <class K, class V, class T>
class PersistentValueMapBase; class PersistentValueMapBase;
...@@ -127,6 +128,7 @@ namespace internal { ...@@ -127,6 +128,7 @@ namespace internal {
enum class ArgumentsType; enum class ArgumentsType;
template <ArgumentsType> template <ArgumentsType>
class Arguments; class Arguments;
class BasicTracedReferenceExtractor;
template <typename T> template <typename T>
class CustomArguments; class CustomArguments;
class FunctionCallbackArguments; class FunctionCallbackArguments;
...@@ -135,7 +137,6 @@ class Heap; ...@@ -135,7 +137,6 @@ class Heap;
class HeapObject; class HeapObject;
class ExternalString; class ExternalString;
class Isolate; class Isolate;
class JSMemberBase;
class LocalEmbedderHeapTracer; class LocalEmbedderHeapTracer;
class MicrotaskQueue; class MicrotaskQueue;
class PropertyCallbackArguments; class PropertyCallbackArguments;
...@@ -302,10 +303,10 @@ class Local { ...@@ -302,10 +303,10 @@ class Local {
V8_INLINE static Local<T> New(Isolate* isolate, V8_INLINE static Local<T> New(Isolate* isolate,
const PersistentBase<T>& that); const PersistentBase<T>& that);
V8_INLINE static Local<T> New(Isolate* isolate, V8_INLINE static Local<T> New(Isolate* isolate,
const TracedReferenceBase<T>& that); const BasicTracedReference<T>& that);
private: private:
friend class internal::JSMemberBase; friend class TracedReferenceBase;
friend class Utils; friend class Utils;
template<class F> friend class Eternal; template<class F> friend class Eternal;
template<class F> friend class PersistentBase; template<class F> friend class PersistentBase;
...@@ -337,7 +338,7 @@ class Local { ...@@ -337,7 +338,7 @@ class Local {
template <class F> template <class F>
friend class TracedGlobal; friend class TracedGlobal;
template <class F> template <class F>
friend class TracedReferenceBase; friend class BasicTracedReference;
template <class F> template <class F>
friend class TracedReference; friend class TracedReference;
...@@ -827,27 +828,11 @@ using UniquePersistent = Global<T>; ...@@ -827,27 +828,11 @@ using UniquePersistent = Global<T>;
template <typename T> template <typename T>
struct TracedGlobalTrait {}; struct TracedGlobalTrait {};
/**
* A traced handle with copy and move semantics. The handle is to be used
* together with |v8::EmbedderHeapTracer| and specifies edges from the embedder
* into V8's heap.
*
* The exact semantics are:
* - Tracing garbage collections use |v8::EmbedderHeapTracer|.
* - Non-tracing garbage collections refer to
* |v8::EmbedderHeapTracer::IsRootForNonTracingGC()| whether the handle should
* be treated as root or not.
*
* Note that the base class cannot be instantiated itself. Choose from
* - TracedGlobal
* - TracedReference
*/
template <typename T>
class TracedReferenceBase { class TracedReferenceBase {
public: public:
/** /**
* Returns true if this TracedReferenceBase is empty, i.e., has not been * Returns true if the reference is empty, i.e., has not been assigned
* assigned an object. * object.
*/ */
bool IsEmpty() const { return val_ == nullptr; } bool IsEmpty() const { return val_ == nullptr; }
...@@ -858,37 +843,69 @@ class TracedReferenceBase { ...@@ -858,37 +843,69 @@ class TracedReferenceBase {
V8_INLINE void Reset(); V8_INLINE void Reset();
/** /**
* Construct a Local<T> from this handle. * Construct a Local<Value> from this handle.
*/ */
Local<T> Get(Isolate* isolate) const { return Local<T>::New(isolate, *this); } V8_INLINE v8::Local<v8::Value> Get(v8::Isolate* isolate) const;
template <class S> /**
V8_INLINE bool operator==(const TracedReferenceBase<S>& that) const { * Returns true if this TracedReference is empty, i.e., has not been
internal::Address* a = reinterpret_cast<internal::Address*>(val_); * assigned an object. This version of IsEmpty is thread-safe.
internal::Address* b = reinterpret_cast<internal::Address*>(that.val_); */
if (a == nullptr) return b == nullptr; bool IsEmptyThreadSafe() const {
if (b == nullptr) return false; return this->GetSlotThreadSafe() == nullptr;
return *a == *b;
} }
template <class S> protected:
V8_INLINE bool operator==(const Local<S>& that) const { /**
internal::Address* a = reinterpret_cast<internal::Address*>(val_); * Update this reference in a thread-safe way.
internal::Address* b = reinterpret_cast<internal::Address*>(that.val_); */
if (a == nullptr) return b == nullptr; void SetSlotThreadSafe(void* new_val) {
if (b == nullptr) return false; reinterpret_cast<std::atomic<void*>*>(&val_)->store(
return *a == *b; new_val, std::memory_order_relaxed);
} }
template <class S> /**
V8_INLINE bool operator!=(const TracedReferenceBase<S>& that) const { * Get this reference in a thread-safe way
return !operator==(that); */
const void* GetSlotThreadSafe() const {
return reinterpret_cast<std::atomic<const void*> const*>(&val_)->load(
std::memory_order_relaxed);
} }
template <class S> // val_ points to a GlobalHandles node.
V8_INLINE bool operator!=(const Local<S>& that) const { internal::Address* val_ = nullptr;
return !operator==(that);
} friend class internal::BasicTracedReferenceExtractor;
template <typename F>
friend class Local;
template <typename U>
friend bool operator==(const TracedReferenceBase&, const Local<U>&);
friend bool operator==(const TracedReferenceBase&,
const TracedReferenceBase&);
};
/**
* A traced handle with copy and move semantics. The handle is to be used
* together with |v8::EmbedderHeapTracer| or as part of GarbageCollected objects
* (see v8-cppgc.h) and specifies edges from C++ objects to JavaScript.
*
* The exact semantics are:
* - Tracing garbage collections use |v8::EmbedderHeapTracer| or cppgc.
* - Non-tracing garbage collections refer to
* |v8::EmbedderHeapTracer::IsRootForNonTracingGC()| whether the handle should
* be treated as root or not.
*
* Note that the base class cannot be instantiated itself. Choose from
* - TracedGlobal
* - TracedReference
*/
template <typename T>
class BasicTracedReference : public TracedReferenceBase {
public:
/**
* Construct a Local<T> from this handle.
*/
Local<T> Get(Isolate* isolate) const { return Local<T>::New(isolate, *this); }
/** /**
* Assigns a wrapper class ID to the handle. * Assigns a wrapper class ID to the handle.
...@@ -902,40 +919,24 @@ class TracedReferenceBase { ...@@ -902,40 +919,24 @@ class TracedReferenceBase {
V8_INLINE uint16_t WrapperClassId() const; V8_INLINE uint16_t WrapperClassId() const;
template <class S> template <class S>
V8_INLINE TracedReferenceBase<S>& As() const { V8_INLINE BasicTracedReference<S>& As() const {
return reinterpret_cast<TracedReferenceBase<S>&>( return reinterpret_cast<BasicTracedReference<S>&>(
const_cast<TracedReferenceBase<T>&>(*this)); const_cast<BasicTracedReference<T>&>(*this));
} }
protected: T* operator->() const { return reinterpret_cast<T*>(val_); }
/** T* operator*() const { return reinterpret_cast<T*>(val_); }
* Update this reference in a thread-safe way
*/
void SetSlotThreadSafe(T* new_val) {
reinterpret_cast<std::atomic<T*>*>(&val_)->store(new_val,
std::memory_order_relaxed);
}
/**
* Get this reference in a thread-safe way
*/
const T* GetSlotThreadSafe() const {
return reinterpret_cast<std::atomic<const T*> const*>(&val_)->load(
std::memory_order_relaxed);
}
private: private:
enum DestructionMode { kWithDestructor, kWithoutDestructor }; enum DestructionMode { kWithDestructor, kWithoutDestructor };
/** /**
* An empty TracedReferenceBase without storage cell. * An empty BasicTracedReference without storage cell.
*/ */
TracedReferenceBase() = default; BasicTracedReference() = default;
V8_INLINE static T* New(Isolate* isolate, T* that, void* slot,
DestructionMode destruction_mode);
T* val_ = nullptr; V8_INLINE static internal::Address* New(Isolate* isolate, T* that, void* slot,
DestructionMode destruction_mode);
friend class EmbedderHeapTracer; friend class EmbedderHeapTracer;
template <typename F> template <typename F>
...@@ -946,27 +947,29 @@ class TracedReferenceBase { ...@@ -946,27 +947,29 @@ class TracedReferenceBase {
template <typename F> template <typename F>
friend class TracedReference; friend class TracedReference;
template <typename F> template <typename F>
friend class BasicTracedReference;
template <typename F>
friend class ReturnValue; friend class ReturnValue;
}; };
/** /**
* A traced handle with destructor that clears the handle. For more details see * A traced handle with destructor that clears the handle. For more details see
* TracedReferenceBase. * BasicTracedReference.
*/ */
template <typename T> template <typename T>
class TracedGlobal : public TracedReferenceBase<T> { class TracedGlobal : public BasicTracedReference<T> {
public: public:
using TracedReferenceBase<T>::Reset; using BasicTracedReference<T>::Reset;
/** /**
* Destructor resetting the handle. * Destructor resetting the handle.Is
*/ */
~TracedGlobal() { this->Reset(); } ~TracedGlobal() { this->Reset(); }
/** /**
* An empty TracedGlobal without storage cell. * An empty TracedGlobal without storage cell.
*/ */
TracedGlobal() : TracedReferenceBase<T>() {} TracedGlobal() : BasicTracedReference<T>() {}
/** /**
* Construct a TracedGlobal from a Local. * Construct a TracedGlobal from a Local.
...@@ -975,9 +978,9 @@ class TracedGlobal : public TracedReferenceBase<T> { ...@@ -975,9 +978,9 @@ class TracedGlobal : public TracedReferenceBase<T> {
* pointing to the same object. * pointing to the same object.
*/ */
template <class S> template <class S>
TracedGlobal(Isolate* isolate, Local<S> that) : TracedReferenceBase<T>() { TracedGlobal(Isolate* isolate, Local<S> that) : BasicTracedReference<T>() {
this->val_ = this->New(isolate, that.val_, &this->val_, this->val_ = this->New(isolate, that.val_, &this->val_,
TracedReferenceBase<T>::kWithDestructor); BasicTracedReference<T>::kWithDestructor);
static_assert(std::is_base_of<T, S>::value, "type check"); static_assert(std::is_base_of<T, S>::value, "type check");
} }
...@@ -1074,7 +1077,7 @@ class TracedGlobal : public TracedReferenceBase<T> { ...@@ -1074,7 +1077,7 @@ class TracedGlobal : public TracedReferenceBase<T> {
* A traced handle without destructor that clears the handle. The embedder needs * A traced handle without destructor that clears the handle. The embedder needs
* to ensure that the handle is not accessed once the V8 object has been * to ensure that the handle is not accessed once the V8 object has been
* reclaimed. This can happen when the handle is not passed through the * reclaimed. This can happen when the handle is not passed through the
* EmbedderHeapTracer. For more details see TracedReferenceBase. * EmbedderHeapTracer. For more details see BasicTracedReference.
* *
* The reference assumes the embedder has precise knowledge about references at * The reference assumes the embedder has precise knowledge about references at
* all times. In case V8 needs to separately handle on-stack references, the * all times. In case V8 needs to separately handle on-stack references, the
...@@ -1082,14 +1085,14 @@ class TracedGlobal : public TracedReferenceBase<T> { ...@@ -1082,14 +1085,14 @@ class TracedGlobal : public TracedReferenceBase<T> {
* |EmbedderHeapTracer::SetStackStart|. * |EmbedderHeapTracer::SetStackStart|.
*/ */
template <typename T> template <typename T>
class TracedReference : public TracedReferenceBase<T> { class TracedReference : public BasicTracedReference<T> {
public: public:
using TracedReferenceBase<T>::Reset; using BasicTracedReference<T>::Reset;
/** /**
* An empty TracedReference without storage cell. * An empty TracedReference without storage cell.
*/ */
TracedReference() : TracedReferenceBase<T>() {} TracedReference() : BasicTracedReference<T>() {}
/** /**
* Construct a TracedReference from a Local. * Construct a TracedReference from a Local.
...@@ -1098,9 +1101,9 @@ class TracedReference : public TracedReferenceBase<T> { ...@@ -1098,9 +1101,9 @@ class TracedReference : public TracedReferenceBase<T> {
* pointing to the same object. * pointing to the same object.
*/ */
template <class S> template <class S>
TracedReference(Isolate* isolate, Local<S> that) : TracedReferenceBase<T>() { TracedReference(Isolate* isolate, Local<S> that) : BasicTracedReference<T>() {
this->val_ = this->New(isolate, that.val_, &this->val_, this->val_ = this->New(isolate, that.val_, &this->val_,
TracedReferenceBase<T>::kWithoutDestructor); BasicTracedReference<T>::kWithoutDestructor);
static_assert(std::is_base_of<T, S>::value, "type check"); static_assert(std::is_base_of<T, S>::value, "type check");
} }
...@@ -1176,14 +1179,6 @@ class TracedReference : public TracedReferenceBase<T> { ...@@ -1176,14 +1179,6 @@ class TracedReference : public TracedReferenceBase<T> {
return reinterpret_cast<TracedReference<S>&>( return reinterpret_cast<TracedReference<S>&>(
const_cast<TracedReference<T>&>(*this)); const_cast<TracedReference<T>&>(*this));
} }
/**
* Returns true if this TracedReference is empty, i.e., has not been
* assigned an object. This version of IsEmpty is thread-safe.
*/
bool IsEmptyThreadSafe() const {
return this->GetSlotThreadSafe() == nullptr;
}
}; };
/** /**
...@@ -3994,10 +3989,10 @@ class V8_EXPORT Object : public Value { ...@@ -3994,10 +3989,10 @@ class V8_EXPORT Object : public Value {
return object.val_->InternalFieldCount(); return object.val_->InternalFieldCount();
} }
/** Same as above, but works for TracedReferenceBase. */ /** Same as above, but works for BasicTracedReference. */
V8_INLINE static int InternalFieldCount( V8_INLINE static int InternalFieldCount(
const TracedReferenceBase<Object>& object) { const BasicTracedReference<Object>& object) {
return object.val_->InternalFieldCount(); return object->InternalFieldCount();
} }
/** Gets the value from an internal field. */ /** Gets the value from an internal field. */
...@@ -4021,8 +4016,8 @@ class V8_EXPORT Object : public Value { ...@@ -4021,8 +4016,8 @@ class V8_EXPORT Object : public Value {
/** Same as above, but works for TracedGlobal. */ /** Same as above, but works for TracedGlobal. */
V8_INLINE static void* GetAlignedPointerFromInternalField( V8_INLINE static void* GetAlignedPointerFromInternalField(
const TracedReferenceBase<Object>& object, int index) { const BasicTracedReference<Object>& object, int index) {
return object.val_->GetAlignedPointerFromInternalField(index); return object->GetAlignedPointerFromInternalField(index);
} }
/** /**
...@@ -4318,7 +4313,7 @@ class ReturnValue { ...@@ -4318,7 +4313,7 @@ class ReturnValue {
template <typename S> template <typename S>
V8_INLINE void Set(const Global<S>& handle); V8_INLINE void Set(const Global<S>& handle);
template <typename S> template <typename S>
V8_INLINE void Set(const TracedReferenceBase<S>& handle); V8_INLINE void Set(const BasicTracedReference<S>& handle);
template <typename S> template <typename S>
V8_INLINE void Set(const Local<S> handle); V8_INLINE void Set(const Local<S> handle);
// Fast primitive setters // Fast primitive setters
...@@ -8010,7 +8005,7 @@ class V8_EXPORT EmbedderHeapTracer { ...@@ -8010,7 +8005,7 @@ class V8_EXPORT EmbedderHeapTracer {
virtual void RegisterV8References( virtual void RegisterV8References(
const std::vector<std::pair<void*, void*> >& embedder_fields) = 0; const std::vector<std::pair<void*, void*> >& embedder_fields) = 0;
void RegisterEmbedderReference(const TracedReferenceBase<v8::Data>& ref); void RegisterEmbedderReference(const BasicTracedReference<v8::Data>& ref);
/** /**
* Called at the beginning of a GC cycle. * Called at the beginning of a GC cycle.
...@@ -9886,6 +9881,8 @@ class V8_EXPORT V8 { ...@@ -9886,6 +9881,8 @@ class V8_EXPORT V8 {
static void ToLocalEmpty(); static void ToLocalEmpty();
static void InternalFieldOutOfBounds(int index); static void InternalFieldOutOfBounds(int index);
template <class T> template <class T>
friend class BasicTracedReference;
template <class T>
friend class Global; friend class Global;
template <class T> friend class Local; template <class T> friend class Local;
template <class T> template <class T>
...@@ -9893,9 +9890,8 @@ class V8_EXPORT V8 { ...@@ -9893,9 +9890,8 @@ class V8_EXPORT V8 {
template <class T> template <class T>
friend class Maybe; friend class Maybe;
template <class T> template <class T>
friend class TracedReferenceBase;
template <class T>
friend class TracedGlobal; friend class TracedGlobal;
friend class TracedReferenceBase;
template <class T> template <class T>
friend class TracedReference; friend class TracedReference;
template <class T> template <class T>
...@@ -10793,8 +10789,8 @@ Local<T> Local<T>::New(Isolate* isolate, const PersistentBase<T>& that) { ...@@ -10793,8 +10789,8 @@ Local<T> Local<T>::New(Isolate* isolate, const PersistentBase<T>& that) {
} }
template <class T> template <class T>
Local<T> Local<T>::New(Isolate* isolate, const TracedReferenceBase<T>& that) { Local<T> Local<T>::New(Isolate* isolate, const BasicTracedReference<T>& that) {
return New(isolate, that.val_); return New(isolate, *that);
} }
template <class T> template <class T>
...@@ -10981,23 +10977,69 @@ Global<T>& Global<T>::operator=(Global<S>&& rhs) { ...@@ -10981,23 +10977,69 @@ Global<T>& Global<T>::operator=(Global<S>&& rhs) {
} }
template <class T> template <class T>
T* TracedReferenceBase<T>::New(Isolate* isolate, T* that, void* slot, internal::Address* BasicTracedReference<T>::New(
DestructionMode destruction_mode) { Isolate* isolate, T* that, void* slot, DestructionMode destruction_mode) {
if (that == nullptr) return nullptr; if (that == nullptr) return nullptr;
internal::Address* p = reinterpret_cast<internal::Address*>(that); internal::Address* p = reinterpret_cast<internal::Address*>(that);
return reinterpret_cast<T*>(V8::GlobalizeTracedReference( return V8::GlobalizeTracedReference(
reinterpret_cast<internal::Isolate*>(isolate), p, reinterpret_cast<internal::Isolate*>(isolate), p,
reinterpret_cast<internal::Address*>(slot), reinterpret_cast<internal::Address*>(slot),
destruction_mode == kWithDestructor)); destruction_mode == kWithDestructor);
} }
template <class T> void TracedReferenceBase::Reset() {
void TracedReferenceBase<T>::Reset() {
if (IsEmpty()) return; if (IsEmpty()) return;
V8::DisposeTracedGlobal(reinterpret_cast<internal::Address*>(val_)); V8::DisposeTracedGlobal(reinterpret_cast<internal::Address*>(val_));
SetSlotThreadSafe(nullptr); SetSlotThreadSafe(nullptr);
} }
v8::Local<v8::Value> TracedReferenceBase::Get(v8::Isolate* isolate) const {
if (IsEmpty()) return Local<Value>();
return Local<Value>::New(isolate, reinterpret_cast<Value*>(val_));
}
V8_INLINE bool operator==(const TracedReferenceBase& lhs,
const TracedReferenceBase& rhs) {
v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(lhs.val_);
v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(rhs.val_);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
}
template <typename U>
V8_INLINE bool operator==(const TracedReferenceBase& lhs,
const v8::Local<U>& rhs) {
v8::internal::Address* a = reinterpret_cast<v8::internal::Address*>(lhs.val_);
v8::internal::Address* b = reinterpret_cast<v8::internal::Address*>(*rhs);
if (a == nullptr) return b == nullptr;
if (b == nullptr) return false;
return *a == *b;
}
template <typename U>
V8_INLINE bool operator==(const v8::Local<U>& lhs,
const TracedReferenceBase& rhs) {
return rhs == lhs;
}
V8_INLINE bool operator!=(const TracedReferenceBase& lhs,
const TracedReferenceBase& rhs) {
return !(lhs == rhs);
}
template <typename U>
V8_INLINE bool operator!=(const TracedReferenceBase& lhs,
const v8::Local<U>& rhs) {
return !(lhs == rhs);
}
template <typename U>
V8_INLINE bool operator!=(const v8::Local<U>& lhs,
const TracedReferenceBase& rhs) {
return !(rhs == lhs);
}
template <class T> template <class T>
template <class S> template <class S>
void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) { void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) {
...@@ -11005,7 +11047,7 @@ void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) { ...@@ -11005,7 +11047,7 @@ void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) {
Reset(); Reset();
if (other.IsEmpty()) return; if (other.IsEmpty()) return;
this->val_ = this->New(isolate, other.val_, &this->val_, this->val_ = this->New(isolate, other.val_, &this->val_,
TracedReferenceBase<T>::kWithDestructor); BasicTracedReference<T>::kWithDestructor);
} }
template <class T> template <class T>
...@@ -11055,7 +11097,7 @@ void TracedReference<T>::Reset(Isolate* isolate, const Local<S>& other) { ...@@ -11055,7 +11097,7 @@ void TracedReference<T>::Reset(Isolate* isolate, const Local<S>& other) {
if (other.IsEmpty()) return; if (other.IsEmpty()) return;
this->SetSlotThreadSafe( this->SetSlotThreadSafe(
this->New(isolate, other.val_, &this->val_, this->New(isolate, other.val_, &this->val_,
TracedReferenceBase<T>::kWithoutDestructor)); BasicTracedReference<T>::kWithoutDestructor));
} }
template <class T> template <class T>
...@@ -11099,7 +11141,7 @@ TracedReference<T>& TracedReference<T>::operator=(const TracedReference& rhs) { ...@@ -11099,7 +11141,7 @@ TracedReference<T>& TracedReference<T>::operator=(const TracedReference& rhs) {
} }
template <class T> template <class T>
void TracedReferenceBase<T>::SetWrapperClassId(uint16_t class_id) { void BasicTracedReference<T>::SetWrapperClassId(uint16_t class_id) {
typedef internal::Internals I; typedef internal::Internals I;
if (IsEmpty()) return; if (IsEmpty()) return;
internal::Address* obj = reinterpret_cast<internal::Address*>(val_); internal::Address* obj = reinterpret_cast<internal::Address*>(val_);
...@@ -11108,7 +11150,7 @@ void TracedReferenceBase<T>::SetWrapperClassId(uint16_t class_id) { ...@@ -11108,7 +11150,7 @@ void TracedReferenceBase<T>::SetWrapperClassId(uint16_t class_id) {
} }
template <class T> template <class T>
uint16_t TracedReferenceBase<T>::WrapperClassId() const { uint16_t BasicTracedReference<T>::WrapperClassId() const {
typedef internal::Internals I; typedef internal::Internals I;
if (IsEmpty()) return 0; if (IsEmpty()) return 0;
internal::Address* obj = reinterpret_cast<internal::Address*>(val_); internal::Address* obj = reinterpret_cast<internal::Address*>(val_);
...@@ -11139,7 +11181,7 @@ void ReturnValue<T>::Set(const Global<S>& handle) { ...@@ -11139,7 +11181,7 @@ void ReturnValue<T>::Set(const Global<S>& handle) {
template <typename T> template <typename T>
template <typename S> template <typename S>
void ReturnValue<T>::Set(const TracedReferenceBase<S>& handle) { void ReturnValue<T>::Set(const BasicTracedReference<S>& handle) {
static_assert(std::is_base_of<T, S>::value, "type check"); static_assert(std::is_base_of<T, S>::value, "type check");
if (V8_UNLIKELY(handle.IsEmpty())) { if (V8_UNLIKELY(handle.IsEmpty())) {
*value_ = GetDefaultValue(); *value_ = GetDefaultValue();
......
...@@ -993,42 +993,6 @@ i::Address* V8::GlobalizeTracedReference(i::Isolate* isolate, i::Address* obj, ...@@ -993,42 +993,6 @@ i::Address* V8::GlobalizeTracedReference(i::Isolate* isolate, i::Address* obj,
return result.location(); return result.location();
} }
// static
i::Address* i::JSMemberBase::New(v8::Isolate* isolate, i::Address* object_slot,
i::Address** this_slot) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
LOG_API(i_isolate, JSMemberBase, New);
#ifdef DEBUG
Utils::ApiCheck((object_slot != nullptr), "i::JSMemberBase::New",
"the object must be not null");
#endif
i::Handle<i::Object> result = i_isolate->global_handles()->CreateTraced(
*object_slot, reinterpret_cast<i::Address*>(this_slot),
false /* no destructor */);
#ifdef VERIFY_HEAP
if (i::FLAG_verify_heap) {
i::Object(*object_slot).ObjectVerify(i_isolate);
}
#endif // VERIFY_HEAP
return result.location();
}
// static
void i::JSMemberBase::Delete(i::Address* object) {
i::GlobalHandles::DestroyTraced(object);
}
// static
void i::JSMemberBase::Copy(const i::Address* const* from_slot,
i::Address** to_slot) {
i::GlobalHandles::CopyTracedGlobal(from_slot, to_slot);
}
// static
void i::JSMemberBase::Move(i::Address** from_slot, i::Address** to_slot) {
i::GlobalHandles::MoveTracedGlobal(from_slot, to_slot);
}
i::Address* V8::CopyGlobalReference(i::Address* from) { i::Address* V8::CopyGlobalReference(i::Address* from) {
i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(from); i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(from);
return result.location(); return result.location();
...@@ -11091,7 +11055,7 @@ void EmbedderHeapTracer::DecreaseAllocatedSize(size_t bytes) { ...@@ -11091,7 +11055,7 @@ void EmbedderHeapTracer::DecreaseAllocatedSize(size_t bytes) {
} }
void EmbedderHeapTracer::RegisterEmbedderReference( void EmbedderHeapTracer::RegisterEmbedderReference(
const TracedReferenceBase<v8::Data>& ref) { const BasicTracedReference<v8::Data>& ref) {
if (ref.IsEmpty()) return; if (ref.IsEmpty()) return;
i::Heap* const heap = reinterpret_cast<i::Isolate*>(isolate_)->heap(); i::Heap* const heap = reinterpret_cast<i::Isolate*>(isolate_)->heap();
......
...@@ -328,7 +328,7 @@ class CppGraphBuilderImpl final { ...@@ -328,7 +328,7 @@ class CppGraphBuilderImpl final {
void Run(); void Run();
void VisitForVisibility(State* parent, const HeapObjectHeader&); void VisitForVisibility(State* parent, const HeapObjectHeader&);
void VisitForVisibility(State& parent, const JSMemberBase&); void VisitForVisibility(State& parent, const TracedReferenceBase&);
void VisitRootForGraphBuilding(RootState&, const HeapObjectHeader&, void VisitRootForGraphBuilding(RootState&, const HeapObjectHeader&,
const cppgc::SourceLocation&); const cppgc::SourceLocation&);
void ProcessPendingObjects(); void ProcessPendingObjects();
...@@ -360,7 +360,7 @@ class CppGraphBuilderImpl final { ...@@ -360,7 +360,7 @@ class CppGraphBuilderImpl final {
graph_.AddEdge(parent.get_node(), current.get_node()); graph_.AddEdge(parent.get_node(), current.get_node());
} }
void AddEdge(State& parent, const JSMemberBase& ref) { void AddEdge(State& parent, const TracedReferenceBase& ref) {
DCHECK(parent.IsVisibleNotDependent()); DCHECK(parent.IsVisibleNotDependent());
v8::Local<v8::Value> v8_value = ref.Get(cpp_heap_.isolate()); v8::Local<v8::Value> v8_value = ref.Get(cpp_heap_.isolate());
if (!v8_value.IsEmpty()) { if (!v8_value.IsEmpty()) {
...@@ -462,7 +462,7 @@ class VisiblityVisitor final : public JSVisitor { ...@@ -462,7 +462,7 @@ class VisiblityVisitor final : public JSVisitor {
void VisitWeakContainer(const void* object, void VisitWeakContainer(const void* object,
cppgc::TraceDescriptor strong_desc, cppgc::TraceDescriptor strong_desc,
cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback, cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback,
const void*) { const void*) final {
if (!weak_desc.callback) { if (!weak_desc.callback) {
// Weak container does not contribute to liveness. // Weak container does not contribute to liveness.
return; return;
...@@ -475,7 +475,7 @@ class VisiblityVisitor final : public JSVisitor { ...@@ -475,7 +475,7 @@ class VisiblityVisitor final : public JSVisitor {
} }
// JS handling. // JS handling.
void Visit(const JSMemberBase& ref) final { void Visit(const TracedReferenceBase& ref) final {
graph_builder_.VisitForVisibility(parent_scope_.ParentAsRegularState(), graph_builder_.VisitForVisibility(parent_scope_.ParentAsRegularState(),
ref); ref);
} }
...@@ -508,7 +508,7 @@ class GraphBuildingVisitor final : public JSVisitor { ...@@ -508,7 +508,7 @@ class GraphBuildingVisitor final : public JSVisitor {
void VisitWeakRoot(const void*, cppgc::TraceDescriptor, cppgc::WeakCallback, void VisitWeakRoot(const void*, cppgc::TraceDescriptor, cppgc::WeakCallback,
const void*, const cppgc::SourceLocation&) final {} const void*, const cppgc::SourceLocation&) final {}
// JS handling. // JS handling.
void Visit(const JSMemberBase& ref) final { void Visit(const TracedReferenceBase& ref) final {
graph_builder_.AddEdge(parent_scope_.ParentAsRegularState(), ref); graph_builder_.AddEdge(parent_scope_.ParentAsRegularState(), ref);
} }
...@@ -604,7 +604,7 @@ void CppGraphBuilderImpl::VisitForVisibility(State* parent, ...@@ -604,7 +604,7 @@ void CppGraphBuilderImpl::VisitForVisibility(State* parent,
} }
void CppGraphBuilderImpl::VisitForVisibility(State& parent, void CppGraphBuilderImpl::VisitForVisibility(State& parent,
const JSMemberBase& ref) { const TracedReferenceBase& ref) {
v8::Local<v8::Value> v8_value = ref.Get(cpp_heap_.isolate()); v8::Local<v8::Value> v8_value = ref.Get(cpp_heap_.isolate());
if (!v8_value.IsEmpty()) { if (!v8_value.IsEmpty()) {
parent.MarkVisible(); parent.MarkVisible();
......
...@@ -6,17 +6,16 @@ ...@@ -6,17 +6,16 @@
#define V8_HEAP_CPPGC_JS_UNIFIED_HEAP_MARKING_STATE_H_ #define V8_HEAP_CPPGC_JS_UNIFIED_HEAP_MARKING_STATE_H_
#include "include/v8-cppgc.h" #include "include/v8-cppgc.h"
#include "include/v8.h"
#include "src/heap/heap.h" #include "src/heap/heap.h"
namespace v8 { namespace v8 {
class JSMemberBase;
namespace internal { namespace internal {
class JSMemberBaseExtractor { class BasicTracedReferenceExtractor {
public: public:
static Address* ObjectReference(const JSMemberBase& ref) { static Address* ObjectReference(const TracedReferenceBase& ref) {
return reinterpret_cast<Address*>(ref.val_); return reinterpret_cast<Address*>(ref.val_);
} }
}; };
...@@ -28,15 +27,15 @@ class UnifiedHeapMarkingState { ...@@ -28,15 +27,15 @@ class UnifiedHeapMarkingState {
UnifiedHeapMarkingState(const UnifiedHeapMarkingState&) = delete; UnifiedHeapMarkingState(const UnifiedHeapMarkingState&) = delete;
UnifiedHeapMarkingState& operator=(const UnifiedHeapMarkingState&) = delete; UnifiedHeapMarkingState& operator=(const UnifiedHeapMarkingState&) = delete;
inline void MarkAndPush(const JSMemberBase&); inline void MarkAndPush(const TracedReferenceBase&);
private: private:
Heap& heap_; Heap& heap_;
}; };
void UnifiedHeapMarkingState::MarkAndPush(const JSMemberBase& ref) { void UnifiedHeapMarkingState::MarkAndPush(const TracedReferenceBase& ref) {
heap_.RegisterExternallyReferencedObject( heap_.RegisterExternallyReferencedObject(
JSMemberBaseExtractor::ObjectReference(ref)); BasicTracedReferenceExtractor::ObjectReference(ref));
} }
} // namespace internal } // namespace internal
......
...@@ -45,7 +45,7 @@ class UnifiedHeapVerificationVisitor final : public JSVisitor { ...@@ -45,7 +45,7 @@ class UnifiedHeapVerificationVisitor final : public JSVisitor {
state_.VerifyMarked(weak_desc.base_object_payload); state_.VerifyMarked(weak_desc.base_object_payload);
} }
void Visit(const internal::JSMemberBase& ref) final { void Visit(const TracedReferenceBase& ref) final {
// TODO(chromium:1056170): Verify V8 object is indeed marked. // TODO(chromium:1056170): Verify V8 object is indeed marked.
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/heap/cppgc-js/unified-heap-marking-visitor.h" #include "src/heap/cppgc-js/unified-heap-marking-visitor.h"
#include "include/v8.h"
#include "src/heap/cppgc-js/unified-heap-marking-state.h" #include "src/heap/cppgc-js/unified-heap-marking-state.h"
#include "src/heap/cppgc/heap.h" #include "src/heap/cppgc/heap.h"
#include "src/heap/cppgc/marking-state.h" #include "src/heap/cppgc/marking-state.h"
...@@ -53,15 +54,15 @@ void UnifiedHeapMarkingVisitorBase::HandleMovableReference(const void** slot) { ...@@ -53,15 +54,15 @@ void UnifiedHeapMarkingVisitorBase::HandleMovableReference(const void** slot) {
} }
namespace { namespace {
void DeferredTraceJSMember(cppgc::Visitor* visitor, const void* ref) { void DeferredTraceTracedReference(cppgc::Visitor* visitor, const void* ref) {
static_cast<JSVisitor*>(visitor)->Trace( static_cast<JSVisitor*>(visitor)->Trace(
*static_cast<const internal::JSMemberBase*>(ref)); *static_cast<const TracedReferenceBase*>(ref));
} }
} // namespace } // namespace
void UnifiedHeapMarkingVisitorBase::Visit(const internal::JSMemberBase& ref) { void UnifiedHeapMarkingVisitorBase::Visit(const TracedReferenceBase& ref) {
bool should_defer_tracing = bool should_defer_tracing = DeferTraceToMutatorThreadIfConcurrent(
DeferTraceToMutatorThreadIfConcurrent(&ref, DeferredTraceJSMember, 0); &ref, DeferredTraceTracedReference, 0);
if (!should_defer_tracing) unified_heap_marking_state_.MarkAndPush(ref); if (!should_defer_tracing) unified_heap_marking_state_.MarkAndPush(ref);
} }
......
...@@ -51,7 +51,7 @@ class V8_EXPORT_PRIVATE UnifiedHeapMarkingVisitorBase : public JSVisitor { ...@@ -51,7 +51,7 @@ class V8_EXPORT_PRIVATE UnifiedHeapMarkingVisitorBase : public JSVisitor {
void HandleMovableReference(const void**) final; void HandleMovableReference(const void**) final;
// JS handling. // JS handling.
void Visit(const internal::JSMemberBase& ref) final; void Visit(const TracedReferenceBase& ref) final;
MarkingStateBase& marking_state_; MarkingStateBase& marking_state_;
UnifiedHeapMarkingState& unified_heap_marking_state_; UnifiedHeapMarkingState& unified_heap_marking_state_;
......
...@@ -750,7 +750,6 @@ class RuntimeCallTimer final { ...@@ -750,7 +750,6 @@ class RuntimeCallTimer final {
V(Int8Array_New) \ V(Int8Array_New) \
V(Isolate_DateTimeConfigurationChangeNotification) \ V(Isolate_DateTimeConfigurationChangeNotification) \
V(Isolate_LocaleConfigurationChangeNotification) \ V(Isolate_LocaleConfigurationChangeNotification) \
V(JSMemberBase_New) \
V(JSON_Parse) \ V(JSON_Parse) \
V(JSON_Stringify) \ V(JSON_Stringify) \
V(Map_AsArray) \ V(Map_AsArray) \
......
...@@ -833,8 +833,8 @@ class EmbedderHeapTracerNoDestructorNonTracingClearing final ...@@ -833,8 +833,8 @@ class EmbedderHeapTracerNoDestructorNonTracingClearing final
// Convention (for test): Objects that are optimized have their first field // Convention (for test): Objects that are optimized have their first field
// set as a back pointer. // set as a back pointer.
TracedReferenceBase<v8::Value>* original_handle = BasicTracedReference<v8::Value>* original_handle =
reinterpret_cast<TracedReferenceBase<v8::Value>*>( reinterpret_cast<BasicTracedReference<v8::Value>*>(
v8::Object::GetAlignedPointerFromInternalField( v8::Object::GetAlignedPointerFromInternalField(
handle.As<v8::Object>(), 0)); handle.As<v8::Object>(), 0));
original_handle->Reset(); original_handle->Reset();
......
...@@ -287,7 +287,6 @@ v8_source_set("unittests_sources") { ...@@ -287,7 +287,6 @@ v8_source_set("unittests_sources") {
"heap/heap-utils.h", "heap/heap-utils.h",
"heap/index-generator-unittest.cc", "heap/index-generator-unittest.cc",
"heap/item-parallel-job-unittest.cc", "heap/item-parallel-job-unittest.cc",
"heap/js-member-unittest.cc",
"heap/list-unittest.cc", "heap/list-unittest.cc",
"heap/local-factory-unittest.cc", "heap/local-factory-unittest.cc",
"heap/local-heap-unittest.cc", "heap/local-heap-unittest.cc",
...@@ -299,6 +298,7 @@ v8_source_set("unittests_sources") { ...@@ -299,6 +298,7 @@ v8_source_set("unittests_sources") {
"heap/safepoint-unittest.cc", "heap/safepoint-unittest.cc",
"heap/slot-set-unittest.cc", "heap/slot-set-unittest.cc",
"heap/spaces-unittest.cc", "heap/spaces-unittest.cc",
"heap/traced-reference-unittest.cc",
"heap/unified-heap-snapshot-unittest.cc", "heap/unified-heap-snapshot-unittest.cc",
"heap/unified-heap-unittest.cc", "heap/unified-heap-unittest.cc",
"heap/unified-heap-utils.cc", "heap/unified-heap-utils.cc",
......
...@@ -10,154 +10,154 @@ ...@@ -10,154 +10,154 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
using JSMemberTest = TestWithIsolate; using TracedReferenceTest = TestWithIsolate;
TEST_F(JSMemberTest, ResetFromLocal) { TEST_F(TracedReferenceTest, ResetFromLocal) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
v8::JSMember<v8::Object> member; v8::TracedReference<v8::Object> ref;
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
EXPECT_TRUE(member.IsEmpty()); EXPECT_TRUE(ref.IsEmpty());
EXPECT_NE(member, local); EXPECT_NE(ref, local);
member.Set(v8_isolate(), local); ref.Reset(v8_isolate(), local);
EXPECT_FALSE(member.IsEmpty()); EXPECT_FALSE(ref.IsEmpty());
EXPECT_EQ(member, local); EXPECT_EQ(ref, local);
} }
} }
TEST_F(JSMemberTest, ConstructFromLocal) { TEST_F(TracedReferenceTest, ConstructFromLocal) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local); v8::TracedReference<v8::Object> ref(v8_isolate(), local);
EXPECT_FALSE(member.IsEmpty()); EXPECT_FALSE(ref.IsEmpty());
EXPECT_EQ(member, local); EXPECT_EQ(ref, local);
} }
} }
TEST_F(JSMemberTest, Reset) { TEST_F(TracedReferenceTest, Reset) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local); v8::TracedReference<v8::Object> ref(v8_isolate(), local);
EXPECT_FALSE(member.IsEmpty()); EXPECT_FALSE(ref.IsEmpty());
EXPECT_EQ(member, local); EXPECT_EQ(ref, local);
member.Reset(); ref.Reset();
EXPECT_TRUE(member.IsEmpty()); EXPECT_TRUE(ref.IsEmpty());
EXPECT_NE(member, local); EXPECT_NE(ref, local);
} }
} }
TEST_F(JSMemberTest, Copy) { TEST_F(TracedReferenceTest, Copy) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local); v8::TracedReference<v8::Object> ref(v8_isolate(), local);
v8::JSMember<v8::Object> member_copy1(member); v8::TracedReference<v8::Object> ref_copy1(ref);
v8::JSMember<v8::Object> member_copy2 = member; v8::TracedReference<v8::Object> ref_copy2 = ref;
EXPECT_EQ(member, local); EXPECT_EQ(ref, local);
EXPECT_EQ(member_copy1, local); EXPECT_EQ(ref_copy1, local);
EXPECT_EQ(member_copy2, local); EXPECT_EQ(ref_copy2, local);
} }
} }
TEST_F(JSMemberTest, CopyHeterogenous) { TEST_F(TracedReferenceTest, CopyHeterogenous) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local); v8::TracedReference<v8::Object> ref(v8_isolate(), local);
v8::JSMember<v8::Value> member_copy1(member); v8::TracedReference<v8::Value> ref_copy1(ref);
v8::JSMember<v8::Value> member_copy2 = member; v8::TracedReference<v8::Value> ref_copy2 = ref;
EXPECT_EQ(member, local); EXPECT_EQ(ref, local);
EXPECT_EQ(member_copy1, local); EXPECT_EQ(ref_copy1, local);
EXPECT_EQ(member_copy2, local); EXPECT_EQ(ref_copy2, local);
} }
} }
TEST_F(JSMemberTest, Move) { TEST_F(TracedReferenceTest, Move) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local); v8::TracedReference<v8::Object> ref(v8_isolate(), local);
v8::JSMember<v8::Object> member_moved1(std::move(member)); v8::TracedReference<v8::Object> ref_moved1(std::move(ref));
v8::JSMember<v8::Object> member_moved2 = std::move(member_moved1); v8::TracedReference<v8::Object> ref_moved2 = std::move(ref_moved1);
EXPECT_TRUE(member.IsEmpty()); EXPECT_TRUE(ref.IsEmpty());
EXPECT_TRUE(member_moved1.IsEmpty()); EXPECT_TRUE(ref_moved1.IsEmpty());
EXPECT_EQ(member_moved2, local); EXPECT_EQ(ref_moved2, local);
} }
} }
TEST_F(JSMemberTest, MoveHeterogenous) { TEST_F(TracedReferenceTest, MoveHeterogenous) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member1(v8_isolate(), local); v8::TracedReference<v8::Object> ref1(v8_isolate(), local);
v8::JSMember<v8::Value> member_moved1(std::move(member1)); v8::TracedReference<v8::Value> ref_moved1(std::move(ref1));
v8::JSMember<v8::Object> member2(v8_isolate(), local); v8::TracedReference<v8::Object> ref2(v8_isolate(), local);
v8::JSMember<v8::Object> member_moved2 = std::move(member2); v8::TracedReference<v8::Object> ref_moved2 = std::move(ref2);
EXPECT_TRUE(member1.IsEmpty()); EXPECT_TRUE(ref1.IsEmpty());
EXPECT_EQ(member_moved1, local); EXPECT_EQ(ref_moved1, local);
EXPECT_TRUE(member2.IsEmpty()); EXPECT_TRUE(ref2.IsEmpty());
EXPECT_EQ(member_moved2, local); EXPECT_EQ(ref_moved2, local);
} }
} }
TEST_F(JSMemberTest, Equality) { TEST_F(TracedReferenceTest, Equality) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local1 = v8::Local<v8::Object> local1 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member1(v8_isolate(), local1); v8::TracedReference<v8::Object> ref1(v8_isolate(), local1);
v8::JSMember<v8::Object> member2(v8_isolate(), local1); v8::TracedReference<v8::Object> ref2(v8_isolate(), local1);
EXPECT_EQ(member1, member2); EXPECT_EQ(ref1, ref2);
EXPECT_EQ(member2, member1); EXPECT_EQ(ref2, ref1);
v8::Local<v8::Object> local2 = v8::Local<v8::Object> local2 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member3(v8_isolate(), local2); v8::TracedReference<v8::Object> ref3(v8_isolate(), local2);
EXPECT_NE(member2, member3); EXPECT_NE(ref2, ref3);
EXPECT_NE(member3, member2); EXPECT_NE(ref3, ref2);
} }
} }
TEST_F(JSMemberTest, EqualityHeterogenous) { TEST_F(TracedReferenceTest, EqualityHeterogenous) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local1 = v8::Local<v8::Object> local1 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member1(v8_isolate(), local1); v8::TracedReference<v8::Object> ref1(v8_isolate(), local1);
v8::JSMember<v8::Value> member2(v8_isolate(), local1); v8::TracedReference<v8::Value> ref2(v8_isolate(), local1);
EXPECT_EQ(member1, member2); EXPECT_EQ(ref1, ref2);
EXPECT_EQ(member2, member1); EXPECT_EQ(ref2, ref1);
v8::Local<v8::Object> local2 = v8::Local<v8::Object> local2 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member3(v8_isolate(), local2); v8::TracedReference<v8::Object> ref3(v8_isolate(), local2);
EXPECT_NE(member2, member3); EXPECT_NE(ref2, ref3);
EXPECT_NE(member3, member2); EXPECT_NE(ref3, ref2);
} }
} }
...@@ -170,7 +170,7 @@ class JSVisitorForTesting final : public JSVisitor { ...@@ -170,7 +170,7 @@ class JSVisitorForTesting final : public JSVisitor {
: JSVisitor(cppgc::internal::VisitorFactory::CreateKey()), : JSVisitor(cppgc::internal::VisitorFactory::CreateKey()),
expected_object_(expected_object) {} expected_object_(expected_object) {}
void Visit(const internal::JSMemberBase& ref) final { void Visit(const TracedReferenceBase& ref) final {
EXPECT_EQ(ref, expected_object_); EXPECT_EQ(ref, expected_object_);
visit_count_++; visit_count_++;
} }
...@@ -184,14 +184,14 @@ class JSVisitorForTesting final : public JSVisitor { ...@@ -184,14 +184,14 @@ class JSVisitorForTesting final : public JSVisitor {
} // namespace } // namespace
TEST_F(JSMemberTest, JSMemberTrace) { TEST_F(TracedReferenceTest, TracedReferenceTrace) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate()); v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
{ {
v8::HandleScope handles(v8_isolate()); v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local = v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate())); v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> js_member(v8_isolate(), local); v8::TracedReference<v8::Object> js_member(v8_isolate(), local);
JSVisitorForTesting visitor(local); JSVisitorForTesting visitor(local);
// Cast to cppgc::Visitor to ensure that we dispatch through the base // Cast to cppgc::Visitor to ensure that we dispatch through the base
// visitor and use traits. // visitor and use traits.
......
...@@ -293,11 +293,11 @@ class GCedWithJSRef : public cppgc::GarbageCollected<GCedWithJSRef> { ...@@ -293,11 +293,11 @@ class GCedWithJSRef : public cppgc::GarbageCollected<GCedWithJSRef> {
virtual void Trace(cppgc::Visitor* v) const { v->Trace(v8_object_); } virtual void Trace(cppgc::Visitor* v) const { v->Trace(v8_object_); }
void SetV8Object(v8::Isolate* isolate, v8::Local<v8::Object> object) { void SetV8Object(v8::Isolate* isolate, v8::Local<v8::Object> object) {
v8_object_.Set(isolate, object); v8_object_.Reset(isolate, object);
} }
private: private:
JSMember<v8::Object> v8_object_; TracedReference<v8::Object> v8_object_;
}; };
constexpr const char GCedWithJSRef::kExpectedName[]; constexpr const char GCedWithJSRef::kExpectedName[];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment