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 @@
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 {
public:
explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
void Trace(const internal::JSMemberBase& ref) {
void Trace(const TracedReferenceBase& ref) {
if (ref.IsEmptyThreadSafe()) return;
Visit(ref);
}
......@@ -245,7 +23,7 @@ class JSVisitor : public cppgc::Visitor {
protected:
using cppgc::Visitor::Visit;
virtual void Visit(const internal::JSMemberBase& ref) {}
virtual void Visit(const TracedReferenceBase& ref) {}
};
} // namespace v8
......@@ -253,8 +31,8 @@ class JSVisitor : public cppgc::Visitor {
namespace cppgc {
template <typename T>
struct TraceTrait<v8::JSMember<T>> {
static void Trace(Visitor* visitor, const v8::JSMember<T>* self) {
struct TraceTrait<v8::TracedReference<T>> {
static void Trace(Visitor* visitor, const v8::TracedReference<T>* self) {
static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
}
};
......
This diff is collapsed.
......@@ -993,42 +993,6 @@ i::Address* V8::GlobalizeTracedReference(i::Isolate* isolate, i::Address* obj,
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::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(from);
return result.location();
......@@ -11091,7 +11055,7 @@ void EmbedderHeapTracer::DecreaseAllocatedSize(size_t bytes) {
}
void EmbedderHeapTracer::RegisterEmbedderReference(
const TracedReferenceBase<v8::Data>& ref) {
const BasicTracedReference<v8::Data>& ref) {
if (ref.IsEmpty()) return;
i::Heap* const heap = reinterpret_cast<i::Isolate*>(isolate_)->heap();
......
......@@ -328,7 +328,7 @@ class CppGraphBuilderImpl final {
void Run();
void VisitForVisibility(State* parent, const HeapObjectHeader&);
void VisitForVisibility(State& parent, const JSMemberBase&);
void VisitForVisibility(State& parent, const TracedReferenceBase&);
void VisitRootForGraphBuilding(RootState&, const HeapObjectHeader&,
const cppgc::SourceLocation&);
void ProcessPendingObjects();
......@@ -360,7 +360,7 @@ class CppGraphBuilderImpl final {
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());
v8::Local<v8::Value> v8_value = ref.Get(cpp_heap_.isolate());
if (!v8_value.IsEmpty()) {
......@@ -462,7 +462,7 @@ class VisiblityVisitor final : public JSVisitor {
void VisitWeakContainer(const void* object,
cppgc::TraceDescriptor strong_desc,
cppgc::TraceDescriptor weak_desc, cppgc::WeakCallback,
const void*) {
const void*) final {
if (!weak_desc.callback) {
// Weak container does not contribute to liveness.
return;
......@@ -475,7 +475,7 @@ class VisiblityVisitor final : public JSVisitor {
}
// JS handling.
void Visit(const JSMemberBase& ref) final {
void Visit(const TracedReferenceBase& ref) final {
graph_builder_.VisitForVisibility(parent_scope_.ParentAsRegularState(),
ref);
}
......@@ -508,7 +508,7 @@ class GraphBuildingVisitor final : public JSVisitor {
void VisitWeakRoot(const void*, cppgc::TraceDescriptor, cppgc::WeakCallback,
const void*, const cppgc::SourceLocation&) final {}
// JS handling.
void Visit(const JSMemberBase& ref) final {
void Visit(const TracedReferenceBase& ref) final {
graph_builder_.AddEdge(parent_scope_.ParentAsRegularState(), ref);
}
......@@ -604,7 +604,7 @@ 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());
if (!v8_value.IsEmpty()) {
parent.MarkVisible();
......
......@@ -6,17 +6,16 @@
#define V8_HEAP_CPPGC_JS_UNIFIED_HEAP_MARKING_STATE_H_
#include "include/v8-cppgc.h"
#include "include/v8.h"
#include "src/heap/heap.h"
namespace v8 {
class JSMemberBase;
namespace internal {
class JSMemberBaseExtractor {
class BasicTracedReferenceExtractor {
public:
static Address* ObjectReference(const JSMemberBase& ref) {
static Address* ObjectReference(const TracedReferenceBase& ref) {
return reinterpret_cast<Address*>(ref.val_);
}
};
......@@ -28,15 +27,15 @@ class UnifiedHeapMarkingState {
UnifiedHeapMarkingState(const UnifiedHeapMarkingState&) = delete;
UnifiedHeapMarkingState& operator=(const UnifiedHeapMarkingState&) = delete;
inline void MarkAndPush(const JSMemberBase&);
inline void MarkAndPush(const TracedReferenceBase&);
private:
Heap& heap_;
};
void UnifiedHeapMarkingState::MarkAndPush(const JSMemberBase& ref) {
void UnifiedHeapMarkingState::MarkAndPush(const TracedReferenceBase& ref) {
heap_.RegisterExternallyReferencedObject(
JSMemberBaseExtractor::ObjectReference(ref));
BasicTracedReferenceExtractor::ObjectReference(ref));
}
} // namespace internal
......
......@@ -45,7 +45,7 @@ class UnifiedHeapVerificationVisitor final : public JSVisitor {
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.
}
......
......@@ -4,6 +4,7 @@
#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/heap.h"
#include "src/heap/cppgc/marking-state.h"
......@@ -53,15 +54,15 @@ void UnifiedHeapMarkingVisitorBase::HandleMovableReference(const void** slot) {
}
namespace {
void DeferredTraceJSMember(cppgc::Visitor* visitor, const void* ref) {
void DeferredTraceTracedReference(cppgc::Visitor* visitor, const void* ref) {
static_cast<JSVisitor*>(visitor)->Trace(
*static_cast<const internal::JSMemberBase*>(ref));
*static_cast<const TracedReferenceBase*>(ref));
}
} // namespace
void UnifiedHeapMarkingVisitorBase::Visit(const internal::JSMemberBase& ref) {
bool should_defer_tracing =
DeferTraceToMutatorThreadIfConcurrent(&ref, DeferredTraceJSMember, 0);
void UnifiedHeapMarkingVisitorBase::Visit(const TracedReferenceBase& ref) {
bool should_defer_tracing = DeferTraceToMutatorThreadIfConcurrent(
&ref, DeferredTraceTracedReference, 0);
if (!should_defer_tracing) unified_heap_marking_state_.MarkAndPush(ref);
}
......
......@@ -51,7 +51,7 @@ class V8_EXPORT_PRIVATE UnifiedHeapMarkingVisitorBase : public JSVisitor {
void HandleMovableReference(const void**) final;
// JS handling.
void Visit(const internal::JSMemberBase& ref) final;
void Visit(const TracedReferenceBase& ref) final;
MarkingStateBase& marking_state_;
UnifiedHeapMarkingState& unified_heap_marking_state_;
......
......@@ -750,7 +750,6 @@ class RuntimeCallTimer final {
V(Int8Array_New) \
V(Isolate_DateTimeConfigurationChangeNotification) \
V(Isolate_LocaleConfigurationChangeNotification) \
V(JSMemberBase_New) \
V(JSON_Parse) \
V(JSON_Stringify) \
V(Map_AsArray) \
......
......@@ -833,8 +833,8 @@ class EmbedderHeapTracerNoDestructorNonTracingClearing final
// Convention (for test): Objects that are optimized have their first field
// set as a back pointer.
TracedReferenceBase<v8::Value>* original_handle =
reinterpret_cast<TracedReferenceBase<v8::Value>*>(
BasicTracedReference<v8::Value>* original_handle =
reinterpret_cast<BasicTracedReference<v8::Value>*>(
v8::Object::GetAlignedPointerFromInternalField(
handle.As<v8::Object>(), 0));
original_handle->Reset();
......
......@@ -287,7 +287,6 @@ v8_source_set("unittests_sources") {
"heap/heap-utils.h",
"heap/index-generator-unittest.cc",
"heap/item-parallel-job-unittest.cc",
"heap/js-member-unittest.cc",
"heap/list-unittest.cc",
"heap/local-factory-unittest.cc",
"heap/local-heap-unittest.cc",
......@@ -299,6 +298,7 @@ v8_source_set("unittests_sources") {
"heap/safepoint-unittest.cc",
"heap/slot-set-unittest.cc",
"heap/spaces-unittest.cc",
"heap/traced-reference-unittest.cc",
"heap/unified-heap-snapshot-unittest.cc",
"heap/unified-heap-unittest.cc",
"heap/unified-heap-utils.cc",
......
......@@ -10,154 +10,154 @@
namespace v8 {
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::Context::Scope context_scope(context);
v8::JSMember<v8::Object> member;
v8::TracedReference<v8::Object> ref;
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
EXPECT_TRUE(member.IsEmpty());
EXPECT_NE(member, local);
member.Set(v8_isolate(), local);
EXPECT_FALSE(member.IsEmpty());
EXPECT_EQ(member, local);
EXPECT_TRUE(ref.IsEmpty());
EXPECT_NE(ref, local);
ref.Reset(v8_isolate(), local);
EXPECT_FALSE(ref.IsEmpty());
EXPECT_EQ(ref, local);
}
}
TEST_F(JSMemberTest, ConstructFromLocal) {
TEST_F(TracedReferenceTest, ConstructFromLocal) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local);
EXPECT_FALSE(member.IsEmpty());
EXPECT_EQ(member, local);
v8::TracedReference<v8::Object> ref(v8_isolate(), local);
EXPECT_FALSE(ref.IsEmpty());
EXPECT_EQ(ref, local);
}
}
TEST_F(JSMemberTest, Reset) {
TEST_F(TracedReferenceTest, Reset) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local);
EXPECT_FALSE(member.IsEmpty());
EXPECT_EQ(member, local);
member.Reset();
EXPECT_TRUE(member.IsEmpty());
EXPECT_NE(member, local);
v8::TracedReference<v8::Object> ref(v8_isolate(), local);
EXPECT_FALSE(ref.IsEmpty());
EXPECT_EQ(ref, local);
ref.Reset();
EXPECT_TRUE(ref.IsEmpty());
EXPECT_NE(ref, local);
}
}
TEST_F(JSMemberTest, Copy) {
TEST_F(TracedReferenceTest, Copy) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local);
v8::JSMember<v8::Object> member_copy1(member);
v8::JSMember<v8::Object> member_copy2 = member;
EXPECT_EQ(member, local);
EXPECT_EQ(member_copy1, local);
EXPECT_EQ(member_copy2, local);
v8::TracedReference<v8::Object> ref(v8_isolate(), local);
v8::TracedReference<v8::Object> ref_copy1(ref);
v8::TracedReference<v8::Object> ref_copy2 = ref;
EXPECT_EQ(ref, local);
EXPECT_EQ(ref_copy1, 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::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local);
v8::JSMember<v8::Value> member_copy1(member);
v8::JSMember<v8::Value> member_copy2 = member;
EXPECT_EQ(member, local);
EXPECT_EQ(member_copy1, local);
EXPECT_EQ(member_copy2, local);
v8::TracedReference<v8::Object> ref(v8_isolate(), local);
v8::TracedReference<v8::Value> ref_copy1(ref);
v8::TracedReference<v8::Value> ref_copy2 = ref;
EXPECT_EQ(ref, local);
EXPECT_EQ(ref_copy1, 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::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member(v8_isolate(), local);
v8::JSMember<v8::Object> member_moved1(std::move(member));
v8::JSMember<v8::Object> member_moved2 = std::move(member_moved1);
EXPECT_TRUE(member.IsEmpty());
EXPECT_TRUE(member_moved1.IsEmpty());
EXPECT_EQ(member_moved2, local);
v8::TracedReference<v8::Object> ref(v8_isolate(), local);
v8::TracedReference<v8::Object> ref_moved1(std::move(ref));
v8::TracedReference<v8::Object> ref_moved2 = std::move(ref_moved1);
EXPECT_TRUE(ref.IsEmpty());
EXPECT_TRUE(ref_moved1.IsEmpty());
EXPECT_EQ(ref_moved2, local);
}
}
TEST_F(JSMemberTest, MoveHeterogenous) {
TEST_F(TracedReferenceTest, MoveHeterogenous) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member1(v8_isolate(), local);
v8::JSMember<v8::Value> member_moved1(std::move(member1));
v8::JSMember<v8::Object> member2(v8_isolate(), local);
v8::JSMember<v8::Object> member_moved2 = std::move(member2);
EXPECT_TRUE(member1.IsEmpty());
EXPECT_EQ(member_moved1, local);
EXPECT_TRUE(member2.IsEmpty());
EXPECT_EQ(member_moved2, local);
v8::TracedReference<v8::Object> ref1(v8_isolate(), local);
v8::TracedReference<v8::Value> ref_moved1(std::move(ref1));
v8::TracedReference<v8::Object> ref2(v8_isolate(), local);
v8::TracedReference<v8::Object> ref_moved2 = std::move(ref2);
EXPECT_TRUE(ref1.IsEmpty());
EXPECT_EQ(ref_moved1, local);
EXPECT_TRUE(ref2.IsEmpty());
EXPECT_EQ(ref_moved2, local);
}
}
TEST_F(JSMemberTest, Equality) {
TEST_F(TracedReferenceTest, Equality) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local1 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member1(v8_isolate(), local1);
v8::JSMember<v8::Object> member2(v8_isolate(), local1);
EXPECT_EQ(member1, member2);
EXPECT_EQ(member2, member1);
v8::TracedReference<v8::Object> ref1(v8_isolate(), local1);
v8::TracedReference<v8::Object> ref2(v8_isolate(), local1);
EXPECT_EQ(ref1, ref2);
EXPECT_EQ(ref2, ref1);
v8::Local<v8::Object> local2 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member3(v8_isolate(), local2);
EXPECT_NE(member2, member3);
EXPECT_NE(member3, member2);
v8::TracedReference<v8::Object> ref3(v8_isolate(), local2);
EXPECT_NE(ref2, ref3);
EXPECT_NE(ref3, ref2);
}
}
TEST_F(JSMemberTest, EqualityHeterogenous) {
TEST_F(TracedReferenceTest, EqualityHeterogenous) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local1 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member1(v8_isolate(), local1);
v8::JSMember<v8::Value> member2(v8_isolate(), local1);
EXPECT_EQ(member1, member2);
EXPECT_EQ(member2, member1);
v8::TracedReference<v8::Object> ref1(v8_isolate(), local1);
v8::TracedReference<v8::Value> ref2(v8_isolate(), local1);
EXPECT_EQ(ref1, ref2);
EXPECT_EQ(ref2, ref1);
v8::Local<v8::Object> local2 =
v8::Local<v8::Object>::New(v8_isolate(), v8::Object::New(v8_isolate()));
v8::JSMember<v8::Object> member3(v8_isolate(), local2);
EXPECT_NE(member2, member3);
EXPECT_NE(member3, member2);
v8::TracedReference<v8::Object> ref3(v8_isolate(), local2);
EXPECT_NE(ref2, ref3);
EXPECT_NE(ref3, ref2);
}
}
......@@ -170,7 +170,7 @@ class JSVisitorForTesting final : public JSVisitor {
: JSVisitor(cppgc::internal::VisitorFactory::CreateKey()),
expected_object_(expected_object) {}
void Visit(const internal::JSMemberBase& ref) final {
void Visit(const TracedReferenceBase& ref) final {
EXPECT_EQ(ref, expected_object_);
visit_count_++;
}
......@@ -184,14 +184,14 @@ class JSVisitorForTesting final : public JSVisitor {
} // namespace
TEST_F(JSMemberTest, JSMemberTrace) {
TEST_F(TracedReferenceTest, TracedReferenceTrace) {
v8::Local<v8::Context> context = v8::Context::New(v8_isolate());
v8::Context::Scope context_scope(context);
{
v8::HandleScope handles(v8_isolate());
v8::Local<v8::Object> local =
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);
// Cast to cppgc::Visitor to ensure that we dispatch through the base
// visitor and use traits.
......
......@@ -293,11 +293,11 @@ class GCedWithJSRef : public cppgc::GarbageCollected<GCedWithJSRef> {
virtual void Trace(cppgc::Visitor* v) const { v->Trace(v8_object_); }
void SetV8Object(v8::Isolate* isolate, v8::Local<v8::Object> object) {
v8_object_.Set(isolate, object);
v8_object_.Reset(isolate, object);
}
private:
JSMember<v8::Object> v8_object_;
TracedReference<v8::Object> v8_object_;
};
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