summaryrefslogtreecommitdiff
path: root/src/base_object.h
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-09-29 01:29:07 +0200
committerAnna Henningsen <anna@addaleax.net>2019-11-19 13:47:29 +0100
commit7e6104f1bb63a07885b08f277c3b708caa6b8a23 (patch)
tree32d76e6f055d3bfacd849633db3a8af3868a328c /src/base_object.h
parentefce655c0f1671d0e86b5c89092ac93db983ef94 (diff)
downloadandroid-node-v8-7e6104f1bb63a07885b08f277c3b708caa6b8a23.tar.gz
android-node-v8-7e6104f1bb63a07885b08f277c3b708caa6b8a23.tar.bz2
android-node-v8-7e6104f1bb63a07885b08f277c3b708caa6b8a23.zip
src: introduce custom smart pointers for `BaseObject`s
Referring to `BaseObject` instances using standard C++ smart pointers can interfere with BaseObject’s own cleanup mechanisms (explicit delete, delete-on-GC and delete-on-cleanup). Introducing custom smart pointers allows referring to `BaseObject`s safely while keeping those mechanisms intact. Refs: https://github.com/nodejs/quic/pull/141 Refs: https://github.com/nodejs/quic/pull/149 Reviewed-By: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/30374 Refs: https://github.com/nodejs/quic/pull/165 Reviewed-By: David Carlier <devnexen@gmail.com>
Diffstat (limited to 'src/base_object.h')
-rw-r--r--src/base_object.h111
1 files changed, 104 insertions, 7 deletions
diff --git a/src/base_object.h b/src/base_object.h
index 0b202cd3a5..38afe11a76 100644
--- a/src/base_object.h
+++ b/src/base_object.h
@@ -31,6 +31,8 @@
namespace node {
class Environment;
+template <typename T, bool kIsWeak>
+class BaseObjectPtrImpl;
class BaseObject : public MemoryRetainer {
public:
@@ -62,10 +64,12 @@ class BaseObject : public MemoryRetainer {
static inline T* FromJSObject(v8::Local<v8::Object> object);
// Make the `v8::Global` a weak reference and, `delete` this object once
- // the JS object has been garbage collected.
+ // the JS object has been garbage collected and there are no (strong)
+ // BaseObjectPtr references to it.
inline void MakeWeak();
- // Undo `MakeWeak()`, i.e. turn this into a strong reference.
+ // Undo `MakeWeak()`, i.e. turn this into a strong reference that is a GC
+ // root and will not be touched by the garbage collector.
inline void ClearWeak();
// Utility to create a FunctionTemplate with one internal field (used for
@@ -86,11 +90,15 @@ class BaseObject : public MemoryRetainer {
// This is a bit of a hack. See the override in async_wrap.cc for details.
virtual bool IsDoneInitializing() const;
+ // Can be used to avoid this object keepling itself alive as a GC root
+ // indefinitely, for example when this object is owned and deleted by another
+ // BaseObject once that is torn down. This can only be called when there is
+ // a BaseObjectPtr to this object.
+ inline void Detach();
+
protected:
- // Can be used to avoid the automatic object deletion when the Environment
- // exits, for example when this object is owned and deleted by another
- // BaseObject at that point.
- inline void RemoveCleanupHook();
+ inline void RemoveCleanupHook(); // TODO(addaleax): Remove.
+ virtual inline void OnGCCollect();
private:
v8::Local<v8::Object> WrappedObject() const override;
@@ -103,12 +111,44 @@ class BaseObject : public MemoryRetainer {
// refer to `doc/guides/node-postmortem-support.md`
friend int GenDebugSymbols();
friend class CleanupHookCallback;
+ template <typename T, bool kIsWeak>
+ friend class BaseObjectPtrImpl;
v8::Global<v8::Object> persistent_handle_;
+
+ // Metadata that is associated with this BaseObject if there are BaseObjectPtr
+ // or BaseObjectWeakPtr references to it.
+ // This object is deleted when the BaseObject itself is destroyed, and there
+ // are no weak references to it.
+ struct PointerData {
+ // Number of BaseObjectPtr instances that refer to this object. If this
+ // is non-zero, the BaseObject is always a GC root and will not be destroyed
+ // during cleanup until the count drops to zero again.
+ unsigned int strong_ptr_count = 0;
+ // Number of BaseObjectWeakPtr instances that refer to this object.
+ unsigned int weak_ptr_count = 0;
+ // Indicates whether MakeWeak() has been called.
+ bool wants_weak_jsobj = false;
+ // Indicates whether Detach() has been called. If that is the case, this
+ // object will be destryoed once the strong pointer count drops to zero.
+ bool is_detached = false;
+ // Reference to the original BaseObject. This is used by weak pointers.
+ BaseObject* self = nullptr;
+ };
+
+ inline bool has_pointer_data() const;
+ // This creates a PointerData struct if none was associated with this
+ // BaseObject before.
+ inline PointerData* pointer_data();
+
+ // Functions that adjust the strong pointer count.
+ inline void decrease_refcount();
+ inline void increase_refcount();
+
Environment* env_;
+ PointerData* pointer_data_ = nullptr;
};
-
// Global alias for FromJSObject() to avoid churn.
template <typename T>
inline T* Unwrap(v8::Local<v8::Object> obj) {
@@ -124,6 +164,63 @@ inline T* Unwrap(v8::Local<v8::Object> obj) {
return __VA_ARGS__; \
} while (0)
+// Implementation of a generic strong or weak pointer to a BaseObject.
+// If strong, this will keep the target BaseObject alive regardless of other
+// circumstances such das GC or Environment cleanup.
+// If weak, destruction behaviour is not affected, but the pointer will be
+// reset to nullptr once the BaseObject is destroyed.
+// The API matches std::shared_ptr closely.
+template <typename T, bool kIsWeak>
+class BaseObjectPtrImpl final {
+ public:
+ inline BaseObjectPtrImpl();
+ inline ~BaseObjectPtrImpl();
+ inline explicit BaseObjectPtrImpl(T* target);
+
+ // Copy and move constructors. Note that the templated version is not a copy
+ // or move constructor in the C++ sense of the word, so an identical
+ // untemplated version is provided.
+ template <typename U, bool kW>
+ inline BaseObjectPtrImpl(const BaseObjectPtrImpl<U, kW>& other);
+ inline BaseObjectPtrImpl(const BaseObjectPtrImpl& other);
+ template <typename U, bool kW>
+ inline BaseObjectPtrImpl& operator=(const BaseObjectPtrImpl<U, kW>& other);
+ inline BaseObjectPtrImpl& operator=(const BaseObjectPtrImpl& other);
+ inline BaseObjectPtrImpl(BaseObjectPtrImpl&& other);
+ inline BaseObjectPtrImpl& operator=(BaseObjectPtrImpl&& other);
+
+ inline void reset(T* ptr = nullptr);
+ inline T* get() const;
+ inline T& operator*() const;
+ inline T* operator->() const;
+ inline operator bool() const;
+
+ private:
+ union {
+ BaseObject* target; // Used for strong pointers.
+ BaseObject::PointerData* pointer_data; // Used for weak pointers.
+ } data_;
+
+ inline BaseObject* get_base_object() const;
+ inline BaseObject::PointerData* pointer_data() const;
+};
+
+template <typename T>
+using BaseObjectPtr = BaseObjectPtrImpl<T, false>;
+template <typename T>
+using BaseObjectWeakPtr = BaseObjectPtrImpl<T, true>;
+
+// Create a BaseObject instance and return a pointer to it.
+// This variant leaves the object as a GC root by default.
+template <typename T, typename... Args>
+inline BaseObjectPtr<T> MakeBaseObject(Args&&... args);
+// Create a BaseObject instance and return a pointer to it.
+// This variant detaches the object by default, meaning that the caller fully
+// owns it, and once the last BaseObjectPtr to it is destroyed, the object
+// itself is also destroyed.
+template <typename T, typename... Args>
+inline BaseObjectPtr<T> MakeDetachedBaseObject(Args&&... args);
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS