[gjs/mozjs102: 47/62] js: Replace class private pointers with reserved slots
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/mozjs102: 47/62] js: Replace class private pointers with reserved slots
- Date: Sun, 7 Aug 2022 17:53:00 +0000 (UTC)
commit 854d19d7b1db23b3646d31a2ec0c836fdc73baaf
Author: Philip Chimento <philip chimento gmail com>
Date: Sat Aug 6 16:19:44 2022 -0700
js: Replace class private pointers with reserved slots
JS::GetPrivate() and JS::SetPrivate() are going away in SpiderMonkey
102. The replacement is to stuff the pointer into a JS::PrivateValue and
store it in an object's reserved slot. This is a change we can make prior
to the switch.
With SpiderMonkey 102, we are intended to use
JS::GetMaybePtrFromReservedSlot() to retrieve the pointer. This function
doesn't exist in SpiderMonkey 91, but it is a small inline function that
we can open-code in jsapi-util.h.
In most of the cases, we can encapsulate this access into three methods
of CWrapperPointerOps: has_private(), init_private(), and unset_private().
(Retrieving the pointer was already encapsulated by the various for_js()
methods.) This provides better safety anyway, because in init_private()
we can enforce that there was no pointer already set. We define that
reserved slot 0 is always the private pointer.
BoxedInstance already used slot 0 for something else, so that moves to
slot 1.
Based on Evan's commit from the mozjs102 branch.
Co-authored-by: Evan Welsh <contact evanwelsh com>
gi/boxed.cpp | 6 ++---
gi/boxed.h | 4 ++++
gi/cwrapper.h | 56 ++++++++++++++++++++++++++++++++++++++++-------
gi/function.cpp | 8 +++----
gi/fundamental.cpp | 2 +-
gi/gerror.cpp | 2 +-
gi/gtype.cpp | 6 ++---
gi/interface.cpp | 2 +-
gi/ns.cpp | 8 +++----
gi/object.cpp | 5 ++---
gi/param.cpp | 23 ++++++++++++-------
gi/union.cpp | 2 +-
gi/wrapperutils.h | 13 +++++------
gjs/context.cpp | 2 +-
gjs/jsapi-util.h | 14 ++++++++++++
gjs/module.cpp | 11 +++++++---
modules/cairo-context.cpp | 3 +--
modules/cairo-path.cpp | 5 +----
modules/cairo-pattern.cpp | 4 +++-
modules/cairo-private.h | 39 +++++++++++++++++++++------------
modules/cairo-surface.cpp | 3 ++-
test/gjs-test-rooting.cpp | 16 +++++++++-----
22 files changed, 155 insertions(+), 79 deletions(-)
---
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index 89d97e3a5..c84cd4d46 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -507,7 +507,8 @@ bool BoxedInstance::get_nested_interface_object(
/* We never actually read the reserved slot, but we put the parent object
* into it to hold onto the parent object.
*/
- JS::SetReservedSlot(obj, 0, JS::ObjectValue(*parent_obj));
+ JS::SetReservedSlot(obj, BoxedInstance::PARENT_OBJECT,
+ JS::ObjectValue(*parent_obj));
value.setObject(*obj);
return true;
@@ -774,8 +775,7 @@ const struct JSClassOps BoxedBase::class_ops = {
*/
const struct JSClass BoxedBase::klass = {
"GObject_Boxed",
- JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE |
- JSCLASS_HAS_RESERVED_SLOTS(1),
+ JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_FOREGROUND_FINALIZE,
&BoxedBase::class_ops
};
// clang-format on
diff --git a/gi/boxed.h b/gi/boxed.h
index ef2404a6f..be5e5e0bd 100644
--- a/gi/boxed.h
+++ b/gi/boxed.h
@@ -7,6 +7,7 @@
#include <config.h>
+#include <stddef.h> // for size_t
#include <stdint.h>
#include <memory> // for unique_ptr
@@ -158,6 +159,9 @@ class BoxedInstance
friend class GIWrapperBase<BoxedBase, BoxedPrototype, BoxedInstance>;
friend class BoxedBase; // for field_getter, etc.
+ // Reserved slots
+ static const size_t PARENT_OBJECT = 1;
+
bool m_allocated_directly : 1;
bool m_owning_ptr : 1; // if set, the JS wrapper owns the C memory referred
// to by m_ptr.
diff --git a/gi/cwrapper.h b/gi/cwrapper.h
index 41095b48b..159479e15 100644
--- a/gi/cwrapper.h
+++ b/gi/cwrapper.h
@@ -7,6 +7,7 @@
#include <config.h>
#include <assert.h>
+#include <stddef.h> // for size_t
#include <string>
#include <type_traits> // for integral_constant
@@ -80,8 +81,10 @@ class CWrapperPointerOps {
*/
[[nodiscard]] static Wrapped* for_js(JSContext* cx,
JS::HandleObject wrapper) {
- return static_cast<Wrapped*>(
- JS_GetInstancePrivate(cx, wrapper, &Base::klass, nullptr));
+ if (!JS_InstanceOf(cx, wrapper, &Base::klass, nullptr))
+ return nullptr;
+
+ return Gjs::maybe_get_private<Wrapped>(wrapper, POINTER);
}
/*
@@ -134,7 +137,45 @@ class CWrapperPointerOps {
* (It can return null if no private data has been set yet on the wrapper.)
*/
[[nodiscard]] static Wrapped* for_js_nocheck(JSObject* wrapper) {
- return static_cast<Wrapped*>(JS::GetPrivate(wrapper));
+ return Gjs::maybe_get_private<Wrapped>(wrapper, POINTER);
+ }
+
+ protected:
+ // The first reserved slot always stores the private pointer.
+ static const size_t POINTER = 0;
+
+ /*
+ * CWrapperPointerOps::has_private:
+ *
+ * Returns true if a private C pointer has already been associated with the
+ * wrapper object.
+ */
+ [[nodiscard]] static bool has_private(JSObject* wrapper) {
+ return !!Gjs::maybe_get_private<Wrapped>(wrapper, POINTER);
+ }
+
+ /*
+ * CWrapperPointerOps::init_private:
+ *
+ * Call this to initialize the wrapper object's private C pointer. The
+ * pointer should not be null. This should not be called twice, without
+ * calling unset_private() in between.
+ */
+ static void init_private(JSObject* wrapper, Wrapped* ptr) {
+ assert(!has_private(wrapper) &&
+ "wrapper object should be a fresh object");
+ assert(ptr && "private pointer should not be null, use unset_private");
+ JS::SetReservedSlot(wrapper, POINTER, JS::PrivateValue(ptr));
+ }
+
+ /*
+ * CWrapperPointerOps::unset_private:
+ *
+ * Call this to remove the wrapper object's private C pointer. After calling
+ * this, it's okay to call init_private() again.
+ */
+ static void unset_private(JSObject* wrapper) {
+ JS::SetReservedSlot(wrapper, POINTER, JS::UndefinedValue());
}
};
@@ -213,7 +254,7 @@ class CWrapper : public CWrapperPointerOps<Base, Wrapped> {
Wrapped* priv = Base::constructor_impl(cx, args);
if (!priv)
return false;
- JS::SetPrivate(object, priv);
+ CWrapperPointerOps<Base, Wrapped>::init_private(object, priv);
args.rval().setObject(*object);
return true;
@@ -257,8 +298,7 @@ class CWrapper : public CWrapperPointerOps<Base, Wrapped> {
Base::finalize_impl(fop, priv);
- // Remove the pointer from the JSObject
- JS::SetPrivate(obj, nullptr);
+ CWrapperPointerOps<Base, Wrapped>::unset_private(obj);
}
static constexpr JSClassOps class_ops = {
@@ -494,8 +534,8 @@ class CWrapper : public CWrapperPointerOps<Base, Wrapped> {
if (!wrapper)
return nullptr;
- assert(!JS::GetPrivate(wrapper));
- JS::SetPrivate(wrapper, Base::copy_ptr(ptr));
+ CWrapperPointerOps<Base, Wrapped>::init_private(wrapper,
+ Base::copy_ptr(ptr));
debug_lifecycle(ptr, wrapper, "from_c_ptr");
diff --git a/gi/function.cpp b/gi/function.cpp
index 62e431d8f..af739ecd7 100644
--- a/gi/function.cpp
+++ b/gi/function.cpp
@@ -22,7 +22,6 @@
#include <js/Class.h>
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory
#include <js/Exception.h>
-#include <js/Object.h>
#include <js/PropertyDescriptor.h> // for JSPROP_PERMANENT
#include <js/PropertySpec.h>
#include <js/Realm.h> // for GetRealmFunctionPrototype
@@ -149,8 +148,8 @@ class Function : public CWrapper<Function> {
static constexpr JSClass klass = {
"GIRepositoryFunction",
- JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE, &Function::class_ops,
- &Function::class_spec};
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
+ &Function::class_ops, &Function::class_spec};
public:
GJS_JSAPI_RETURN_CONVENTION
@@ -1326,8 +1325,7 @@ JSObject* Function::create(JSContext* context, GType gtype,
auto* priv = new Function(info);
- g_assert(!JS::GetPrivate(function) && "Function should be a fresh object");
- JS::SetPrivate(function, priv);
+ Function::init_private(function, priv);
debug_lifecycle(function, priv, "Constructor");
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
index dcaf3914d..56cf2dc05 100644
--- a/gi/fundamental.cpp
+++ b/gi/fundamental.cpp
@@ -250,7 +250,7 @@ const struct JSClassOps FundamentalBase::class_ops = {
const struct JSClass FundamentalBase::klass = {
"GFundamental_Object",
- JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
&FundamentalBase::class_ops
};
// clang-format on
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index 5aba318f8..ba70005b2 100644
--- a/gi/gerror.cpp
+++ b/gi/gerror.cpp
@@ -193,7 +193,7 @@ const struct JSClassOps ErrorBase::class_ops = {
const struct JSClass ErrorBase::klass = {
"GLib_Error",
- JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&ErrorBase::class_ops
};
diff --git a/gi/gtype.cpp b/gi/gtype.cpp
index 7e4c39f7e..3b0b8b801 100644
--- a/gi/gtype.cpp
+++ b/gi/gtype.cpp
@@ -12,7 +12,6 @@
#include <js/CallArgs.h>
#include <js/Class.h>
#include <js/GCHashTable.h> // for WeakCache
-#include <js/Object.h>
#include <js/PropertyDescriptor.h> // for JSPROP_PERMANENT
#include <js/PropertySpec.h>
#include <js/RootingAPI.h>
@@ -98,7 +97,8 @@ class GTypeObj : public CWrapper<GTypeObj, void> {
js::ClassSpec::DontDefineConstructor};
static constexpr JSClass klass = {
- "GIRepositoryGType", JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
+ "GIRepositoryGType",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
>ypeObj::class_ops, >ypeObj::class_spec};
GJS_JSAPI_RETURN_CONVENTION
@@ -172,7 +172,7 @@ class GTypeObj : public CWrapper<GTypeObj, void> {
if (!gtype_wrapper)
return nullptr;
- JS::SetPrivate(gtype_wrapper, GSIZE_TO_POINTER(gtype));
+ GTypeObj::init_private(gtype_wrapper, GSIZE_TO_POINTER(gtype));
gjs->gtype_table().put(gtype, gtype_wrapper);
diff --git a/gi/interface.cpp b/gi/interface.cpp
index c08294523..4a94dbda0 100644
--- a/gi/interface.cpp
+++ b/gi/interface.cpp
@@ -178,7 +178,7 @@ const struct JSClassOps InterfaceBase::class_ops = {
const struct JSClass InterfaceBase::klass = {
"GObject_Interface",
- JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&InterfaceBase::class_ops
};
diff --git a/gi/ns.cpp b/gi/ns.cpp
index 5d59b948e..1b546c3d3 100644
--- a/gi/ns.cpp
+++ b/gi/ns.cpp
@@ -12,7 +12,6 @@
#include <js/ComparisonOperators.h>
#include <js/ErrorReport.h> // for JS_ReportOutOfMemory
#include <js/Id.h>
-#include <js/Object.h>
#include <js/PropertyDescriptor.h> // for JSPROP_READONLY
#include <js/PropertySpec.h>
#include <js/RootingAPI.h>
@@ -203,8 +202,8 @@ class Ns : private GjsAutoChar, public CWrapper<Ns> {
static constexpr JSClass klass = {
"GIRepositoryNamespace",
- JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE, &Ns::class_ops,
- &Ns::class_spec};
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
+ &Ns::class_ops, &Ns::class_spec};
public:
GJS_JSAPI_RETURN_CONVENTION
@@ -219,8 +218,7 @@ class Ns : private GjsAutoChar, public CWrapper<Ns> {
return nullptr;
auto* priv = new Ns(ns_name);
- g_assert(!JS::GetPrivate(ns));
- JS::SetPrivate(ns, priv);
+ Ns::init_private(ns, priv);
gjs_debug_lifecycle(GJS_DEBUG_GNAMESPACE,
"ns constructor, obj %p priv %p", ns.get(), priv);
diff --git a/gi/object.cpp b/gi/object.cpp
index 5bf88aa28..6cf97c723 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -31,7 +31,6 @@
#include <js/GCVector.h> // for MutableWrappedPtrOperations
#include <js/HeapAPI.h>
#include <js/MemoryFunctions.h> // for AddAssociatedMemory, RemoveAssoci...
-#include <js/Object.h>
#include <js/PropertyDescriptor.h> // for JSPROP_PERMANENT, JSPROP_READONLY
#include <js/String.h>
#include <js/Symbol.h>
@@ -2539,7 +2538,7 @@ const struct JSClassOps ObjectBase::class_ops = {
const struct JSClass ObjectBase::klass = {
"GObject_Object",
- JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
&ObjectBase::class_ops
};
@@ -2726,7 +2725,7 @@ ObjectInstance* ObjectInstance::new_for_gobject(JSContext* cx, GObject* gobj) {
ObjectInstance* priv = new ObjectInstance(prototype, obj);
- JS::SetPrivate(obj, priv);
+ ObjectBase::init_private(obj, priv);
g_object_ref_sink(gobj);
priv->associate_js_gobject(cx, obj, gobj);
diff --git a/gi/param.cpp b/gi/param.cpp
index 7ad313346..5f419db99 100644
--- a/gi/param.cpp
+++ b/gi/param.cpp
@@ -4,6 +4,8 @@
#include <config.h>
+#include <stddef.h> // for size_t
+
#include <girepository.h>
#include <glib.h>
@@ -13,6 +15,7 @@
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
#include <js/Utility.h> // for UniqueChars
+#include <js/Value.h>
#include <jsapi.h> // for JS_GetPropertyById
#include <jspubtd.h> // for JSProto_TypeError
@@ -31,6 +34,9 @@
extern struct JSClass gjs_param_class;
+// Reserved slots
+static const size_t POINTER = 0;
+
struct Param : GjsAutoParam {
explicit Param(GParamSpec* param)
: GjsAutoParam(param, GjsAutoTakeOwnership()) {}
@@ -38,8 +44,10 @@ struct Param : GjsAutoParam {
[[nodiscard]] static GParamSpec* param_value(JSContext* cx,
JS::HandleObject obj) {
- auto* priv = static_cast<Param*>(
- JS_GetInstancePrivate(cx, obj, &gjs_param_class, nullptr));
+ if (!JS_InstanceOf(cx, obj, &gjs_param_class, nullptr))
+ return nullptr;
+
+ auto* priv = Gjs::maybe_get_private<Param>(obj, POINTER);
return priv ? priv->get() : nullptr;
}
@@ -115,14 +123,14 @@ static bool gjs_param_constructor(JSContext* cx, unsigned argc, JS::Value* vp) {
}
static void param_finalize(JSFreeOp*, JSObject* obj) {
- Param* priv = static_cast<Param*>(JS::GetPrivate(obj));
+ Param* priv = Gjs::maybe_get_private<Param>(obj, POINTER);
gjs_debug_lifecycle(GJS_DEBUG_GPARAM, "finalize, obj %p priv %p", obj,
priv);
if (!priv)
return; /* wrong class? */
GJS_DEC_COUNTER(param);
- JS::SetPrivate(obj, nullptr);
+ JS::SetReservedSlot(obj, POINTER, JS::UndefinedValue());
delete priv;
}
@@ -141,9 +149,8 @@ static const struct JSClassOps gjs_param_class_ops = {
struct JSClass gjs_param_class = {
"GObject_ParamSpec",
- JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
- &gjs_param_class_ops
-};
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
+ &gjs_param_class_ops};
GJS_JSAPI_RETURN_CONVENTION
static JSObject*
@@ -221,7 +228,7 @@ gjs_param_from_g_param(JSContext *context,
GJS_INC_COUNTER(param);
auto* priv = new Param(gparam);
- JS::SetPrivate(obj, priv);
+ JS::SetReservedSlot(obj, POINTER, JS::PrivateValue(priv));
gjs_debug(GJS_DEBUG_GPARAM,
"JSObject created with param instance %p type %s", gparam,
diff --git a/gi/union.cpp b/gi/union.cpp
index 5096f7a56..b8356c9e3 100644
--- a/gi/union.cpp
+++ b/gi/union.cpp
@@ -148,7 +148,7 @@ const struct JSClassOps UnionBase::class_ops = {
const struct JSClass UnionBase::klass = {
"GObject_Union",
- JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
&UnionBase::class_ops
};
// clang-format on
diff --git a/gi/wrapperutils.h b/gi/wrapperutils.h
index aa50cdd05..0b87f7cdf 100644
--- a/gi/wrapperutils.h
+++ b/gi/wrapperutils.h
@@ -408,8 +408,7 @@ class GIWrapperBase : public CWrapperPointerOps<Base> {
else
priv->to_instance()->finalize_impl(fop, obj);
- // Remove the pointer from the JSObject
- JS::SetPrivate(obj, nullptr);
+ Base::unset_private(obj);
}
/*
@@ -902,7 +901,7 @@ class GIWrapperPrototype : public Base {
// a garbage collection or error happens subsequently, then this object
// might be traced and we would end up dereferencing a null pointer.
Prototype* proto = priv.release();
- JS::SetPrivate(prototype, proto);
+ Prototype::init_private(prototype, proto);
if (!gjs_wrapper_define_gtype_prop(cx, constructor, gtype))
return nullptr;
@@ -949,7 +948,7 @@ class GIWrapperPrototype : public Base {
return nullptr;
Prototype* proto = priv.release();
- JS::SetPrivate(prototype, proto);
+ Prototype::init_private(prototype, proto);
if (!proto->define_static_methods(cx, constructor))
return nullptr;
@@ -1060,24 +1059,22 @@ class GIWrapperInstance : public Base {
*/
[[nodiscard]] static Instance* new_for_js_object(JSContext* cx,
JS::HandleObject obj) {
- g_assert(!JS::GetPrivate(obj));
Prototype* prototype = Prototype::for_js_prototype(cx, obj);
auto* priv = new Instance(prototype, obj);
// Init the private variable before we do anything else. If a garbage
// collection happens when calling the constructor, then this object
// might be traced and we would end up dereferencing a null pointer.
- JS::SetPrivate(obj, priv);
+ Instance::init_private(obj, priv);
return priv;
}
[[nodiscard]] static Instance* new_for_js_object(Prototype* prototype,
JS::HandleObject obj) {
- g_assert(!JS::GetPrivate(obj));
auto* priv = new Instance(prototype, obj);
- JS::SetPrivate(obj, priv);
+ Instance::init_private(obj, priv);
return priv;
}
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 4e22825d0..a9dde93db 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -433,7 +433,7 @@ void GjsContextPrivate::dispose(void) {
m_gtype_table->clear();
/* Do a full GC here before tearing down, since once we do
- * that we may not have the JS::GetPrivate() to access the
+ * that we may not have the JS::GetReservedSlot(, 0) to access the
* context
*/
gjs_debug(GJS_DEBUG_CONTEXT, "Final triggered GC");
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 0724181e3..a891fa42c 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -26,8 +26,10 @@
#include <js/GCAPI.h>
#include <js/GCPolicyAPI.h> // for IgnoreGCPolicy
#include <js/Id.h>
+#include <js/Object.h> // for GetReservedSlot
#include <js/TypeDecls.h>
#include <js/Utility.h> // for UniqueChars
+#include <js/Value.h>
#include <jspubtd.h> // for JSProtoKey
#include "gjs/macros.h"
@@ -634,6 +636,18 @@ template <typename T>
return true;
}
+/**
+ * Helper function, backported from future SpiderMonkey's
+ * JS::GetMaybePtrFromReservedSlot(), to get the pointer value (or nullptr if
+ * not set) from an object's reserved slot. The slot must contain either a
+ * JS::PrivateValue(T*) or JS::UndefinedValue.
+ */
+template <typename T>
+inline T* maybe_get_private(JSObject* obj, size_t slot) {
+ JS::Value v = JS::GetReservedSlot(obj, slot);
+ return v.isUndefined() ? nullptr : static_cast<T*>(v.toPrivate());
+}
+
} // namespace Gjs
[[nodiscard]] const char* gjs_explain_gc_reason(JS::GCReason reason);
diff --git a/gjs/module.cpp b/gjs/module.cpp
index bcff321af..c8d4b21c0 100644
--- a/gjs/module.cpp
+++ b/gjs/module.cpp
@@ -57,6 +57,9 @@ union Utf8Unit;
class GjsScriptModule {
char *m_name;
+ // Reserved slots
+ static const size_t POINTER = 0;
+
GjsScriptModule(const char* name) {
m_name = g_strdup(name);
GJS_INC_COUNTER(module);
@@ -73,13 +76,15 @@ class GjsScriptModule {
/* Private data accessors */
[[nodiscard]] static inline GjsScriptModule* priv(JSObject* module) {
- return static_cast<GjsScriptModule*>(JS::GetPrivate(module));
+ return Gjs::maybe_get_private<GjsScriptModule>(
+ module, GjsScriptModule::POINTER);
}
/* Creates a JS module object. Use instead of the class's constructor */
[[nodiscard]] static JSObject* create(JSContext* cx, const char* name) {
JSObject* module = JS_NewObject(cx, &GjsScriptModule::klass);
- JS::SetPrivate(module, new GjsScriptModule(name));
+ JS::SetReservedSlot(module, GjsScriptModule::POINTER,
+ JS::PrivateValue(new GjsScriptModule(name)));
return module;
}
@@ -225,7 +230,7 @@ class GjsScriptModule {
static constexpr JSClass klass = {
"GjsScriptModule",
- JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&GjsScriptModule::class_ops,
};
diff --git a/modules/cairo-context.cpp b/modules/cairo-context.cpp
index fd6429870..356ba4562 100644
--- a/modules/cairo-context.cpp
+++ b/modules/cairo-context.cpp
@@ -13,7 +13,6 @@
#include <js/Array.h> // for JS::NewArrayObject
#include <js/CallArgs.h>
#include <js/Conversions.h>
-#include <js/Object.h>
#include <js/PropertyDescriptor.h> // for JSPROP_READONLY
#include <js/PropertySpec.h>
#include <js/RootingAPI.h>
@@ -357,7 +356,7 @@ bool CairoContext::dispose(JSContext* context, unsigned argc, JS::Value* vp) {
_GJS_CAIRO_CONTEXT_GET_PRIV_CR_CHECKED(context, argc, vp, rec, obj);
cairo_destroy(cr);
- JS::SetPrivate(obj, nullptr);
+ CairoContext::unset_private(obj);
rec.rval().setUndefined();
return true;
diff --git a/modules/cairo-path.cpp b/modules/cairo-path.cpp
index 76a879dfa..415fcf2ef 100644
--- a/modules/cairo-path.cpp
+++ b/modules/cairo-path.cpp
@@ -6,9 +6,7 @@
#include <config.h>
#include <cairo.h>
-#include <glib.h> // for g_assert
-#include <js/Object.h>
#include <js/PropertyDescriptor.h> // for JSPROP_READONLY
#include <js/PropertySpec.h>
#include <js/RootingAPI.h>
@@ -38,8 +36,7 @@ JSObject* CairoPath::take_c_ptr(JSContext* cx, cairo_path_t* ptr) {
if (!wrapper)
return nullptr;
- g_assert(!JS::GetPrivate(wrapper));
- JS::SetPrivate(wrapper, ptr);
+ CairoPath::init_private(wrapper, ptr);
debug_lifecycle(ptr, wrapper, "take_c_ptr");
diff --git a/modules/cairo-pattern.cpp b/modules/cairo-pattern.cpp
index 1a6d07da3..a92541844 100644
--- a/modules/cairo-pattern.cpp
+++ b/modules/cairo-pattern.cpp
@@ -15,6 +15,7 @@
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
+#include "gi/cwrapper.h"
#include "gjs/jsapi-class.h"
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
@@ -136,5 +137,6 @@ cairo_pattern_t* CairoPattern::for_js(JSContext* cx,
return nullptr;
}
- return static_cast<cairo_pattern_t*>(JS::GetPrivate(pattern_wrapper));
+ return Gjs::maybe_get_private<cairo_pattern_t>(pattern_wrapper,
+ CairoPattern::POINTER);
}
diff --git a/modules/cairo-private.h b/modules/cairo-private.h
index a470a94a5..8e17c83e4 100644
--- a/modules/cairo-private.h
+++ b/modules/cairo-private.h
@@ -69,7 +69,7 @@ class CairoRegion : public CWrapper<CairoRegion, cairo_region_t> {
CairoRegion::define_gtype_prop,
};
static constexpr JSClass klass = {
- "Region", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "Region", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoRegion::class_ops, &CairoRegion::class_spec};
};
@@ -109,8 +109,11 @@ class CairoContext : public CWrapper<CairoContext, cairo_t> {
CairoContext::define_gtype_prop,
};
static constexpr JSClass klass = {
- "Context", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "Context", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoContext::class_ops, &CairoContext::class_spec};
+
+ GJS_JSAPI_RETURN_CONVENTION
+ static bool dispose(JSContext* cx, unsigned argc, JS::Value* vp);
};
void gjs_cairo_context_init(void);
@@ -143,7 +146,7 @@ class CairoPath : public CWrapper<CairoPath, cairo_path_t> {
nullptr, // finishInit
};
static constexpr JSClass klass = {
- "Path", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "Path", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPath::class_ops, &CairoPath::class_spec};
public:
@@ -185,7 +188,7 @@ class CairoSurface : public CWrapper<CairoSurface, cairo_surface_t> {
&CairoSurface::define_gtype_prop,
};
static constexpr JSClass klass = {
- "Surface", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "Surface", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoSurface::class_ops, &CairoSurface::class_spec};
static cairo_surface_t* copy_ptr(cairo_surface_t* surface) {
@@ -229,7 +232,8 @@ class CairoImageSurface : public CWrapper<CairoImageSurface, cairo_surface_t> {
&CairoSurface::define_gtype_prop,
};
static constexpr JSClass klass = {
- "ImageSurface", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "ImageSurface",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoSurface::class_ops, &CairoImageSurface::class_spec};
static cairo_surface_t* copy_ptr(cairo_surface_t* surface) {
@@ -268,7 +272,8 @@ class CairoPSSurface : public CWrapper<CairoPSSurface, cairo_surface_t> {
&CairoSurface::define_gtype_prop,
};
static constexpr JSClass klass = {
- "PSSurface", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "PSSurface",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoSurface::class_ops, &CairoPSSurface::class_spec};
static cairo_surface_t* copy_ptr(cairo_surface_t* surface) {
@@ -313,7 +318,8 @@ class CairoPDFSurface : public CWrapper<CairoPDFSurface, cairo_surface_t> {
&CairoSurface::define_gtype_prop,
};
static constexpr JSClass klass = {
- "PDFSurface", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "PDFSurface",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoSurface::class_ops, &CairoPDFSurface::class_spec};
static cairo_surface_t* copy_ptr(cairo_surface_t* surface) {
@@ -358,7 +364,8 @@ class CairoSVGSurface : public CWrapper<CairoSVGSurface, cairo_surface_t> {
&CairoSurface::define_gtype_prop,
};
static constexpr JSClass klass = {
- "SVGSurface", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "SVGSurface",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoSurface::class_ops, &CairoSVGSurface::class_spec};
static cairo_surface_t* copy_ptr(cairo_surface_t* surface) {
@@ -410,7 +417,7 @@ class CairoPattern : public CWrapper<CairoPattern, cairo_pattern_t> {
&CairoPattern::define_gtype_prop,
};
static constexpr JSClass klass = {
- "Pattern", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "Pattern", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPattern::class_ops, &CairoPattern::class_spec};
static GType gtype() { return CAIRO_GOBJECT_TYPE_PATTERN; }
@@ -459,7 +466,7 @@ class CairoGradient : public CWrapper<CairoGradient, cairo_pattern_t> {
&CairoPattern::define_gtype_prop,
};
static constexpr JSClass klass = {
- "Gradient", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "Gradient", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPattern::class_ops, &CairoGradient::class_spec};
static void finalize_impl(JSFreeOp*, cairo_pattern_t*) {}
@@ -490,7 +497,8 @@ class CairoLinearGradient
&CairoPattern::define_gtype_prop,
};
static constexpr JSClass klass = {
- "LinearGradient", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "LinearGradient",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPattern::class_ops, &CairoLinearGradient::class_spec};
static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
@@ -529,7 +537,8 @@ class CairoRadialGradient
&CairoPattern::define_gtype_prop,
};
static constexpr JSClass klass = {
- "RadialGradient", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "RadialGradient",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPattern::class_ops, &CairoRadialGradient::class_spec};
static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
@@ -568,7 +577,8 @@ class CairoSurfacePattern
&CairoPattern::define_gtype_prop,
};
static constexpr JSClass klass = {
- "SurfacePattern", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "SurfacePattern",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPattern::class_ops, &CairoSurfacePattern::class_spec};
static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
@@ -605,7 +615,8 @@ class CairoSolidPattern : public CWrapper<CairoSolidPattern, cairo_pattern_t> {
&CairoPattern::define_gtype_prop,
};
static constexpr JSClass klass = {
- "SolidPattern", JSCLASS_HAS_PRIVATE | JSCLASS_BACKGROUND_FINALIZE,
+ "SolidPattern",
+ JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_BACKGROUND_FINALIZE,
&CairoPattern::class_ops, &CairoSolidPattern::class_spec};
static cairo_pattern_t* copy_ptr(cairo_pattern_t* pattern) {
diff --git a/modules/cairo-surface.cpp b/modules/cairo-surface.cpp
index 710e8c1bf..51661c3cd 100644
--- a/modules/cairo-surface.cpp
+++ b/modules/cairo-surface.cpp
@@ -272,7 +272,8 @@ cairo_surface_t* CairoSurface::for_js(JSContext* cx,
return nullptr;
}
- return static_cast<cairo_surface_t*>(JS::GetPrivate(surface_wrapper));
+ return Gjs::maybe_get_private<cairo_surface_t>(surface_wrapper,
+ CairoSurface::POINTER);
}
[[nodiscard]] static bool surface_to_g_argument(
diff --git a/test/gjs-test-rooting.cpp b/test/gjs-test-rooting.cpp
index edf8656ba..077f45081 100644
--- a/test/gjs-test-rooting.cpp
+++ b/test/gjs-test-rooting.cpp
@@ -3,6 +3,8 @@
#include <config.h>
+#include <stddef.h> // for size_t
+
#include <glib.h>
#include <js/Class.h>
@@ -14,6 +16,7 @@
#include "gjs/context-private.h"
#include "gjs/jsapi-util-root.h"
+#include "gjs/jsapi-util.h" // for maybe_get_private
#include "test/gjs-test-utils.h"
// COMPAT: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1553
@@ -26,6 +29,9 @@ static GMutex gc_lock;
static GCond gc_finished;
static int gc_counter;
+// TestObj reserved slots
+static const size_t POINTER = 0;
+
#define PARENT(fx) ((GjsUnitTestFixture *)fx)
struct GjsRootingFixture {
GjsUnitTestFixture parent;
@@ -37,7 +43,7 @@ struct GjsRootingFixture {
};
static void test_obj_finalize(JSFreeOp*, JSObject* obj) {
- bool* finalized_p = static_cast<bool*>(JS::GetPrivate(obj));
+ bool* finalized_p = Gjs::maybe_get_private<bool>(obj, POINTER);
g_assert_false(*finalized_p);
*finalized_p = true;
}
@@ -52,16 +58,14 @@ static const JSClassOps test_obj_class_ops = {
test_obj_finalize};
static JSClass test_obj_class = {
- "TestObj",
- JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
- &test_obj_class_ops
-};
+ "TestObj", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_FOREGROUND_FINALIZE,
+ &test_obj_class_ops};
static JSObject *
test_obj_new(GjsRootingFixture *fx)
{
JSObject *retval = JS_NewObject(PARENT(fx)->cx, &test_obj_class);
- JS::SetPrivate(retval, &fx->finalized);
+ JS::SetReservedSlot(retval, POINTER, JS::PrivateValue(&fx->finalized));
return retval;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]