Commit f6386018 authored by Michael Lippautz's avatar Michael Lippautz Committed by V8 LUCI CQ

[api] Remove TracedGlobal<>

Remove deprecated TracedGlobal<>, greatly simplifying handling of
traced references in general.

Also saves a word per v8::TracedReference as there's no need to keep a
possible callback around.

Bug: v8:12603
Change-Id: Ice35d7906775b912d02e97a27a722b3e1cec28d9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3532251Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79589}
parent 574c2809
...@@ -34,29 +34,22 @@ class V8_EXPORT EmbedderRootsHandler { ...@@ -34,29 +34,22 @@ class V8_EXPORT EmbedderRootsHandler {
virtual ~EmbedderRootsHandler() = default; virtual ~EmbedderRootsHandler() = default;
/** /**
* Returns true if the TracedGlobal handle should be considered as root for * Returns true if the |TracedReference| handle should be considered as root
* the currently running non-tracing garbage collection and false otherwise. * for the currently running non-tracing garbage collection and false
* The default implementation will keep all TracedGlobal references as roots. * otherwise. The default implementation will keep all |TracedReference|
* references as roots.
* *
* If this returns false, then V8 may decide that the object referred to by * If this returns false, then V8 may decide that the object referred to by
* such a handle is reclaimed. In that case: * such a handle is reclaimed. In that case, V8 calls |ResetRoot()| for the
* - No action is required if handles are used with destructors, i.e., by just * |TracedReference|.
* using |TracedGlobal|.
* - When run without destructors, i.e., by using |TracedReference|, V8 calls
* |ResetRoot|.
* *
* Note that the |handle| is different from the handle that the embedder holds * Note that the `handle` is different from the handle that the embedder holds
* for retaining the object. The embedder may use |WrapperClassId()| to * for retaining the object. The embedder may use |WrapperClassId()| to
* distinguish cases where it wants handles to be treated as roots from not * distinguish cases where it wants handles to be treated as roots from not
* being treated as roots. * being treated as roots.
*/ */
virtual bool IsRoot(const v8::TracedReference<v8::Value>& handle) = 0; virtual bool IsRoot(const v8::TracedReference<v8::Value>& handle) = 0;
V8_DEPRECATED("See v8::TracedGlobal class comment.")
virtual bool IsRoot(const v8::TracedGlobal<v8::Value>& handle) {
return true;
}
/** /**
* Used in combination with |IsRoot|. Called by V8 when an * Used in combination with |IsRoot|. Called by V8 when an
* object that is backed by a handle is reclaimed by a non-tracing garbage * object that is backed by a handle is reclaimed by a non-tracing garbage
...@@ -87,13 +80,11 @@ class V8_EXPORT EmbedderHeapTracer { ...@@ -87,13 +80,11 @@ class V8_EXPORT EmbedderHeapTracer {
}; };
/** /**
* Interface for iterating through TracedGlobal handles. * Interface for iterating through |TracedReference| handles.
*/ */
class V8_EXPORT TracedGlobalHandleVisitor { class V8_EXPORT TracedGlobalHandleVisitor {
public: public:
virtual ~TracedGlobalHandleVisitor() = default; virtual ~TracedGlobalHandleVisitor() = default;
V8_DEPRECATED("See v8::TracedGlobal class comment.")
virtual void VisitTracedGlobalHandle(const TracedGlobal<Value>& handle) {}
virtual void VisitTracedReference(const TracedReference<Value>& handle) {} virtual void VisitTracedReference(const TracedReference<Value>& handle) {}
}; };
...@@ -118,8 +109,8 @@ class V8_EXPORT EmbedderHeapTracer { ...@@ -118,8 +109,8 @@ class V8_EXPORT EmbedderHeapTracer {
virtual ~EmbedderHeapTracer() = default; virtual ~EmbedderHeapTracer() = default;
/** /**
* Iterates all TracedGlobal handles created for the v8::Isolate the tracer is * Iterates all |TracedReference| handles created for the |v8::Isolate| the
* attached to. * tracer is attached to.
*/ */
void IterateTracedGlobalHandles(TracedGlobalHandleVisitor* visitor); void IterateTracedGlobalHandles(TracedGlobalHandleVisitor* visitor);
...@@ -194,8 +185,6 @@ class V8_EXPORT EmbedderHeapTracer { ...@@ -194,8 +185,6 @@ class V8_EXPORT EmbedderHeapTracer {
*/ */
virtual bool IsRootForNonTracingGC( virtual bool IsRootForNonTracingGC(
const v8::TracedReference<v8::Value>& handle); const v8::TracedReference<v8::Value>& handle);
V8_DEPRECATED("See v8::TracedGlobal class comment.")
virtual bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle);
/** /**
* See documentation on EmbedderRootsHandler. * See documentation on EmbedderRootsHandler.
......
...@@ -46,8 +46,6 @@ class String; ...@@ -46,8 +46,6 @@ class String;
template <class F> template <class F>
class Traced; class Traced;
template <class F> template <class F>
class TracedGlobal;
template <class F>
class TracedReference; class TracedReference;
class TracedReferenceBase; class TracedReferenceBase;
class Utils; class Utils;
...@@ -312,8 +310,6 @@ class Local { ...@@ -312,8 +310,6 @@ class Local {
template <class F> template <class F>
friend class Traced; friend class Traced;
template <class F> template <class F>
friend class TracedGlobal;
template <class F>
friend class BasicTracedReference; friend class BasicTracedReference;
template <class F> template <class F>
friend class TracedReference; friend class TracedReference;
......
...@@ -493,7 +493,7 @@ class V8_EXPORT Object : public Value { ...@@ -493,7 +493,7 @@ class V8_EXPORT Object : public Value {
return object.val_->GetAlignedPointerFromInternalField(index); return object.val_->GetAlignedPointerFromInternalField(index);
} }
/** Same as above, but works for TracedGlobal. */ /** Same as above, but works for TracedReference. */
V8_INLINE static void* GetAlignedPointerFromInternalField( V8_INLINE static void* GetAlignedPointerFromInternalField(
const BasicTracedReference<Object>& object, int index) { const BasicTracedReference<Object>& object, int index) {
return object->GetAlignedPointerFromInternalField(index); return object->GetAlignedPointerFromInternalField(index);
......
...@@ -27,8 +27,6 @@ namespace internal { ...@@ -27,8 +27,6 @@ namespace internal {
class BasicTracedReferenceExtractor; class BasicTracedReferenceExtractor;
enum class GlobalHandleDestructionMode { kWithDestructor, kWithoutDestructor };
enum class GlobalHandleStoreMode { enum class GlobalHandleStoreMode {
kInitializingStore, kInitializingStore,
kAssigningStore, kAssigningStore,
...@@ -36,25 +34,15 @@ enum class GlobalHandleStoreMode { ...@@ -36,25 +34,15 @@ enum class GlobalHandleStoreMode {
V8_EXPORT internal::Address* GlobalizeTracedReference( V8_EXPORT internal::Address* GlobalizeTracedReference(
internal::Isolate* isolate, internal::Address* handle, internal::Isolate* isolate, internal::Address* handle,
internal::Address* slot, GlobalHandleDestructionMode destruction_mode, internal::Address* slot, GlobalHandleStoreMode store_mode);
GlobalHandleStoreMode store_mode); V8_EXPORT void MoveTracedReference(internal::Address** from,
V8_EXPORT void MoveTracedGlobalReference(internal::Address** from, internal::Address** to);
internal::Address** to); V8_EXPORT void CopyTracedReference(const internal::Address* const* from,
V8_EXPORT void CopyTracedGlobalReference(const internal::Address* const* from, internal::Address** to);
internal::Address** to); V8_EXPORT void DisposeTracedReference(internal::Address* global_handle);
V8_EXPORT void DisposeTracedGlobal(internal::Address* global_handle);
V8_EXPORT void SetFinalizationCallbackTraced(
internal::Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback);
} // namespace internal } // namespace internal
/**
* Deprecated. Use |TracedReference<T>| instead.
*/
template <typename T>
struct TracedGlobalTrait {};
class TracedReferenceBase { class TracedReferenceBase {
public: public:
/** /**
...@@ -138,9 +126,8 @@ class TracedReferenceBase { ...@@ -138,9 +126,8 @@ class TracedReferenceBase {
* |v8::EmbedderRootsHandler::IsRoot()| whether the handle should * |v8::EmbedderRootsHandler::IsRoot()| whether the handle should
* be treated as root or not. * be treated as root or not.
* *
* Note that the base class cannot be instantiated itself. Choose from * Note that the base class cannot be instantiated itself, use |TracedReference|
* - TracedGlobal * instead.
* - TracedReference
*/ */
template <typename T> template <typename T>
class BasicTracedReference : public TracedReferenceBase { class BasicTracedReference : public TracedReferenceBase {
...@@ -177,7 +164,6 @@ class BasicTracedReference : public TracedReferenceBase { ...@@ -177,7 +164,6 @@ class BasicTracedReference : public TracedReferenceBase {
V8_INLINE static internal::Address* New( V8_INLINE static internal::Address* New(
Isolate* isolate, T* that, void* slot, Isolate* isolate, T* that, void* slot,
internal::GlobalHandleDestructionMode destruction_mode,
internal::GlobalHandleStoreMode store_mode); internal::GlobalHandleStoreMode store_mode);
friend class EmbedderHeapTracer; friend class EmbedderHeapTracer;
...@@ -185,8 +171,6 @@ class BasicTracedReference : public TracedReferenceBase { ...@@ -185,8 +171,6 @@ class BasicTracedReference : public TracedReferenceBase {
friend class Local; friend class Local;
friend class Object; friend class Object;
template <typename F> template <typename F>
friend class TracedGlobal;
template <typename F>
friend class TracedReference; friend class TracedReference;
template <typename F> template <typename F>
friend class BasicTracedReference; friend class BasicTracedReference;
...@@ -194,146 +178,6 @@ class BasicTracedReference : public TracedReferenceBase { ...@@ -194,146 +178,6 @@ class BasicTracedReference : public TracedReferenceBase {
friend class ReturnValue; friend class ReturnValue;
}; };
/**
* A traced handle with destructor that clears the handle. For more details see
* BasicTracedReference.
*
* This type is being deprecated and embedders are encouraged to use
* `v8::TracedReference` in combination with `v8::CppHeap`. If this is not
* possible, the following provides feature parity:
*
* \code
* template <typename T>
* struct TracedGlobalPolyfill {
* v8::TracedReference<T> traced_reference;
* v8::Global<T> weak_reference_for_callback;
* };
* \endcode
*
* In this example, `weak_reference_for_callback` can be used to emulate
* `SetFinalizationCallback()`.
*/
template <typename T>
class TracedGlobal : public BasicTracedReference<T> {
public:
using BasicTracedReference<T>::Reset;
/**
* Destructor resetting the handle.Is
*/
~TracedGlobal() { this->Reset(); }
/**
* An empty TracedGlobal without storage cell.
*/
V8_DEPRECATED("See class comment.")
TracedGlobal() : BasicTracedReference<T>() {}
/**
* Construct a TracedGlobal from a Local.
*
* When the Local is non-empty, a new storage cell is created
* pointing to the same object.
*/
template <class S>
V8_DEPRECATED("See class comment.")
TracedGlobal(Isolate* isolate, Local<S> that) : BasicTracedReference<T>() {
this->val_ =
this->New(isolate, that.val_, &this->val_,
internal::GlobalHandleDestructionMode::kWithDestructor,
internal::GlobalHandleStoreMode::kInitializingStore);
static_assert(std::is_base_of<T, S>::value, "type check");
}
/**
* Move constructor initializing TracedGlobal from an existing one.
*/
V8_INLINE TracedGlobal(TracedGlobal&& other) noexcept {
// Forward to operator=.
*this = std::move(other);
}
/**
* Move constructor initializing TracedGlobal from an existing one.
*/
template <typename S>
V8_INLINE TracedGlobal(TracedGlobal<S>&& other) noexcept {
// Forward to operator=.
*this = std::move(other);
}
/**
* Copy constructor initializing TracedGlobal from an existing one.
*/
V8_INLINE TracedGlobal(const TracedGlobal& other) {
// Forward to operator=;
*this = other;
}
/**
* Copy constructor initializing TracedGlobal from an existing one.
*/
template <typename S>
V8_INLINE TracedGlobal(const TracedGlobal<S>& other) {
// Forward to operator=;
*this = other;
}
/**
* Move assignment operator initializing TracedGlobal from an existing one.
*/
V8_INLINE TracedGlobal& operator=(TracedGlobal&& rhs) noexcept;
/**
* Move assignment operator initializing TracedGlobal from an existing one.
*/
template <class S>
V8_INLINE TracedGlobal& operator=(TracedGlobal<S>&& rhs) noexcept;
/**
* Copy assignment operator initializing TracedGlobal from an existing one.
*
* Note: Prohibited when |other| has a finalization callback set through
* |SetFinalizationCallback|.
*/
V8_INLINE TracedGlobal& operator=(const TracedGlobal& rhs);
/**
* Copy assignment operator initializing TracedGlobal from an existing one.
*
* Note: Prohibited when |other| has a finalization callback set through
* |SetFinalizationCallback|.
*/
template <class S>
V8_INLINE TracedGlobal& operator=(const TracedGlobal<S>& rhs);
/**
* If non-empty, destroy the underlying storage cell and create a new one with
* the contents of other if other is non empty
*/
template <class S>
V8_INLINE void Reset(Isolate* isolate, const Local<S>& other);
template <class S>
V8_INLINE TracedGlobal<S>& As() const {
return reinterpret_cast<TracedGlobal<S>&>(
const_cast<TracedGlobal<T>&>(*this));
}
/**
* Adds a finalization callback to the handle. The type of this callback is
* similar to WeakCallbackType::kInternalFields, i.e., it will pass the
* parameter and the first two internal fields of the object.
*
* The callback is then supposed to reset the handle in the callback. No
* further V8 API may be called in this callback. In case additional work
* involving V8 needs to be done, a second callback can be scheduled using
* WeakCallbackInfo<void>::SetSecondPassCallback.
*/
V8_INLINE void SetFinalizationCallback(
void* parameter, WeakCallbackInfo<void>::Callback callback);
};
/** /**
* 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
...@@ -363,10 +207,8 @@ class TracedReference : public BasicTracedReference<T> { ...@@ -363,10 +207,8 @@ class TracedReference : public BasicTracedReference<T> {
*/ */
template <class S> template <class S>
TracedReference(Isolate* isolate, Local<S> that) : BasicTracedReference<T>() { TracedReference(Isolate* isolate, Local<S> that) : BasicTracedReference<T>() {
this->val_ = this->val_ = this->New(isolate, that.val_, &this->val_,
this->New(isolate, that.val_, &this->val_, internal::GlobalHandleStoreMode::kInitializingStore);
internal::GlobalHandleDestructionMode::kWithoutDestructor,
internal::GlobalHandleStoreMode::kInitializingStore);
static_assert(std::is_base_of<T, S>::value, "type check"); static_assert(std::is_base_of<T, S>::value, "type check");
} }
...@@ -409,23 +251,23 @@ class TracedReference : public BasicTracedReference<T> { ...@@ -409,23 +251,23 @@ class TracedReference : public BasicTracedReference<T> {
} }
/** /**
* Move assignment operator initializing TracedGlobal from an existing one. * Move assignment operator initializing TracedReference from an existing one.
*/ */
V8_INLINE TracedReference& operator=(TracedReference&& rhs) noexcept; V8_INLINE TracedReference& operator=(TracedReference&& rhs) noexcept;
/** /**
* Move assignment operator initializing TracedGlobal from an existing one. * Move assignment operator initializing TracedReference from an existing one.
*/ */
template <class S> template <class S>
V8_INLINE TracedReference& operator=(TracedReference<S>&& rhs) noexcept; V8_INLINE TracedReference& operator=(TracedReference<S>&& rhs) noexcept;
/** /**
* Copy assignment operator initializing TracedGlobal from an existing one. * Copy assignment operator initializing TracedReference from an existing one.
*/ */
V8_INLINE TracedReference& operator=(const TracedReference& rhs); V8_INLINE TracedReference& operator=(const TracedReference& rhs);
/** /**
* Copy assignment operator initializing TracedGlobal from an existing one. * Copy assignment operator initializing TracedReference from an existing one.
*/ */
template <class S> template <class S>
V8_INLINE TracedReference& operator=(const TracedReference<S>& rhs); V8_INLINE TracedReference& operator=(const TracedReference<S>& rhs);
...@@ -448,18 +290,17 @@ class TracedReference : public BasicTracedReference<T> { ...@@ -448,18 +290,17 @@ class TracedReference : public BasicTracedReference<T> {
template <class T> template <class T>
internal::Address* BasicTracedReference<T>::New( internal::Address* BasicTracedReference<T>::New(
Isolate* isolate, T* that, void* slot, Isolate* isolate, T* that, void* slot,
internal::GlobalHandleDestructionMode destruction_mode,
internal::GlobalHandleStoreMode store_mode) { internal::GlobalHandleStoreMode store_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 internal::GlobalizeTracedReference( return internal::GlobalizeTracedReference(
reinterpret_cast<internal::Isolate*>(isolate), p, reinterpret_cast<internal::Isolate*>(isolate), p,
reinterpret_cast<internal::Address*>(slot), destruction_mode, store_mode); reinterpret_cast<internal::Address*>(slot), store_mode);
} }
void TracedReferenceBase::Reset() { void TracedReferenceBase::Reset() {
if (IsEmpty()) return; if (IsEmpty()) return;
internal::DisposeTracedGlobal(reinterpret_cast<internal::Address*>(val_)); internal::DisposeTracedReference(reinterpret_cast<internal::Address*>(val_));
SetSlotThreadSafe(nullptr); SetSlotThreadSafe(nullptr);
} }
...@@ -513,7 +354,6 @@ void TracedReference<T>::Reset(Isolate* isolate, const Local<S>& other) { ...@@ -513,7 +354,6 @@ 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_,
internal::GlobalHandleDestructionMode::kWithoutDestructor,
internal::GlobalHandleStoreMode::kAssigningStore)); internal::GlobalHandleStoreMode::kAssigningStore));
} }
...@@ -539,7 +379,7 @@ template <class T> ...@@ -539,7 +379,7 @@ template <class T>
TracedReference<T>& TracedReference<T>::operator=( TracedReference<T>& TracedReference<T>::operator=(
TracedReference&& rhs) noexcept { TracedReference&& rhs) noexcept {
if (this != &rhs) { if (this != &rhs) {
internal::MoveTracedGlobalReference( internal::MoveTracedReference(
reinterpret_cast<internal::Address**>(&rhs.val_), reinterpret_cast<internal::Address**>(&rhs.val_),
reinterpret_cast<internal::Address**>(&this->val_)); reinterpret_cast<internal::Address**>(&this->val_));
} }
...@@ -551,7 +391,7 @@ TracedReference<T>& TracedReference<T>::operator=(const TracedReference& rhs) { ...@@ -551,7 +391,7 @@ TracedReference<T>& TracedReference<T>::operator=(const TracedReference& rhs) {
if (this != &rhs) { if (this != &rhs) {
this->Reset(); this->Reset();
if (rhs.val_ != nullptr) { if (rhs.val_ != nullptr) {
internal::CopyTracedGlobalReference( internal::CopyTracedReference(
reinterpret_cast<const internal::Address* const*>(&rhs.val_), reinterpret_cast<const internal::Address* const*>(&rhs.val_),
reinterpret_cast<internal::Address**>(&this->val_)); reinterpret_cast<internal::Address**>(&this->val_));
} }
...@@ -575,63 +415,6 @@ uint16_t TracedReferenceBase::WrapperClassId() const { ...@@ -575,63 +415,6 @@ uint16_t TracedReferenceBase::WrapperClassId() const {
return *reinterpret_cast<uint16_t*>(addr); return *reinterpret_cast<uint16_t*>(addr);
} }
template <class T>
template <class S>
void TracedGlobal<T>::Reset(Isolate* isolate, const Local<S>& other) {
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_,
internal::GlobalHandleDestructionMode::kWithDestructor,
internal::GlobalHandleStoreMode::kAssigningStore);
}
template <class T>
template <class S>
TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal<S>&& rhs) noexcept {
static_assert(std::is_base_of<T, S>::value, "type check");
*this = std::move(rhs.template As<T>());
return *this;
}
template <class T>
template <class S>
TracedGlobal<T>& TracedGlobal<T>::operator=(const TracedGlobal<S>& rhs) {
static_assert(std::is_base_of<T, S>::value, "type check");
*this = rhs.template As<T>();
return *this;
}
template <class T>
TracedGlobal<T>& TracedGlobal<T>::operator=(TracedGlobal&& rhs) noexcept {
if (this != &rhs) {
internal::MoveTracedGlobalReference(
reinterpret_cast<internal::Address**>(&rhs.val_),
reinterpret_cast<internal::Address**>(&this->val_));
}
return *this;
}
template <class T>
TracedGlobal<T>& TracedGlobal<T>::operator=(const TracedGlobal& rhs) {
if (this != &rhs) {
this->Reset();
if (rhs.val_ != nullptr) {
internal::CopyTracedGlobalReference(
reinterpret_cast<const internal::Address* const*>(&rhs.val_),
reinterpret_cast<internal::Address**>(&this->val_));
}
}
return *this;
}
template <class T>
void TracedGlobal<T>::SetFinalizationCallback(
void* parameter, typename WeakCallbackInfo<void>::Callback callback) {
internal::SetFinalizationCallbackTraced(
reinterpret_cast<internal::Address*>(this->val_), parameter, callback);
}
} // namespace v8 } // namespace v8
#endif // INCLUDE_V8_TRACED_HANDLE_H_ #endif // INCLUDE_V8_TRACED_HANDLE_H_
...@@ -807,17 +807,16 @@ void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory, ...@@ -807,17 +807,16 @@ void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory,
namespace internal { namespace internal {
i::Address* GlobalizeTracedReference( i::Address* GlobalizeTracedReference(i::Isolate* isolate, i::Address* obj,
i::Isolate* isolate, i::Address* obj, internal::Address* slot, internal::Address* slot,
GlobalHandleDestructionMode destruction_mode, GlobalHandleStoreMode store_mode) {
GlobalHandleStoreMode store_mode) {
LOG_API(isolate, TracedGlobal, New); LOG_API(isolate, TracedGlobal, New);
#ifdef DEBUG #ifdef DEBUG
Utils::ApiCheck((slot != nullptr), "v8::GlobalizeTracedReference", Utils::ApiCheck((slot != nullptr), "v8::GlobalizeTracedReference",
"the address slot must be not null"); "the address slot must be not null");
#endif #endif
i::Handle<i::Object> result = isolate->global_handles()->CreateTraced( i::Handle<i::Object> result =
*obj, slot, destruction_mode, store_mode); isolate->global_handles()->CreateTraced(*obj, slot, store_mode);
#ifdef VERIFY_HEAP #ifdef VERIFY_HEAP
if (i::FLAG_verify_heap) { if (i::FLAG_verify_heap) {
i::Object(*obj).ObjectVerify(isolate); i::Object(*obj).ObjectVerify(isolate);
...@@ -826,24 +825,17 @@ i::Address* GlobalizeTracedReference( ...@@ -826,24 +825,17 @@ i::Address* GlobalizeTracedReference(
return result.location(); return result.location();
} }
void MoveTracedGlobalReference(internal::Address** from, void MoveTracedReference(internal::Address** from, internal::Address** to) {
internal::Address** to) { GlobalHandles::MoveTracedReference(from, to);
GlobalHandles::MoveTracedGlobal(from, to);
} }
void CopyTracedGlobalReference(const internal::Address* const* from, void CopyTracedReference(const internal::Address* const* from,
internal::Address** to) { internal::Address** to) {
GlobalHandles::CopyTracedGlobal(from, to); GlobalHandles::CopyTracedReference(from, to);
} }
void DisposeTracedGlobal(internal::Address* location) { void DisposeTracedReference(internal::Address* location) {
GlobalHandles::DestroyTraced(location); GlobalHandles::DestroyTracedReference(location);
}
void SetFinalizationCallbackTraced(internal::Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback) {
GlobalHandles::SetFinalizationCallbackForTraced(location, parameter,
callback);
} }
} // namespace internal } // namespace internal
...@@ -10277,11 +10269,6 @@ bool EmbedderHeapTracer::IsRootForNonTracingGC( ...@@ -10277,11 +10269,6 @@ bool EmbedderHeapTracer::IsRootForNonTracingGC(
return true; return true;
} }
bool EmbedderHeapTracer::IsRootForNonTracingGC(
const v8::TracedGlobal<v8::Value>& handle) {
return true;
}
void EmbedderHeapTracer::ResetHandleInNonTracingGC( void EmbedderHeapTracer::ResetHandleInNonTracingGC(
const v8::TracedReference<v8::Value>& handle) { const v8::TracedReference<v8::Value>& handle) {
UNREACHABLE(); UNREACHABLE();
......
...@@ -33,10 +33,6 @@ namespace internal { ...@@ -33,10 +33,6 @@ namespace internal {
namespace { namespace {
// Specifies whether V8 expects the holder memory of a global handle to be live
// or dead.
enum class HandleHolder { kLive, kDead };
constexpr size_t kBlockSize = 256; constexpr size_t kBlockSize = 256;
} // namespace } // namespace
...@@ -574,8 +570,7 @@ class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> { ...@@ -574,8 +570,7 @@ class GlobalHandles::Node final : public NodeBase<GlobalHandles::Node> {
set_state(NEAR_DEATH); set_state(NEAR_DEATH);
} }
void ResetPhantomHandle(HandleHolder handle_holder) { void ResetPhantomHandle() {
DCHECK_EQ(HandleHolder::kLive, handle_holder);
DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type()); DCHECK_EQ(PHANTOM_WEAK_RESET_HANDLE, weakness_type());
DCHECK_EQ(PENDING, state()); DCHECK_EQ(PENDING, state());
DCHECK_NULL(weak_callback_); DCHECK_NULL(weak_callback_);
...@@ -653,7 +648,6 @@ class GlobalHandles::TracedNode final ...@@ -653,7 +648,6 @@ class GlobalHandles::TracedNode final
void MarkAsUsed() { set_state(NORMAL); } void MarkAsUsed() { set_state(NORMAL); }
bool IsInUse() const { return state() != FREE; } bool IsInUse() const { return state() != FREE; }
bool IsRetainer() const { return state() == NORMAL; } bool IsRetainer() const { return state() == NORMAL; }
bool IsPhantomResetHandle() const { return callback_ == nullptr; }
bool is_in_young_list() const { return IsInYoungList::decode(flags_); } bool is_in_young_list() const { return IsInYoungList::decode(flags_); }
void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); } void set_in_young_list(bool v) { flags_ = IsInYoungList::update(flags_, v); }
...@@ -661,9 +655,6 @@ class GlobalHandles::TracedNode final ...@@ -661,9 +655,6 @@ class GlobalHandles::TracedNode final
bool is_root() const { return IsRoot::decode(flags_); } bool is_root() const { return IsRoot::decode(flags_); }
void set_root(bool v) { flags_ = IsRoot::update(flags_, v); } void set_root(bool v) { flags_ = IsRoot::update(flags_, v); }
bool has_destructor() const { return HasDestructor::decode(flags_); }
void set_has_destructor(bool v) { flags_ = HasDestructor::update(flags_, v); }
bool markbit() const { return Markbit::decode(flags_); } bool markbit() const { return Markbit::decode(flags_); }
void clear_markbit() { flags_ = Markbit::update(flags_, false); } void clear_markbit() { flags_ = Markbit::update(flags_, false); }
void set_markbit() { flags_ = Markbit::update(flags_, true); } void set_markbit() { flags_ = Markbit::update(flags_, true); }
...@@ -673,44 +664,10 @@ class GlobalHandles::TracedNode final ...@@ -673,44 +664,10 @@ class GlobalHandles::TracedNode final
void clear_object() { object_ = kNullAddress; } void clear_object() { object_ = kNullAddress; }
void SetFinalizationCallback(void* parameter,
WeakCallbackInfo<void>::Callback callback) {
set_parameter(parameter);
callback_ = callback;
}
bool HasFinalizationCallback() const { return callback_ != nullptr; }
void CopyObjectReference(const TracedNode& other) { object_ = other.object_; } void CopyObjectReference(const TracedNode& other) { object_ = other.object_; }
void CollectPhantomCallbackData( void ResetPhantomHandle() {
std::vector<std::pair<TracedNode*, PendingPhantomCallback>>*
pending_phantom_callbacks) {
DCHECK(IsInUse()); DCHECK(IsInUse());
DCHECK_NOT_NULL(callback_);
void* embedder_fields[v8::kEmbedderFieldsInWeakCallback] = {nullptr,
nullptr};
ExtractInternalFields(JSObject::cast(object()), embedder_fields,
v8::kEmbedderFieldsInWeakCallback);
// Zap with something dangerous.
location().store(Object(0xCA11));
pending_phantom_callbacks->push_back(std::make_pair(
this, PendingPhantomCallback(callback_, parameter(), embedder_fields)));
set_state(NEAR_DEATH);
}
void ResetPhantomHandle(HandleHolder handle_holder) {
DCHECK(IsInUse());
// Even if the handle holder should be alive, the back reference may have
// been cleared which prevents the handle from being reclaimed at this
// point. This can happen for explicitly reset handles during incremental
// marking that then cannot be reclaimed during Scavenge.
if (handle_holder == HandleHolder::kLive && data_.parameter) {
Address** handle = reinterpret_cast<Address**>(data_.parameter);
*handle = nullptr;
}
NodeSpace<TracedNode>::Release(this); NodeSpace<TracedNode>::Release(this);
DCHECK(!IsInUse()); DCHECK(!IsInUse());
} }
...@@ -721,27 +678,21 @@ class GlobalHandles::TracedNode final ...@@ -721,27 +678,21 @@ class GlobalHandles::TracedNode final
using NodeState = base::BitField8<State, 0, 2>; using NodeState = base::BitField8<State, 0, 2>;
using IsInYoungList = NodeState::Next<bool, 1>; using IsInYoungList = NodeState::Next<bool, 1>;
using IsRoot = IsInYoungList::Next<bool, 1>; using IsRoot = IsInYoungList::Next<bool, 1>;
using HasDestructor = IsRoot::Next<bool, 1>; using Markbit = IsRoot::Next<bool, 1>;
using Markbit = HasDestructor::Next<bool, 1>;
using IsOnStack = Markbit::Next<bool, 1>; using IsOnStack = Markbit::Next<bool, 1>;
void ClearImplFields() { void ClearImplFields() {
set_root(true); set_root(true);
// Nodes are black allocated for simplicity. // Nodes are black allocated for simplicity.
set_markbit(); set_markbit();
callback_ = nullptr;
set_is_on_stack(false); set_is_on_stack(false);
set_has_destructor(false);
} }
void CheckImplFieldsAreCleared() const { void CheckImplFieldsAreCleared() const {
DCHECK(is_root()); DCHECK(is_root());
DCHECK(markbit()); DCHECK(markbit());
DCHECK_NULL(callback_);
} }
WeakCallbackInfo<void>::Callback callback_;
friend class NodeBase<GlobalHandles::TracedNode>; friend class NodeBase<GlobalHandles::TracedNode>;
}; };
...@@ -902,9 +853,6 @@ void GlobalHandles::TracedNode::Verify(GlobalHandles* global_handles, ...@@ -902,9 +853,6 @@ void GlobalHandles::TracedNode::Verify(GlobalHandles* global_handles,
#ifdef DEBUG #ifdef DEBUG
const TracedNode* node = FromLocation(*slot); const TracedNode* node = FromLocation(*slot);
DCHECK(node->IsInUse()); DCHECK(node->IsInUse());
DCHECK_IMPLIES(!node->has_destructor(), nullptr == node->parameter());
DCHECK_IMPLIES(node->has_destructor() && !node->HasFinalizationCallback(),
node->parameter());
bool slot_on_stack = global_handles->on_stack_nodes_->IsOnStack( bool slot_on_stack = global_handles->on_stack_nodes_->IsOnStack(
reinterpret_cast<uintptr_t>(slot)); reinterpret_cast<uintptr_t>(slot));
DCHECK_EQ(slot_on_stack, node->is_on_stack()); DCHECK_EQ(slot_on_stack, node->is_on_stack());
...@@ -971,17 +919,16 @@ Handle<Object> GlobalHandles::Create(Address value) { ...@@ -971,17 +919,16 @@ Handle<Object> GlobalHandles::Create(Address value) {
return Create(Object(value)); return Create(Object(value));
} }
Handle<Object> GlobalHandles::CreateTraced( Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot,
Object value, Address* slot, GlobalHandleDestructionMode destruction_mode, GlobalHandleStoreMode store_mode) {
GlobalHandleStoreMode store_mode) {
return CreateTraced( return CreateTraced(
value, slot, destruction_mode, store_mode, value, slot, store_mode,
on_stack_nodes_->IsOnStack(reinterpret_cast<uintptr_t>(slot))); on_stack_nodes_->IsOnStack(reinterpret_cast<uintptr_t>(slot)));
} }
Handle<Object> GlobalHandles::CreateTraced( Handle<Object> GlobalHandles::CreateTraced(Object value, Address* slot,
Object value, Address* slot, GlobalHandleDestructionMode destruction_mode, GlobalHandleStoreMode store_mode,
GlobalHandleStoreMode store_mode, bool is_on_stack) { bool is_on_stack) {
GlobalHandles::TracedNode* result; GlobalHandles::TracedNode* result;
if (is_on_stack) { if (is_on_stack) {
result = on_stack_nodes_->Acquire(value, reinterpret_cast<uintptr_t>(slot)); result = on_stack_nodes_->Acquire(value, reinterpret_cast<uintptr_t>(slot));
...@@ -995,17 +942,13 @@ Handle<Object> GlobalHandles::CreateTraced( ...@@ -995,17 +942,13 @@ Handle<Object> GlobalHandles::CreateTraced(
WriteBarrier::MarkingFromGlobalHandle(value); WriteBarrier::MarkingFromGlobalHandle(value);
} }
} }
const bool has_destructor = result->set_parameter(nullptr);
destruction_mode == GlobalHandleDestructionMode::kWithDestructor;
result->set_has_destructor(has_destructor);
result->set_parameter(has_destructor ? slot : nullptr);
return result->handle(); return result->handle();
} }
Handle<Object> GlobalHandles::CreateTraced( Handle<Object> GlobalHandles::CreateTraced(Address value, Address* slot,
Address value, Address* slot, GlobalHandleDestructionMode destruction_mode, GlobalHandleStoreMode store_mode) {
GlobalHandleStoreMode store_mode) { return CreateTraced(Object(value), slot, store_mode);
return CreateTraced(Object(value), slot, destruction_mode, store_mode);
} }
Handle<Object> GlobalHandles::CopyGlobal(Address* location) { Handle<Object> GlobalHandles::CopyGlobal(Address* location) {
...@@ -1028,23 +971,15 @@ void SetSlotThreadSafe(Address** slot, Address* val) { ...@@ -1028,23 +971,15 @@ void SetSlotThreadSafe(Address** slot, Address* val) {
} // namespace } // namespace
// static // static
void GlobalHandles::CopyTracedGlobal(const Address* const* from, Address** to) { void GlobalHandles::CopyTracedReference(const Address* const* from,
Address** to) {
DCHECK_NOT_NULL(*from); DCHECK_NOT_NULL(*from);
DCHECK_NULL(*to); DCHECK_NULL(*to);
const TracedNode* node = TracedNode::FromLocation(*from); const TracedNode* node = TracedNode::FromLocation(*from);
// Copying a traced handle with finalization callback is prohibited because
// the callback may require knowing about multiple copies of the traced
// handle.
CHECK_WITH_MSG(!node->HasFinalizationCallback(),
"Copying of references is not supported when "
"SetFinalizationCallback is set.");
GlobalHandles* global_handles = GlobalHandles* global_handles =
GlobalHandles::From(const_cast<TracedNode*>(node)); GlobalHandles::From(const_cast<TracedNode*>(node));
Handle<Object> o = global_handles->CreateTraced( Handle<Object> o = global_handles->CreateTraced(
node->object(), reinterpret_cast<Address*>(to), node->object(), reinterpret_cast<Address*>(to),
node->has_destructor() ? GlobalHandleDestructionMode::kWithDestructor
: GlobalHandleDestructionMode::kWithoutDestructor,
GlobalHandleStoreMode::kAssigningStore); GlobalHandleStoreMode::kAssigningStore);
SetSlotThreadSafe(to, o.location()); SetSlotThreadSafe(to, o.location());
TracedNode::Verify(global_handles, from); TracedNode::Verify(global_handles, from);
...@@ -1070,10 +1005,10 @@ void GlobalHandles::MoveGlobal(Address** from, Address** to) { ...@@ -1070,10 +1005,10 @@ void GlobalHandles::MoveGlobal(Address** from, Address** to) {
// those the callers need to ensure consistency. // those the callers need to ensure consistency.
} }
void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { void GlobalHandles::MoveTracedReference(Address** from, Address** to) {
// Fast path for moving from an empty reference. // Fast path for moving from an empty reference.
if (!*from) { if (!*from) {
DestroyTraced(*to); DestroyTracedReference(*to);
SetSlotThreadSafe(to, nullptr); SetSlotThreadSafe(to, nullptr);
return; return;
} }
...@@ -1097,17 +1032,6 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -1097,17 +1032,6 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
to_on_stack = to_node->is_on_stack(); to_on_stack = to_node->is_on_stack();
} }
// Moving a traced handle with finalization callback is prohibited because
// the callback may require knowing about multiple copies of the traced
// handle.
CHECK_WITH_MSG(!from_node->HasFinalizationCallback(),
"Moving of references is not supported when "
"SetFinalizationCallback is set.");
// Types in v8.h ensure that we only copy/move handles that have the same
// destructor behavior.
DCHECK_IMPLIES(to_node,
to_node->has_destructor() == from_node->has_destructor());
// Moving. // Moving.
if (from_on_stack || to_on_stack) { if (from_on_stack || to_on_stack) {
// Move involving a stack slot. // Move involving a stack slot.
...@@ -1115,9 +1039,6 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -1115,9 +1039,6 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
DCHECK(global_handles); DCHECK(global_handles);
Handle<Object> o = global_handles->CreateTraced( Handle<Object> o = global_handles->CreateTraced(
from_node->object(), reinterpret_cast<Address*>(to), from_node->object(), reinterpret_cast<Address*>(to),
from_node->has_destructor()
? GlobalHandleDestructionMode::kWithDestructor
: GlobalHandleDestructionMode::kWithoutDestructor,
GlobalHandleStoreMode::kAssigningStore, to_on_stack); GlobalHandleStoreMode::kAssigningStore, to_on_stack);
SetSlotThreadSafe(to, o.location()); SetSlotThreadSafe(to, o.location());
to_node = TracedNode::FromLocation(*to); to_node = TracedNode::FromLocation(*to);
...@@ -1135,20 +1056,16 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -1135,20 +1056,16 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
WriteBarrier::MarkingFromGlobalHandle(to_node->object()); WriteBarrier::MarkingFromGlobalHandle(to_node->object());
} }
} }
DestroyTraced(*from); DestroyTracedReference(*from);
SetSlotThreadSafe(from, nullptr); SetSlotThreadSafe(from, nullptr);
} else { } else {
// Pure heap move. // Pure heap move.
DestroyTraced(*to); DestroyTracedReference(*to);
SetSlotThreadSafe(to, *from); SetSlotThreadSafe(to, *from);
to_node = from_node; to_node = from_node;
DCHECK_NOT_NULL(*from); DCHECK_NOT_NULL(*from);
DCHECK_NOT_NULL(*to); DCHECK_NOT_NULL(*to);
DCHECK_EQ(*from, *to); DCHECK_EQ(*from, *to);
// Fixup back reference for destructor.
if (to_node->has_destructor()) {
to_node->set_parameter(to);
}
WriteBarrier::MarkingFromGlobalHandle(to_node->object()); WriteBarrier::MarkingFromGlobalHandle(to_node->object());
SetSlotThreadSafe(from, nullptr); SetSlotThreadSafe(from, nullptr);
} }
...@@ -1175,7 +1092,7 @@ void GlobalHandles::Destroy(Address* location) { ...@@ -1175,7 +1092,7 @@ void GlobalHandles::Destroy(Address* location) {
} }
// static // static
void GlobalHandles::DestroyTraced(Address* location) { void GlobalHandles::DestroyTracedReference(Address* location) {
if (location != nullptr) { if (location != nullptr) {
TracedNode* node = TracedNode::FromLocation(location); TracedNode* node = TracedNode::FromLocation(location);
if (node->is_on_stack()) { if (node->is_on_stack()) {
...@@ -1209,20 +1126,9 @@ void GlobalHandles::DestroyTraced(Address* location) { ...@@ -1209,20 +1126,9 @@ void GlobalHandles::DestroyTraced(Address* location) {
// next cycle. // next cycle.
node->clear_object(); node->clear_object();
node->set_parameter(nullptr); node->set_parameter(nullptr);
node->SetFinalizationCallback(nullptr, nullptr);
// The destructor setting is left untouched to avoid casting a
// v8::TracedGlobal to a v8::TracedReference for the EmbedderRootsHandler
// which would be UB.
} }
} }
void GlobalHandles::SetFinalizationCallbackForTraced(
Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback) {
TracedNode::FromLocation(location)->SetFinalizationCallback(parameter,
callback);
}
using GenericCallback = v8::WeakCallbackInfo<void>::Callback; using GenericCallback = v8::WeakCallbackInfo<void>::Callback;
void GlobalHandles::MakeWeak(Address* location, void* parameter, void GlobalHandles::MakeWeak(Address* location, void* parameter,
...@@ -1269,7 +1175,7 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles( ...@@ -1269,7 +1175,7 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles(
should_reset_handle(isolate()->heap(), node->location())) { should_reset_handle(isolate()->heap(), node->location())) {
if (node->IsPhantomResetHandle()) { if (node->IsPhantomResetHandle()) {
node->MarkPending(); node->MarkPending();
node->ResetPhantomHandle(HandleHolder::kLive); node->ResetPhantomHandle();
++number_of_phantom_handle_resets_; ++number_of_phantom_handle_resets_;
} else if (node->IsPhantomCallback()) { } else if (node->IsPhantomCallback()) {
node->MarkPending(); node->MarkPending();
...@@ -1280,31 +1186,20 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles( ...@@ -1280,31 +1186,20 @@ void GlobalHandles::IterateWeakRootsForPhantomHandles(
for (TracedNode* node : *traced_nodes_) { for (TracedNode* node : *traced_nodes_) {
if (!node->IsInUse()) continue; if (!node->IsInUse()) continue;
// Detect unreachable nodes first. // Detect unreachable nodes first.
if (!node->markbit() && node->IsPhantomResetHandle() && if (!node->markbit()) {
!node->has_destructor()) { // The handle itself is unreachable. We can clear it even if the target V8
// The handle is unreachable and does not have a callback and a // object is alive.
// destructor associated with it. We can clear it even if the target V8 node->ResetPhantomHandle();
// object is alive. Note that the desctructor and the callback may
// access the handle, that is why we avoid clearing it.
node->ResetPhantomHandle(HandleHolder::kDead);
++number_of_phantom_handle_resets_; ++number_of_phantom_handle_resets_;
continue; continue;
} else if (node->markbit()) {
// Clear the markbit for the next GC.
node->clear_markbit();
} }
// Clear the markbit for the next GC.
node->clear_markbit();
DCHECK(node->IsInUse()); DCHECK(node->IsInUse());
// Detect nodes with unreachable target objects. // Detect nodes with unreachable target objects.
if (should_reset_handle(isolate()->heap(), node->location())) { if (should_reset_handle(isolate()->heap(), node->location())) {
// If the node allows eager resetting, then reset it here. Otherwise, node->ResetPhantomHandle();
// collect its callback that will reset it. ++number_of_phantom_handle_resets_;
if (node->IsPhantomResetHandle()) {
node->ResetPhantomHandle(node->has_destructor() ? HandleHolder::kLive
: HandleHolder::kDead);
++number_of_phantom_handle_resets_;
} else {
node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
}
} }
} }
} }
...@@ -1335,15 +1230,8 @@ void GlobalHandles::IdentifyWeakUnmodifiedObjects( ...@@ -1335,15 +1230,8 @@ void GlobalHandles::IdentifyWeakUnmodifiedObjects(
DCHECK(node->is_root()); DCHECK(node->is_root());
if (is_unmodified(node->location())) { if (is_unmodified(node->location())) {
v8::Value* value = ToApi<v8::Value>(node->handle()); v8::Value* value = ToApi<v8::Value>(node->handle());
if (node->has_destructor()) { node->set_root(handler->IsRoot(
START_ALLOW_USE_DEPRECATED() *reinterpret_cast<v8::TracedReference<v8::Value>*>(&value)));
node->set_root(handler->IsRoot(
*reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value)));
END_ALLOW_USE_DEPRECATED()
} else {
node->set_root(handler->IsRoot(
*reinterpret_cast<v8::TracedReference<v8::Value>*>(&value)));
}
} }
} }
} }
...@@ -1397,7 +1285,7 @@ void GlobalHandles::IterateYoungWeakObjectsForPhantomHandles( ...@@ -1397,7 +1285,7 @@ void GlobalHandles::IterateYoungWeakObjectsForPhantomHandles(
DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback()); DCHECK(node->IsPhantomResetHandle() || node->IsPhantomCallback());
if (node->IsPhantomResetHandle()) { if (node->IsPhantomResetHandle()) {
node->MarkPending(); node->MarkPending();
node->ResetPhantomHandle(HandleHolder::kLive); node->ResetPhantomHandle();
++number_of_phantom_handle_resets_; ++number_of_phantom_handle_resets_;
} else if (node->IsPhantomCallback()) { } else if (node->IsPhantomCallback()) {
node->MarkPending(); node->MarkPending();
...@@ -1422,25 +1310,13 @@ void GlobalHandles::IterateYoungWeakObjectsForPhantomHandles( ...@@ -1422,25 +1310,13 @@ void GlobalHandles::IterateYoungWeakObjectsForPhantomHandles(
DCHECK_IMPLIES(node->is_root(), DCHECK_IMPLIES(node->is_root(),
!should_reset_handle(isolate_->heap(), node->location())); !should_reset_handle(isolate_->heap(), node->location()));
if (should_reset_handle(isolate_->heap(), node->location())) { if (should_reset_handle(isolate_->heap(), node->location())) {
if (node->IsPhantomResetHandle()) { v8::Value* value = ToApi<v8::Value>(node->handle());
if (node->has_destructor()) { handler->ResetRoot(
// For handles with destructor it is guaranteed that the embedder *reinterpret_cast<v8::TracedReference<v8::Value>*>(&value));
// memory is still alive as the destructor would have otherwise // We cannot check whether a node is in use here as the reset behavior
// removed the memory. // depends on whether incremental marking is running when reclaiming
node->ResetPhantomHandle(HandleHolder::kLive); // young objects.
} else { ++number_of_phantom_handle_resets_;
v8::Value* value = ToApi<v8::Value>(node->handle());
handler->ResetRoot(
*reinterpret_cast<v8::TracedReference<v8::Value>*>(&value));
// We cannot check whether a node is in use here as the reset behavior
// depends on whether incremental marking is running when reclaiming
// young objects.
}
++number_of_phantom_handle_resets_;
} else {
node->CollectPhantomCallbackData(&traced_pending_phantom_callbacks_);
}
} else { } else {
if (!node->is_root()) { if (!node->is_root()) {
node->set_root(true); node->set_root(true);
...@@ -1724,15 +1600,8 @@ void GlobalHandles::IterateTracedNodes( ...@@ -1724,15 +1600,8 @@ void GlobalHandles::IterateTracedNodes(
for (TracedNode* node : *traced_nodes_) { for (TracedNode* node : *traced_nodes_) {
if (node->IsInUse()) { if (node->IsInUse()) {
v8::Value* value = ToApi<v8::Value>(node->handle()); v8::Value* value = ToApi<v8::Value>(node->handle());
if (node->has_destructor()) { visitor->VisitTracedReference(
START_ALLOW_USE_DEPRECATED() *reinterpret_cast<v8::TracedReference<v8::Value>*>(&value));
visitor->VisitTracedGlobalHandle(
*reinterpret_cast<v8::TracedGlobal<v8::Value>*>(&value));
END_ALLOW_USE_DEPRECATED()
} else {
visitor->VisitTracedReference(
*reinterpret_cast<v8::TracedReference<v8::Value>*>(&value));
}
} }
} }
} }
......
...@@ -90,12 +90,9 @@ class V8_EXPORT_PRIVATE GlobalHandles final { ...@@ -90,12 +90,9 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
// API for traced handles. // API for traced handles.
// //
static void MoveTracedGlobal(Address** from, Address** to); static void MoveTracedReference(Address** from, Address** to);
static void CopyTracedGlobal(const Address* const* from, Address** to); static void CopyTracedReference(const Address* const* from, Address** to);
static void DestroyTraced(Address* location); static void DestroyTracedReference(Address* location);
static void SetFinalizationCallbackForTraced(
Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback);
static void MarkTraced(Address* location); static void MarkTraced(Address* location);
explicit GlobalHandles(Isolate* isolate); explicit GlobalHandles(Isolate* isolate);
...@@ -109,14 +106,11 @@ class V8_EXPORT_PRIVATE GlobalHandles final { ...@@ -109,14 +106,11 @@ class V8_EXPORT_PRIVATE GlobalHandles final {
inline Handle<T> Create(T value); inline Handle<T> Create(T value);
Handle<Object> CreateTraced(Object value, Address* slot, Handle<Object> CreateTraced(Object value, Address* slot,
GlobalHandleDestructionMode destruction_mode,
GlobalHandleStoreMode store_mode, GlobalHandleStoreMode store_mode,
bool is_on_stack); bool is_on_stack);
Handle<Object> CreateTraced(Object value, Address* slot, Handle<Object> CreateTraced(Object value, Address* slot,
GlobalHandleDestructionMode destruction_mode,
GlobalHandleStoreMode store_mode); GlobalHandleStoreMode store_mode);
Handle<Object> CreateTraced(Address value, Address* slot, Handle<Object> CreateTraced(Address value, Address* slot,
GlobalHandleDestructionMode destruction_mode,
GlobalHandleStoreMode store_mode); GlobalHandleStoreMode store_mode);
void RecordStats(HeapStats* stats); void RecordStats(HeapStats* stats);
......
...@@ -64,10 +64,6 @@ class V8ToCppGCReferencesVisitor final ...@@ -64,10 +64,6 @@ class V8ToCppGCReferencesVisitor final
isolate_(isolate), isolate_(isolate),
wrapper_descriptor_(wrapper_descriptor) {} wrapper_descriptor_(wrapper_descriptor) {}
void VisitTracedGlobalHandle(const v8::TracedGlobal<v8::Value>&) final {
UNREACHABLE();
}
void VisitTracedReference(const v8::TracedReference<v8::Value>& value) final { void VisitTracedReference(const v8::TracedReference<v8::Value>& value) final {
VisitHandle(value, value.WrapperClassId()); VisitHandle(value, value.WrapperClassId());
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "include/v8-cppgc.h" #include "include/v8-cppgc.h"
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/common/allow-deprecated.h"
#include "src/handles/global-handles.h" #include "src/handles/global-handles.h"
#include "src/heap/embedder-tracing-inl.h" #include "src/heap/embedder-tracing-inl.h"
#include "src/heap/gc-tracer.h" #include "src/heap/gc-tracer.h"
...@@ -211,13 +210,6 @@ bool DefaultEmbedderRootsHandler::IsRoot( ...@@ -211,13 +210,6 @@ bool DefaultEmbedderRootsHandler::IsRoot(
return !tracer_ || tracer_->IsRootForNonTracingGC(handle); return !tracer_ || tracer_->IsRootForNonTracingGC(handle);
} }
START_ALLOW_USE_DEPRECATED()
bool DefaultEmbedderRootsHandler::IsRoot(
const v8::TracedGlobal<v8::Value>& handle) {
return !tracer_ || tracer_->IsRootForNonTracingGC(handle);
}
END_ALLOW_USE_DEPRECATED()
void DefaultEmbedderRootsHandler::ResetRoot( void DefaultEmbedderRootsHandler::ResetRoot(
const v8::TracedReference<v8::Value>& handle) { const v8::TracedReference<v8::Value>& handle) {
// Resetting is only called when IsRoot() returns false which // Resetting is only called when IsRoot() returns false which
......
...@@ -27,10 +27,6 @@ class V8_EXPORT_PRIVATE DefaultEmbedderRootsHandler final ...@@ -27,10 +27,6 @@ class V8_EXPORT_PRIVATE DefaultEmbedderRootsHandler final
public: public:
bool IsRoot(const v8::TracedReference<v8::Value>& handle) final; bool IsRoot(const v8::TracedReference<v8::Value>& handle) final;
START_ALLOW_USE_DEPRECATED()
bool IsRoot(const v8::TracedGlobal<v8::Value>& handle) final;
END_ALLOW_USE_DEPRECATED()
void ResetRoot(const v8::TracedReference<v8::Value>& handle) final; void ResetRoot(const v8::TracedReference<v8::Value>& handle) final;
void SetTracer(EmbedderHeapTracer* tracer) { tracer_ = tracer; } void SetTracer(EmbedderHeapTracer* tracer) { tracer_ = tracer; }
......
...@@ -1032,22 +1032,15 @@ ...@@ -1032,22 +1032,15 @@
'test-debug/TerminateOnResumeFromOtherThread': [SKIP], 'test-debug/TerminateOnResumeFromOtherThread': [SKIP],
'test-debug/TerminateOnResumeRunJavaScriptAtBreakpoint': [SKIP], 'test-debug/TerminateOnResumeRunJavaScriptAtBreakpoint': [SKIP],
'test-debug/TerminateOnResumeRunMicrotaskAtBreakpoint': [SKIP], 'test-debug/TerminateOnResumeRunMicrotaskAtBreakpoint': [SKIP],
'test-embedder-tracing/BasicTracedReference': [SKIP],
'test-embedder-tracing/GarbageCollectionForTesting': [SKIP], 'test-embedder-tracing/GarbageCollectionForTesting': [SKIP],
'test-embedder-tracing/NotifyEmptyStack': [SKIP], 'test-embedder-tracing/NotifyEmptyStack': [SKIP],
'test-embedder-tracing/TracedGlobalCopy': [SKIP], 'test-embedder-tracing/TracedReferenceCopyReferences': [SKIP],
'test-embedder-tracing/TracedGlobalCopyNoDestructor': [SKIP],
'test-embedder-tracing/TracedGlobalCopyWithDestructor': [SKIP],
'test-embedder-tracing/TracedGlobalDestructor': [SKIP],
'test-embedder-tracing/TracedGlobalInStdUnorderedMap': [SKIP],
'test-embedder-tracing/TracedGlobalInStdVector': [SKIP],
'test-embedder-tracing/TracedGlobalMove': [SKIP],
'test-embedder-tracing/TracedGlobalNoDestructor': [SKIP],
'test-embedder-tracing/TracedGlobalSetFinalizationCallbackMarkSweep': [SKIP],
'test-embedder-tracing/TracedGlobalToUnmodifiedJSObjectDiesOnMarkSweep': [SKIP],
'test-embedder-tracing/TracedReferenceCopy': [SKIP], 'test-embedder-tracing/TracedReferenceCopy': [SKIP],
'test-embedder-tracing/TracedReferenceHandlesDoNotLeak': [SKIP], 'test-embedder-tracing/TracedReferenceHandlesDoNotLeak': [SKIP],
'test-embedder-tracing/TracedReferenceHandlesMarking': [SKIP], 'test-embedder-tracing/TracedReferenceHandlesMarking': [SKIP],
'test-embedder-tracing/TracedReferenceMove': [SKIP], 'test-embedder-tracing/TracedReferenceMove': [SKIP],
'test-embedder-tracing/TracedReferenceToUnmodifiedJSObjectDiesOnMarkSweep': [SKIP],
'test-embedder-tracing/TracingInEphemerons': [SKIP], 'test-embedder-tracing/TracingInEphemerons': [SKIP],
'test-embedder-tracing/TracingInRevivedSubgraph': [SKIP], 'test-embedder-tracing/TracingInRevivedSubgraph': [SKIP],
'test-embedder-tracing/V8RegisteringEmbedderReference': [SKIP], 'test-embedder-tracing/V8RegisteringEmbedderReference': [SKIP],
......
...@@ -70,19 +70,11 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer { ...@@ -70,19 +70,11 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
embedder_fields.begin(), embedder_fields.end()); embedder_fields.begin(), embedder_fields.end());
} }
void AddReferenceForTracing(v8::TracedGlobal<v8::Value>* global) {
to_register_with_v8_.push_back(global);
}
void AddReferenceForTracing(v8::TracedReference<v8::Value>* ref) { void AddReferenceForTracing(v8::TracedReference<v8::Value>* ref) {
to_register_with_v8_references_.push_back(ref); to_register_with_v8_references_.push_back(ref);
} }
bool AdvanceTracing(double deadline_in_ms) final { bool AdvanceTracing(double deadline_in_ms) final {
for (auto global : to_register_with_v8_) {
RegisterEmbedderReference(global->As<v8::Data>());
}
to_register_with_v8_.clear();
for (auto ref : to_register_with_v8_references_) { for (auto ref : to_register_with_v8_references_) {
RegisterEmbedderReference(ref->As<v8::Data>()); RegisterEmbedderReference(ref->As<v8::Data>());
} }
...@@ -90,7 +82,7 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer { ...@@ -90,7 +82,7 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
return true; return true;
} }
bool IsTracingDone() final { return to_register_with_v8_.empty(); } bool IsTracingDone() final { return to_register_with_v8_references_.empty(); }
void TracePrologue(EmbedderHeapTracer::TraceFlags) final { void TracePrologue(EmbedderHeapTracer::TraceFlags) final {
if (prologue_behavior_ == TracePrologueBehavior::kCallV8WriteBarrier) { if (prologue_behavior_ == TracePrologueBehavior::kCallV8WriteBarrier) {
...@@ -112,21 +104,31 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer { ...@@ -112,21 +104,31 @@ class TestEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
return false; return false;
} }
void ConsiderTracedGlobalAsRoot(bool value) { void DoNotConsiderAsRootForScavenge(v8::TracedReference<v8::Value>* handle) {
consider_traced_global_as_root_ = value; handle->SetWrapperClassId(17);
non_root_handles_.push_back(handle);
}
bool IsRootForNonTracingGC(
const v8::TracedReference<v8::Value>& handle) final {
return handle.WrapperClassId() != 17;
} }
bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final { void ResetHandleInNonTracingGC(
return consider_traced_global_as_root_; const v8::TracedReference<v8::Value>& handle) final {
for (auto* non_root_handle : non_root_handles_) {
if (*non_root_handle == handle) {
non_root_handle->Reset();
}
}
} }
private: private:
std::vector<std::pair<void*, void*>> registered_from_v8_; std::vector<std::pair<void*, void*>> registered_from_v8_;
std::vector<v8::TracedGlobal<v8::Value>*> to_register_with_v8_;
std::vector<v8::TracedReference<v8::Value>*> to_register_with_v8_references_; std::vector<v8::TracedReference<v8::Value>*> to_register_with_v8_references_;
bool consider_traced_global_as_root_ = true;
TracePrologueBehavior prologue_behavior_ = TracePrologueBehavior::kNoop; TracePrologueBehavior prologue_behavior_ = TracePrologueBehavior::kNoop;
v8::Global<v8::Array> array_; v8::Global<v8::Array> array_;
std::vector<v8::TracedReference<v8::Value>*> non_root_handles_;
}; };
} // namespace } // namespace
...@@ -163,16 +165,16 @@ TEST(EmbedderRegisteringV8Reference) { ...@@ -163,16 +165,16 @@ TEST(EmbedderRegisteringV8Reference) {
v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
v8::TracedGlobal<v8::Value> g; auto handle = std::make_unique<v8::TracedReference<v8::Value>>();
{ {
v8::HandleScope inner_scope(isolate); v8::HandleScope inner_scope(isolate);
v8::Local<v8::Value> o = v8::Local<v8::Value> o =
v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate)); v8::Local<v8::Object>::New(isolate, v8::Object::New(isolate));
g.Reset(isolate, o); handle->Reset(isolate, o);
} }
tracer.AddReferenceForTracing(&g); tracer.AddReferenceForTracing(handle.get());
CcTest::CollectGarbage(i::OLD_SPACE); CcTest::CollectGarbage(i::OLD_SPACE);
CHECK(!g.IsEmpty()); CHECK(!handle->IsEmpty());
} }
namespace { namespace {
...@@ -299,12 +301,12 @@ TEST(FinalizeTracingWhenMarking) { ...@@ -299,12 +301,12 @@ TEST(FinalizeTracingWhenMarking) {
namespace { namespace {
void ConstructJSObject(v8::Isolate* isolate, v8::Local<v8::Context> context, void ConstructJSObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
v8::TracedGlobal<v8::Object>* global) { v8::TracedReference<v8::Object>* handle) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Object> object(v8::Object::New(isolate)); v8::Local<v8::Object> object(v8::Object::New(isolate));
CHECK(!object.IsEmpty()); CHECK(!object.IsEmpty());
*global = v8::TracedGlobal<v8::Object>(isolate, object); *handle = v8::TracedReference<v8::Object>(isolate, object);
CHECK(!global->IsEmpty()); CHECK(!handle->IsEmpty());
} }
template <typename T> template <typename T>
...@@ -320,92 +322,47 @@ void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context, ...@@ -320,92 +322,47 @@ void ConstructJSApiObject(v8::Isolate* isolate, v8::Local<v8::Context> context,
enum class SurvivalMode { kSurvives, kDies }; enum class SurvivalMode { kSurvives, kDies };
template <typename ModifierFunction, typename ConstructTracedGlobalFunction> template <typename ModifierFunction, typename ConstructTracedReferenceFunction>
void TracedGlobalTest(v8::Isolate* isolate, void TracedReferenceTest(v8::Isolate* isolate,
ConstructTracedGlobalFunction construct_function, ConstructTracedReferenceFunction construct_function,
ModifierFunction modifier_function, void (*gc_function)(), ModifierFunction modifier_function,
SurvivalMode survives) { void (*gc_function)(), SurvivalMode survives) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
auto* global_handles =
reinterpret_cast<i::Isolate*>(isolate)->global_handles();
auto global = std::make_unique<v8::TracedGlobal<v8::Object>>(); const size_t initial_count = global_handles->handles_count();
construct_function(isolate, context, global.get()); auto handle = std::make_unique<v8::TracedReference<v8::Object>>();
CHECK(InCorrectGeneration(isolate, *global)); construct_function(isolate, context, handle.get());
modifier_function(*global); CHECK(InCorrectGeneration(isolate, *handle));
modifier_function(*handle);
const size_t after_modification_count = global_handles->handles_count();
gc_function(); gc_function();
CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !global->IsEmpty()); // Cannot check the handle as it is not explicitly cleared by the GC. Instead
CHECK_IMPLIES(survives == SurvivalMode::kDies, global->IsEmpty()); // check the handles count.
CHECK_IMPLIES(survives == SurvivalMode::kSurvives,
after_modification_count == global_handles->handles_count());
CHECK_IMPLIES(survives == SurvivalMode::kDies,
initial_count == global_handles->handles_count());
} }
} // namespace } // namespace
TEST(TracedGlobalReset) { TEST(TracedReferenceReset) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::TracedGlobal<v8::Object> traced; v8::TracedReference<v8::Object> handle;
ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced); ConstructJSObject(isolate, isolate->GetCurrentContext(), &handle);
CHECK(!traced.IsEmpty()); CHECK(!handle.IsEmpty());
traced.Reset(); handle.Reset();
CHECK(traced.IsEmpty()); CHECK(handle.IsEmpty());
}
TEST(TracedGlobalInStdVector) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
std::vector<v8::TracedGlobal<v8::Object>> vec;
{
v8::HandleScope new_scope(isolate);
vec.emplace_back(isolate, v8::Object::New(isolate));
}
CHECK(!vec[0].IsEmpty());
InvokeMarkSweep();
CHECK(vec[0].IsEmpty());
}
TEST(TracedGlobalCopyWithDestructor) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope outer_scope(isolate);
i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
const size_t initial_count = global_handles->handles_count();
auto global1 = std::make_unique<v8::TracedGlobal<v8::Object>>();
{
v8::HandleScope scope(isolate);
global1->Reset(isolate, v8::Object::New(isolate));
}
auto global2 = std::make_unique<v8::TracedGlobal<v8::Object>>(*global1);
auto global3 = std::make_unique<v8::TracedGlobal<v8::Object>>();
*global3 = *global2;
CHECK_EQ(initial_count + 3, global_handles->handles_count());
CHECK(!global1->IsEmpty());
CHECK_EQ(*global1, *global2);
CHECK_EQ(*global2, *global3);
{
v8::HandleScope scope(isolate);
auto tmp = v8::Local<v8::Object>::New(isolate, *global3);
CHECK(!tmp.IsEmpty());
InvokeMarkSweep();
}
CHECK_EQ(initial_count + 3, global_handles->handles_count());
CHECK(!global1->IsEmpty());
CHECK_EQ(*global1, *global2);
CHECK_EQ(*global2, *global3);
InvokeMarkSweep();
CHECK_EQ(initial_count, global_handles->handles_count());
CHECK(global1->IsEmpty());
CHECK_EQ(*global1, *global2);
CHECK_EQ(*global2, *global3);
} }
TEST(TracedGlobalCopyNoDestructor) { TEST(TracedReferenceCopyReferences) {
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
...@@ -413,127 +370,112 @@ TEST(TracedGlobalCopyNoDestructor) { ...@@ -413,127 +370,112 @@ TEST(TracedGlobalCopyNoDestructor) {
i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles(); i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
const size_t initial_count = global_handles->handles_count(); const size_t initial_count = global_handles->handles_count();
auto global1 = std::make_unique<v8::TracedReference<v8::Value>>(); auto handle1 = std::make_unique<v8::TracedReference<v8::Value>>();
{ {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
global1->Reset(isolate, v8::Object::New(isolate)); handle1->Reset(isolate, v8::Object::New(isolate));
} }
auto global2 = std::make_unique<v8::TracedReference<v8::Value>>(*global1); auto handle2 = std::make_unique<v8::TracedReference<v8::Value>>(*handle1);
auto global3 = std::make_unique<v8::TracedReference<v8::Value>>(); auto handle3 = std::make_unique<v8::TracedReference<v8::Value>>();
*global3 = *global2; *handle3 = *handle2;
CHECK_EQ(initial_count + 3, global_handles->handles_count()); CHECK_EQ(initial_count + 3, global_handles->handles_count());
CHECK(!global1->IsEmpty()); CHECK(!handle1->IsEmpty());
CHECK_EQ(*global1, *global2); CHECK_EQ(*handle1, *handle2);
CHECK_EQ(*global2, *global3); CHECK_EQ(*handle2, *handle3);
{ {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
auto tmp = v8::Local<v8::Value>::New(isolate, *global3); auto tmp = v8::Local<v8::Value>::New(isolate, *handle3);
CHECK(!tmp.IsEmpty()); CHECK(!tmp.IsEmpty());
InvokeMarkSweep(); InvokeMarkSweep();
} }
CHECK_EQ(initial_count + 3, global_handles->handles_count()); CHECK_EQ(initial_count + 3, global_handles->handles_count());
CHECK(!global1->IsEmpty()); CHECK(!handle1->IsEmpty());
CHECK_EQ(*global1, *global2); CHECK_EQ(*handle1, *handle2);
CHECK_EQ(*global2, *global3); CHECK_EQ(*handle2, *handle3);
InvokeMarkSweep(); InvokeMarkSweep();
CHECK_EQ(initial_count, global_handles->handles_count()); CHECK_EQ(initial_count, global_handles->handles_count());
} }
TEST(TracedGlobalInStdUnorderedMap) { TEST(TracedReferenceToUnmodifiedJSObjectDiesOnMarkSweep) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
std::unordered_map<int, v8::TracedGlobal<v8::Object>> map;
{
v8::HandleScope new_scope(isolate);
map.emplace(std::piecewise_construct, std::forward_as_tuple(1),
std::forward_as_tuple(isolate, v8::Object::New(isolate)));
}
CHECK(!map[1].IsEmpty());
InvokeMarkSweep();
CHECK(map[1].IsEmpty());
}
TEST(TracedGlobalToUnmodifiedJSObjectDiesOnMarkSweep) {
// When stressing incremental marking, a write barrier may keep the object // When stressing incremental marking, a write barrier may keep the object
// alive. // alive.
if (FLAG_stress_incremental_marking) return; if (FLAG_stress_incremental_marking) return;
CcTest::InitializeVM(); CcTest::InitializeVM();
TracedGlobalTest( TracedReferenceTest(
CcTest::isolate(), ConstructJSObject, CcTest::isolate(), ConstructJSObject,
[](const TracedGlobal<v8::Object>& global) {}, [] { InvokeMarkSweep(); }, [](const TracedReference<v8::Object>&) {}, [] { InvokeMarkSweep(); },
SurvivalMode::kDies); SurvivalMode::kDies);
} }
TEST(TracedGlobalToUnmodifiedJSObjectSurvivesMarkSweepWhenHeldAliveOtherwise) { TEST(TracedReferenceToUnmodifiedJSObjectSurvivesMarkSweepWhenHeldAlive) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::Global<v8::Object> strong_global; v8::Global<v8::Object> strong_global;
TracedGlobalTest( TracedReferenceTest(
CcTest::isolate(), ConstructJSObject, CcTest::isolate(), ConstructJSObject,
[isolate, &strong_global](const TracedGlobal<v8::Object>& global) { [isolate, &strong_global](const TracedReference<v8::Object>& handle) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
strong_global = v8::Global<v8::Object>(isolate, global.Get(isolate)); strong_global = v8::Global<v8::Object>(isolate, handle.Get(isolate));
}, },
[]() { InvokeMarkSweep(); }, SurvivalMode::kSurvives); []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
} }
TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavenge) { TEST(TracedReferenceToUnmodifiedJSObjectSurvivesScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
TracedGlobalTest( TracedReferenceTest(
CcTest::isolate(), ConstructJSObject, CcTest::isolate(), ConstructJSObject,
[](const TracedGlobal<v8::Object>& global) {}, []() { InvokeScavenge(); }, [](const TracedReference<v8::Object>&) {}, []() { InvokeScavenge(); },
SurvivalMode::kSurvives); SurvivalMode::kSurvives);
} }
TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavengeWhenExcludedFromRoots) { TEST(TracedReferenceToUnmodifiedJSObjectSurvivesScavengeWhenExcludedFromRoots) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
tracer.ConsiderTracedGlobalAsRoot(false); TracedReferenceTest(
TracedGlobalTest(
CcTest::isolate(), ConstructJSObject, CcTest::isolate(), ConstructJSObject,
[](const TracedGlobal<v8::Object>& global) {}, []() { InvokeScavenge(); }, [&tracer](const TracedReference<v8::Object>& handle) {
SurvivalMode::kSurvives); tracer.DoNotConsiderAsRootForScavenge(&handle.As<v8::Value>());
},
[]() { InvokeScavenge(); }, SurvivalMode::kSurvives);
} }
TEST(TracedGlobalToUnmodifiedJSApiObjectSurvivesScavengePerDefault) { TEST(TracedReferenceToUnmodifiedJSApiObjectSurvivesScavengePerDefault) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
tracer.ConsiderTracedGlobalAsRoot(true); TracedReferenceTest(
TracedGlobalTest( CcTest::isolate(), ConstructJSApiObject<TracedReference<v8::Object>>,
CcTest::isolate(), ConstructJSApiObject<TracedGlobal<v8::Object>>, [](const TracedReference<v8::Object>&) {}, []() { InvokeScavenge(); },
[](const TracedGlobal<v8::Object>& global) {}, []() { InvokeScavenge(); },
SurvivalMode::kSurvives); SurvivalMode::kSurvives);
} }
TEST(TracedGlobalToUnmodifiedJSApiObjectDiesOnScavengeWhenExcludedFromRoots) { TEST(
TracedReferenceToUnmodifiedJSApiObjectDiesOnScavengeWhenExcludedFromRoots) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
tracer.ConsiderTracedGlobalAsRoot(false); TracedReferenceTest(
TracedGlobalTest( CcTest::isolate(), ConstructJSApiObject<TracedReference<v8::Object>>,
CcTest::isolate(), ConstructJSApiObject<TracedGlobal<v8::Object>>, [&tracer](const TracedReference<v8::Object>& handle) {
[](const TracedGlobal<v8::Object>& global) {}, []() { InvokeScavenge(); }, tracer.DoNotConsiderAsRootForScavenge(&handle.As<v8::Value>());
SurvivalMode::kDies); },
[]() { InvokeScavenge(); }, SurvivalMode::kDies);
} }
TEST(TracedGlobalWrapperClassId) { TEST(TracedReferenceWrapperClassId) {
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
...@@ -541,7 +483,7 @@ TEST(TracedGlobalWrapperClassId) { ...@@ -541,7 +483,7 @@ TEST(TracedGlobalWrapperClassId) {
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
v8::TracedGlobal<v8::Object> traced; v8::TracedReference<v8::Object> traced;
ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced); ConstructJSObject(isolate, isolate->GetCurrentContext(), &traced);
CHECK_EQ(0, traced.WrapperClassId()); CHECK_EQ(0, traced.WrapperClassId());
traced.SetWrapperClassId(17); traced.SetWrapperClassId(17);
...@@ -599,30 +541,14 @@ TEST(TracedReferenceHandlesDoNotLeak) { ...@@ -599,30 +541,14 @@ TEST(TracedReferenceHandlesDoNotLeak) {
CHECK_EQ(initial_count, final_count + 1); CHECK_EQ(initial_count, final_count + 1);
} }
TEST(TracedGlobalHandlesAreRetained) {
// TracedGlobal handles are cleared by the destructor of the embedder object.
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::TracedGlobal<v8::Value> global;
global.Reset(isolate, v8::Undefined(isolate));
i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
const size_t initial_count = global_handles->handles_count();
// We need two GCs because handles are black allocated.
InvokeMarkSweep();
InvokeMarkSweep();
const size_t final_count = global_handles->handles_count();
CHECK_EQ(initial_count, final_count);
}
namespace { namespace {
class TracedGlobalVisitor final class TracedReferenceVisitor final
: public v8::EmbedderHeapTracer::TracedGlobalHandleVisitor { : public v8::EmbedderHeapTracer::TracedGlobalHandleVisitor {
public: public:
~TracedGlobalVisitor() override = default; ~TracedReferenceVisitor() override = default;
void VisitTracedGlobalHandle(const TracedGlobal<Value>& value) final {
void VisitTracedReference(const TracedReference<Value>& value) final {
if (value.WrapperClassId() == 57) { if (value.WrapperClassId() == 57) {
count_++; count_++;
} }
...@@ -636,7 +562,7 @@ class TracedGlobalVisitor final ...@@ -636,7 +562,7 @@ class TracedGlobalVisitor final
} // namespace } // namespace
TEST(TracedGlobalIteration) { TEST(TracedReferenceIteration) {
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
...@@ -644,11 +570,11 @@ TEST(TracedGlobalIteration) { ...@@ -644,11 +570,11 @@ TEST(TracedGlobalIteration) {
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
auto traced = std::make_unique<v8::TracedGlobal<v8::Object>>(); auto handle = std::make_unique<v8::TracedReference<v8::Object>>();
ConstructJSObject(isolate, isolate->GetCurrentContext(), traced.get()); ConstructJSObject(isolate, isolate->GetCurrentContext(), handle.get());
CHECK(!traced->IsEmpty()); CHECK(!handle->IsEmpty());
traced->SetWrapperClassId(57); handle->SetWrapperClassId(57);
TracedGlobalVisitor visitor; TracedReferenceVisitor visitor;
{ {
v8::HandleScope new_scope(isolate); v8::HandleScope new_scope(isolate);
tracer.IterateTracedGlobalHandles(&visitor); tracer.IterateTracedGlobalHandles(&visitor);
...@@ -656,64 +582,6 @@ TEST(TracedGlobalIteration) { ...@@ -656,64 +582,6 @@ TEST(TracedGlobalIteration) {
CHECK_EQ(1, visitor.count()); CHECK_EQ(1, visitor.count());
} }
namespace {
void FinalizationCallback(const WeakCallbackInfo<void>& data) {
v8::TracedGlobal<v8::Object>* traced =
reinterpret_cast<v8::TracedGlobal<v8::Object>*>(data.GetParameter());
CHECK_EQ(reinterpret_cast<void*>(0x4), data.GetInternalField(0));
CHECK_EQ(reinterpret_cast<void*>(0x8), data.GetInternalField(1));
traced->Reset();
}
} // namespace
TEST(TracedGlobalSetFinalizationCallbackScavenge) {
if (FLAG_single_generation) return;
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
TestEmbedderHeapTracer tracer;
tracer.ConsiderTracedGlobalAsRoot(false);
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
auto traced = std::make_unique<v8::TracedGlobal<v8::Object>>();
ConstructJSApiObject(isolate, isolate->GetCurrentContext(), traced.get());
CHECK(!traced->IsEmpty());
{
v8::HandleScope new_scope(isolate);
auto local = traced->Get(isolate);
local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
}
traced->SetFinalizationCallback(traced.get(), FinalizationCallback);
heap::InvokeScavenge();
CHECK(traced->IsEmpty());
}
TEST(TracedGlobalSetFinalizationCallbackMarkSweep) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
auto traced = std::make_unique<v8::TracedGlobal<v8::Object>>();
ConstructJSApiObject(isolate, isolate->GetCurrentContext(), traced.get());
CHECK(!traced->IsEmpty());
{
v8::HandleScope new_scope(isolate);
auto local = traced->Get(isolate);
local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
}
traced->SetFinalizationCallback(traced.get(), FinalizationCallback);
heap::InvokeMarkSweep();
CHECK(traced->IsEmpty());
}
TEST(TracePrologueCallingIntoV8WriteBarrier) { TEST(TracePrologueCallingIntoV8WriteBarrier) {
// Regression test: https://crbug.com/940003 // Regression test: https://crbug.com/940003
if (!FLAG_incremental_marking) return; if (!FLAG_incremental_marking) return;
...@@ -736,34 +604,7 @@ TEST(TracePrologueCallingIntoV8WriteBarrier) { ...@@ -736,34 +604,7 @@ TEST(TracePrologueCallingIntoV8WriteBarrier) {
heap::InvokeMarkSweep(); heap::InvokeMarkSweep();
} }
TEST(TracedGlobalWithDestructor) { TEST(BasicTracedReference) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
const size_t initial_count = global_handles->handles_count();
auto* traced = new v8::TracedGlobal<v8::Object>();
{
v8::HandleScope new_scope(isolate);
v8::Local<v8::Object> object(ConstructTraceableJSApiObject(
isolate->GetCurrentContext(), nullptr, nullptr));
CHECK(traced->IsEmpty());
*traced = v8::TracedGlobal<v8::Object>(isolate, object);
CHECK(!traced->IsEmpty());
CHECK_EQ(initial_count + 1, global_handles->handles_count());
}
delete traced;
CHECK_EQ(initial_count, global_handles->handles_count());
// GC should not need to clear the handle.
heap::InvokeMarkSweep();
CHECK_EQ(initial_count, global_handles->handles_count());
}
TEST(TracedGlobalNoDestructor) {
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
...@@ -807,24 +648,7 @@ class EmptyEmbedderHeapTracer : public v8::EmbedderHeapTracer { ...@@ -807,24 +648,7 @@ class EmptyEmbedderHeapTracer : public v8::EmbedderHeapTracer {
}; };
// EmbedderHeapTracer that can optimize Scavenger handling when used with // EmbedderHeapTracer that can optimize Scavenger handling when used with
// TraceGlobal handles that have destructors. // TracedReference.
class EmbedderHeapTracerDestructorNonTracingClearing final
: public EmptyEmbedderHeapTracer {
public:
explicit EmbedderHeapTracerDestructorNonTracingClearing(
uint16_t class_id_to_optimize)
: class_id_to_optimize_(class_id_to_optimize) {}
bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final {
return handle.WrapperClassId() != class_id_to_optimize_;
}
private:
uint16_t class_id_to_optimize_;
};
// EmbedderHeapTracer that can optimize Scavenger handling when used with
// TraceGlobal handles without destructors.
class EmbedderHeapTracerNoDestructorNonTracingClearing final class EmbedderHeapTracerNoDestructorNonTracingClearing final
: public EmptyEmbedderHeapTracer { : public EmptyEmbedderHeapTracer {
public: public:
...@@ -877,33 +701,7 @@ void SetupOptimizedAndNonOptimizedHandle(v8::Isolate* isolate, ...@@ -877,33 +701,7 @@ void SetupOptimizedAndNonOptimizedHandle(v8::Isolate* isolate,
} // namespace } // namespace
TEST(TracedGlobalDestructorReclaimedOnScavenge) { TEST(TracedReferenceNoDestructorReclaimedOnScavenge) {
if (FLAG_single_generation) return;
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
constexpr uint16_t kClassIdToOptimize = 17;
EmbedderHeapTracerDestructorNonTracingClearing tracer(kClassIdToOptimize);
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
i::GlobalHandles* global_handles = CcTest::i_isolate()->global_handles();
const size_t initial_count = global_handles->handles_count();
auto* optimized_handle = new v8::TracedGlobal<v8::Object>();
auto* non_optimized_handle = new v8::TracedGlobal<v8::Object>();
SetupOptimizedAndNonOptimizedHandle(isolate, kClassIdToOptimize,
optimized_handle, non_optimized_handle);
CHECK_EQ(initial_count + 2, global_handles->handles_count());
heap::InvokeScavenge();
CHECK_EQ(initial_count + 1, global_handles->handles_count());
CHECK(optimized_handle->IsEmpty());
delete optimized_handle;
CHECK(!non_optimized_handle->IsEmpty());
delete non_optimized_handle;
CHECK_EQ(initial_count, global_handles->handles_count());
}
TEST(TracedGlobalNoDestructorReclaimedOnScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
...@@ -999,13 +797,13 @@ enum class TargetHandling { ...@@ -999,13 +797,13 @@ enum class TargetHandling {
kInitializedOldGen kInitializedOldGen
}; };
template <typename T>
V8_NOINLINE void StackToHeapTest(TestEmbedderHeapTracer* tracer, Operation op, V8_NOINLINE void StackToHeapTest(TestEmbedderHeapTracer* tracer, Operation op,
TargetHandling target_handling) { TargetHandling target_handling) {
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::Global<v8::Object> observer; v8::Global<v8::Object> observer;
T stack_handle; v8::TracedReference<v8::Value> stack_handle;
T* heap_handle = new T(); v8::TracedReference<v8::Value>* heap_handle =
new v8::TracedReference<v8::Value>();
if (target_handling != TargetHandling::kNonInitialized) { if (target_handling != TargetHandling::kNonInitialized) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject( v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject(
...@@ -1040,13 +838,13 @@ V8_NOINLINE void StackToHeapTest(TestEmbedderHeapTracer* tracer, Operation op, ...@@ -1040,13 +838,13 @@ V8_NOINLINE void StackToHeapTest(TestEmbedderHeapTracer* tracer, Operation op,
delete heap_handle; delete heap_handle;
} }
template <typename T>
V8_NOINLINE void HeapToStackTest(TestEmbedderHeapTracer* tracer, Operation op, V8_NOINLINE void HeapToStackTest(TestEmbedderHeapTracer* tracer, Operation op,
TargetHandling target_handling) { TargetHandling target_handling) {
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::Global<v8::Object> observer; v8::Global<v8::Object> observer;
T stack_handle; v8::TracedReference<v8::Value> stack_handle;
T* heap_handle = new T(); v8::TracedReference<v8::Value>* heap_handle =
new v8::TracedReference<v8::Value>();
if (target_handling != TargetHandling::kNonInitialized) { if (target_handling != TargetHandling::kNonInitialized) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject( v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject(
...@@ -1081,13 +879,12 @@ V8_NOINLINE void HeapToStackTest(TestEmbedderHeapTracer* tracer, Operation op, ...@@ -1081,13 +879,12 @@ V8_NOINLINE void HeapToStackTest(TestEmbedderHeapTracer* tracer, Operation op,
delete heap_handle; delete heap_handle;
} }
template <typename T>
V8_NOINLINE void StackToStackTest(TestEmbedderHeapTracer* tracer, Operation op, V8_NOINLINE void StackToStackTest(TestEmbedderHeapTracer* tracer, Operation op,
TargetHandling target_handling) { TargetHandling target_handling) {
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::Global<v8::Object> observer; v8::Global<v8::Object> observer;
T stack_handle1; v8::TracedReference<v8::Value> stack_handle1;
T stack_handle2; v8::TracedReference<v8::Value> stack_handle2;
if (target_handling != TargetHandling::kNonInitialized) { if (target_handling != TargetHandling::kNonInitialized) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject( v8::Local<v8::Object> to_object(ConstructTraceableJSApiObject(
...@@ -1120,7 +917,6 @@ V8_NOINLINE void StackToStackTest(TestEmbedderHeapTracer* tracer, Operation op, ...@@ -1120,7 +917,6 @@ V8_NOINLINE void StackToStackTest(TestEmbedderHeapTracer* tracer, Operation op,
CHECK(observer.IsEmpty()); CHECK(observer.IsEmpty());
} }
template <typename T>
V8_NOINLINE void TracedReferenceCleanedTest(TestEmbedderHeapTracer* tracer) { V8_NOINLINE void TracedReferenceCleanedTest(TestEmbedderHeapTracer* tracer) {
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
...@@ -1129,7 +925,7 @@ V8_NOINLINE void TracedReferenceCleanedTest(TestEmbedderHeapTracer* tracer) { ...@@ -1129,7 +925,7 @@ V8_NOINLINE void TracedReferenceCleanedTest(TestEmbedderHeapTracer* tracer) {
const size_t before = const size_t before =
CcTest::i_isolate()->global_handles()->NumberOfOnStackHandlesForTesting(); CcTest::i_isolate()->global_handles()->NumberOfOnStackHandlesForTesting();
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
T stack_handle; v8::TracedReference<v8::Value> stack_handle;
stack_handle.Reset(isolate, object); stack_handle.Reset(isolate, object);
} }
CHECK_EQ(before + 1, CcTest::i_isolate() CHECK_EQ(before + 1, CcTest::i_isolate()
...@@ -1137,27 +933,6 @@ V8_NOINLINE void TracedReferenceCleanedTest(TestEmbedderHeapTracer* tracer) { ...@@ -1137,27 +933,6 @@ V8_NOINLINE void TracedReferenceCleanedTest(TestEmbedderHeapTracer* tracer) {
->NumberOfOnStackHandlesForTesting()); ->NumberOfOnStackHandlesForTesting());
} }
V8_NOINLINE void TracedGlobalDestructorTest(TestEmbedderHeapTracer* tracer) {
v8::Isolate* isolate = CcTest::isolate();
v8::Global<v8::Object> observer;
{
v8::TracedGlobal<v8::Value> stack_handle;
{
v8::HandleScope scope(isolate);
v8::Local<v8::Object> object(ConstructTraceableJSApiObject(
isolate->GetCurrentContext(), nullptr, nullptr));
stack_handle.Reset(isolate, object);
observer.Reset(isolate, object);
observer.SetWeak();
}
CHECK(!observer.IsEmpty());
heap::InvokeMarkSweep();
CHECK(!observer.IsEmpty());
}
heap::InvokeMarkSweep();
CHECK(observer.IsEmpty());
}
} // namespace } // namespace
TEST(TracedReferenceOnStack) { TEST(TracedReferenceOnStack) {
...@@ -1170,16 +945,6 @@ TEST(TracedReferenceOnStack) { ...@@ -1170,16 +945,6 @@ TEST(TracedReferenceOnStack) {
OnStackTest<v8::TracedReference<v8::Value>>(&tracer); OnStackTest<v8::TracedReference<v8::Value>>(&tracer);
} }
TEST(TracedGlobalOnStack) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer);
tracer.SetStackStart(&manual_gc);
OnStackTest<v8::TracedGlobal<v8::Value>>(&tracer);
}
TEST(TracedReferenceCleaned) { TEST(TracedReferenceCleaned) {
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
...@@ -1187,139 +952,55 @@ TEST(TracedReferenceCleaned) { ...@@ -1187,139 +952,55 @@ TEST(TracedReferenceCleaned) {
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(), heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer); &tracer);
tracer.SetStackStart(&manual_gc); tracer.SetStackStart(&manual_gc);
TracedReferenceCleanedTest<v8::TracedReference<v8::Value>>(&tracer); TracedReferenceCleanedTest(&tracer);
}
TEST(TracedGlobalCleaned) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer);
tracer.SetStackStart(&manual_gc);
TracedReferenceCleanedTest<v8::TracedGlobal<v8::Value>>(&tracer);
} }
TEST(TracedReferenceMove) { TEST(TracedReferenceMove) {
using ReferenceType = v8::TracedReference<v8::Value>;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(), heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer); &tracer);
tracer.SetStackStart(&manual_gc); tracer.SetStackStart(&manual_gc);
StackToHeapTest<ReferenceType>(&tracer, Operation::kMove, StackToHeapTest(&tracer, Operation::kMove, TargetHandling::kNonInitialized);
TargetHandling::kNonInitialized); StackToHeapTest(&tracer, Operation::kMove,
StackToHeapTest<ReferenceType>(&tracer, Operation::kMove, TargetHandling::kInitializedYoungGen);
TargetHandling::kInitializedYoungGen); StackToHeapTest(&tracer, Operation::kMove,
StackToHeapTest<ReferenceType>(&tracer, Operation::kMove, TargetHandling::kInitializedOldGen);
TargetHandling::kInitializedOldGen); HeapToStackTest(&tracer, Operation::kMove, TargetHandling::kNonInitialized);
HeapToStackTest<ReferenceType>(&tracer, Operation::kMove, HeapToStackTest(&tracer, Operation::kMove,
TargetHandling::kNonInitialized); TargetHandling::kInitializedYoungGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kMove, HeapToStackTest(&tracer, Operation::kMove,
TargetHandling::kInitializedYoungGen); TargetHandling::kInitializedOldGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kMove, StackToStackTest(&tracer, Operation::kMove, TargetHandling::kNonInitialized);
TargetHandling::kInitializedOldGen); StackToStackTest(&tracer, Operation::kMove,
StackToStackTest<ReferenceType>(&tracer, Operation::kMove, TargetHandling::kInitializedYoungGen);
TargetHandling::kNonInitialized); StackToStackTest(&tracer, Operation::kMove,
StackToStackTest<ReferenceType>(&tracer, Operation::kMove, TargetHandling::kInitializedOldGen);
TargetHandling::kInitializedYoungGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedOldGen);
} }
TEST(TracedReferenceCopy) { TEST(TracedReferenceCopy) {
using ReferenceType = v8::TracedReference<v8::Value>;
ManualGCScope manual_gc;
CcTest::InitializeVM();
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer);
tracer.SetStackStart(&manual_gc);
StackToHeapTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kNonInitialized);
StackToHeapTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
StackToHeapTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kNonInitialized);
HeapToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kNonInitialized);
StackToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
}
TEST(TracedGlobalMove) {
using ReferenceType = v8::TracedGlobal<v8::Value>;
ManualGCScope manual_gc;
CcTest::InitializeVM();
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer);
tracer.SetStackStart(&manual_gc);
StackToHeapTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kNonInitialized);
StackToHeapTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedYoungGen);
StackToHeapTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedOldGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kNonInitialized);
HeapToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedYoungGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedOldGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kNonInitialized);
StackToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedYoungGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kMove,
TargetHandling::kInitializedOldGen);
}
TEST(TracedGlobalCopy) {
using ReferenceType = v8::TracedGlobal<v8::Value>;
ManualGCScope manual_gc;
CcTest::InitializeVM();
TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer);
tracer.SetStackStart(&manual_gc);
StackToHeapTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kNonInitialized);
StackToHeapTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
StackToHeapTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kNonInitialized);
HeapToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
HeapToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kNonInitialized);
StackToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
StackToStackTest<ReferenceType>(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
}
TEST(TracedGlobalDestructor) {
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
TestEmbedderHeapTracer tracer; TestEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(), heap::TemporaryEmbedderHeapTracerScope tracer_scope(CcTest::isolate(),
&tracer); &tracer);
tracer.SetStackStart(&manual_gc); tracer.SetStackStart(&manual_gc);
TracedGlobalDestructorTest(&tracer); StackToHeapTest(&tracer, Operation::kCopy, TargetHandling::kNonInitialized);
StackToHeapTest(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
StackToHeapTest(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
HeapToStackTest(&tracer, Operation::kCopy, TargetHandling::kNonInitialized);
HeapToStackTest(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
HeapToStackTest(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
StackToStackTest(&tracer, Operation::kCopy, TargetHandling::kNonInitialized);
StackToStackTest(&tracer, Operation::kCopy,
TargetHandling::kInitializedYoungGen);
StackToStackTest(&tracer, Operation::kCopy,
TargetHandling::kInitializedOldGen);
} }
TEST(NotifyEmptyStack) { TEST(NotifyEmptyStack) {
......
...@@ -44,6 +44,10 @@ namespace internal { ...@@ -44,6 +44,10 @@ namespace internal {
namespace { namespace {
struct TracedReferenceWrapper {
v8::TracedReference<v8::Object> handle;
};
// Empty v8::EmbedderHeapTracer that never keeps objects alive on Scavenge. See // Empty v8::EmbedderHeapTracer that never keeps objects alive on Scavenge. See
// |IsRootForNonTracingGC|. // |IsRootForNonTracingGC|.
class NonRootingEmbedderHeapTracer final : public v8::EmbedderHeapTracer { class NonRootingEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
...@@ -58,9 +62,26 @@ class NonRootingEmbedderHeapTracer final : public v8::EmbedderHeapTracer { ...@@ -58,9 +62,26 @@ class NonRootingEmbedderHeapTracer final : public v8::EmbedderHeapTracer {
void TraceEpilogue(TraceSummary*) final {} void TraceEpilogue(TraceSummary*) final {}
void EnterFinalPause(EmbedderStackState) final {} void EnterFinalPause(EmbedderStackState) final {}
bool IsRootForNonTracingGC(const v8::TracedGlobal<v8::Value>& handle) final { bool IsRootForNonTracingGC(
const v8::TracedReference<v8::Value>& handle) final {
return false; return false;
} }
void ResetHandleInNonTracingGC(
const v8::TracedReference<v8::Value>& handle) final {
for (auto* wrapper : wrappers_) {
if (wrapper->handle == handle) {
wrapper->handle.Reset();
}
}
}
void Register(TracedReferenceWrapper* wrapper) {
wrappers_.push_back(wrapper);
}
private:
std::vector<TracedReferenceWrapper*> wrappers_;
}; };
void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); } void InvokeScavenge() { CcTest::CollectGarbage(i::NEW_SPACE); }
...@@ -76,10 +97,6 @@ struct FlagAndGlobal { ...@@ -76,10 +97,6 @@ struct FlagAndGlobal {
v8::Global<v8::Object> handle; v8::Global<v8::Object> handle;
}; };
struct TracedGlobalWrapper {
v8::TracedGlobal<v8::Object> handle;
};
void ResetHandleAndSetFlag(const v8::WeakCallbackInfo<FlagAndGlobal>& data) { void ResetHandleAndSetFlag(const v8::WeakCallbackInfo<FlagAndGlobal>& data) {
data.GetParameter()->handle.Reset(); data.GetParameter()->handle.Reset();
data.GetParameter()->flag = true; data.GetParameter()->flag = true;
...@@ -104,12 +121,12 @@ void ConstructJSObject(v8::Isolate* isolate, v8::Global<v8::Object>* global) { ...@@ -104,12 +121,12 @@ void ConstructJSObject(v8::Isolate* isolate, v8::Global<v8::Object>* global) {
} }
void ConstructJSObject(v8::Isolate* isolate, void ConstructJSObject(v8::Isolate* isolate,
v8::TracedGlobal<v8::Object>* traced) { v8::TracedReference<v8::Object>* handle) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Object> object(v8::Object::New(isolate)); v8::Local<v8::Object> object(v8::Object::New(isolate));
CHECK(!object.IsEmpty()); CHECK(!object.IsEmpty());
*traced = v8::TracedGlobal<v8::Object>(isolate, object); *handle = v8::TracedReference<v8::Object>(isolate, object);
CHECK(!traced->IsEmpty()); CHECK(!handle->IsEmpty());
} }
template <typename HandleContainer> template <typename HandleContainer>
...@@ -150,12 +167,11 @@ void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function, ...@@ -150,12 +167,11 @@ void WeakHandleTest(v8::Isolate* isolate, ConstructFunction construct_function,
CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag); CHECK_IMPLIES(survives == SurvivalMode::kDies, fp.flag);
} }
template <typename ConstructFunction, typename ModifierFunction, template <typename ConstructFunction, typename ModifierFunction>
typename GCFunction> void TracedReferenceTestWithScavenge(v8::Isolate* isolate,
void TracedGlobalTest(v8::Isolate* isolate, ConstructFunction construct_function,
ConstructFunction construct_function, ModifierFunction modifier_function,
ModifierFunction modifier_function, SurvivalMode survives) {
GCFunction gc_function, SurvivalMode survives) {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate); v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context); v8::Context::Scope context_scope(context);
...@@ -163,11 +179,14 @@ void TracedGlobalTest(v8::Isolate* isolate, ...@@ -163,11 +179,14 @@ void TracedGlobalTest(v8::Isolate* isolate,
NonRootingEmbedderHeapTracer tracer; NonRootingEmbedderHeapTracer tracer;
heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer); heap::TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
auto fp = std::make_unique<TracedGlobalWrapper>(); auto fp = std::make_unique<TracedReferenceWrapper>();
tracer.Register(fp.get());
construct_function(isolate, context, fp.get()); construct_function(isolate, context, fp.get());
CHECK(heap::InCorrectGeneration(isolate, fp->handle)); CHECK(heap::InCorrectGeneration(isolate, fp->handle));
modifier_function(fp.get()); modifier_function(fp.get());
gc_function(); InvokeScavenge();
// Scavenge clear properly resets the original handle, so we can check the
// handle directly here.
CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp->handle.IsEmpty()); CHECK_IMPLIES(survives == SurvivalMode::kSurvives, !fp->handle.IsEmpty());
CHECK_IMPLIES(survives == SurvivalMode::kDies, fp->handle.IsEmpty()); CHECK_IMPLIES(survives == SurvivalMode::kDies, fp->handle.IsEmpty());
} }
...@@ -343,14 +362,13 @@ TEST(WeakHandleToUnmodifiedJSObjectDiesOnScavenge) { ...@@ -343,14 +362,13 @@ TEST(WeakHandleToUnmodifiedJSObjectDiesOnScavenge) {
SurvivalMode::kDies); SurvivalMode::kDies);
} }
TEST(TracedGlobalToUnmodifiedJSObjectSurvivesScavenge) { TEST(TracedReferenceToUnmodifiedJSObjectSurvivesScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
TracedGlobalTest( TracedReferenceTestWithScavenge(
CcTest::isolate(), &ConstructJSObject<TracedGlobalWrapper>, CcTest::isolate(), &ConstructJSObject<TracedReferenceWrapper>,
[](TracedGlobalWrapper* fp) {}, []() { InvokeScavenge(); }, [](TracedReferenceWrapper* fp) {}, SurvivalMode::kSurvives);
SurvivalMode::kSurvives);
} }
TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) { TEST(WeakHandleToUnmodifiedJSObjectDiesOnMarkCompact) {
...@@ -382,17 +400,16 @@ TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) { ...@@ -382,17 +400,16 @@ TEST(WeakHandleToUnmodifiedJSApiObjectDiesOnScavenge) {
SurvivalMode::kDies); SurvivalMode::kDies);
} }
TEST(TracedGlobalToUnmodifiedJSApiObjectDiesOnScavenge) { TEST(TracedReferenceToUnmodifiedJSApiObjectDiesOnScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
CcTest::InitializeVM(); CcTest::InitializeVM();
TracedGlobalTest( TracedReferenceTestWithScavenge(
CcTest::isolate(), &ConstructJSApiObject<TracedGlobalWrapper>, CcTest::isolate(), &ConstructJSApiObject<TracedReferenceWrapper>,
[](TracedGlobalWrapper* fp) {}, []() { InvokeScavenge(); }, [](TracedReferenceWrapper* fp) {}, SurvivalMode::kDies);
SurvivalMode::kDies);
} }
TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) { TEST(TracedReferenceToJSApiObjectWithIdentityHashSurvivesScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
ManualGCScope manual_gc; ManualGCScope manual_gc;
...@@ -401,9 +418,9 @@ TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) { ...@@ -401,9 +418,9 @@ TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) {
HandleScope scope(i_isolate); HandleScope scope(i_isolate);
Handle<JSWeakMap> weakmap = i_isolate->factory()->NewJSWeakMap(); Handle<JSWeakMap> weakmap = i_isolate->factory()->NewJSWeakMap();
TracedGlobalTest( TracedReferenceTestWithScavenge(
CcTest::isolate(), &ConstructJSApiObject<TracedGlobalWrapper>, CcTest::isolate(), &ConstructJSApiObject<TracedReferenceWrapper>,
[&weakmap, i_isolate](TracedGlobalWrapper* fp) { [&weakmap, i_isolate](TracedReferenceWrapper* fp) {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
Handle<JSReceiver> key = Handle<JSReceiver> key =
Utils::OpenHandle(*fp->handle.Get(CcTest::isolate())); Utils::OpenHandle(*fp->handle.Get(CcTest::isolate()));
...@@ -411,7 +428,7 @@ TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) { ...@@ -411,7 +428,7 @@ TEST(TracedGlobalToJSApiObjectWithIdentityHashSurvivesScavenge) {
int32_t hash = key->GetOrCreateHash(i_isolate).value(); int32_t hash = key->GetOrCreateHash(i_isolate).value();
JSWeakCollection::Set(weakmap, key, smi, hash); JSWeakCollection::Set(weakmap, key, smi, hash);
}, },
[]() { InvokeScavenge(); }, SurvivalMode::kSurvives); SurvivalMode::kSurvives);
} }
TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) { TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesScavengeWhenInHandle) {
...@@ -447,13 +464,13 @@ TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) { ...@@ -447,13 +464,13 @@ TEST(WeakHandleToUnmodifiedJSApiObjectSurvivesMarkCompactWhenInHandle) {
[]() { InvokeMarkSweep(); }, SurvivalMode::kSurvives); []() { InvokeMarkSweep(); }, SurvivalMode::kSurvives);
} }
TEST(TracedGlobalToJSApiObjectWithModifiedMapSurvivesScavenge) { TEST(TracedReferenceToJSApiObjectWithModifiedMapSurvivesScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
LocalContext context; LocalContext context;
TracedGlobal<v8::Object> handle; TracedReference<v8::Object> handle;
{ {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
// Create an API object which does not have the same map as constructor. // Create an API object which does not have the same map as constructor.
...@@ -469,13 +486,13 @@ TEST(TracedGlobalToJSApiObjectWithModifiedMapSurvivesScavenge) { ...@@ -469,13 +486,13 @@ TEST(TracedGlobalToJSApiObjectWithModifiedMapSurvivesScavenge) {
CHECK(!handle.IsEmpty()); CHECK(!handle.IsEmpty());
} }
TEST(TracedGlobalTOJsApiObjectWithElementsSurvivesScavenge) { TEST(TracedReferenceTOJsApiObjectWithElementsSurvivesScavenge) {
if (FLAG_single_generation) return; if (FLAG_single_generation) return;
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
LocalContext context; LocalContext context;
TracedGlobal<v8::Object> handle; TracedReference<v8::Object> handle;
{ {
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
...@@ -717,13 +734,14 @@ TEST(TotalSizeTracedNode) { ...@@ -717,13 +734,14 @@ TEST(TotalSizeTracedNode) {
Isolate* i_isolate = CcTest::i_isolate(); Isolate* i_isolate = CcTest::i_isolate();
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
v8::TracedGlobal<v8::Object>* global = new TracedGlobal<v8::Object>(); v8::TracedReference<v8::Object>* handle = new TracedReference<v8::Object>();
CHECK_EQ(i_isolate->global_handles()->TotalSize(), 0); CHECK_EQ(i_isolate->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0); CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0);
ConstructJSObject(isolate, global); ConstructJSObject(isolate, handle);
CHECK_GT(i_isolate->global_handles()->TotalSize(), 0); CHECK_GT(i_isolate->global_handles()->TotalSize(), 0);
CHECK_GT(i_isolate->global_handles()->UsedSize(), 0); CHECK_GT(i_isolate->global_handles()->UsedSize(), 0);
delete global; delete handle;
InvokeMarkSweep();
CHECK_GT(i_isolate->global_handles()->TotalSize(), 0); CHECK_GT(i_isolate->global_handles()->TotalSize(), 0);
CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0); CHECK_EQ(i_isolate->global_handles()->UsedSize(), 0);
} }
......
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