[gjs: 7/9] union: Split private struct into UnionPrototype/UnionInstance
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs: 7/9] union: Split private struct into UnionPrototype/UnionInstance
- Date: Tue, 8 Jan 2019 06:54:26 +0000 (UTC)
commit cc2e68cb1f91621d8ed1a189153f780058f75aee
Author: Philip Chimento <philip chimento gmail com>
Date: Tue Dec 11 22:11:21 2018 -0800
union: Split private struct into UnionPrototype/UnionInstance
This continues the ports of GObject introspection wrappers to the new
framework introduced in wrapperutils.h.
gi/union.cpp | 307 ++++++++++--------------------------------------------
gi/union.h | 60 +++++++++++
gjs/mem-private.h | 3 +-
gjs/mem.cpp | 6 +-
4 files changed, 122 insertions(+), 254 deletions(-)
---
diff --git a/gi/union.cpp b/gi/union.cpp
index b8c1355d..c0639d39 100644
--- a/gi/union.cpp
+++ b/gi/union.cpp
@@ -41,57 +41,33 @@
#include "gjs/mem-private.h"
#include "repo.h"
-typedef struct {
- GIUnionInfo *info;
- void *gboxed; /* NULL if we are the prototype and not an instance */
- GType gtype;
-} Union;
-
-extern struct JSClass gjs_union_class;
+UnionPrototype::UnionPrototype(GIUnionInfo* info, GType gtype)
+ : GIWrapperPrototype(info, gtype) {
+ GJS_INC_COUNTER(union_prototype);
+}
-GJS_DEFINE_PRIV_FROM_JS(Union, gjs_union_class)
+UnionPrototype::~UnionPrototype(void) { GJS_DEC_COUNTER(union_prototype); }
-/*
- * The *resolved out parameter, on success, should be false to indicate that id
- * was not resolved; and true if id was resolved.
- */
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-union_resolve(JSContext *context,
- JS::HandleObject obj,
- JS::HandleId id,
- bool *resolved)
-{
- Union *priv = priv_from_js(context, obj);
- gjs_debug_jsprop(GJS_DEBUG_GBOXED, "Resolve prop '%s' hook, obj %s, priv %p",
- gjs_debug_id(id).c_str(), gjs_debug_object(obj).c_str(), priv);
-
- if (priv == nullptr)
- return false; /* wrong class */
-
- if (priv->gboxed != NULL) {
- /* We are an instance, not a prototype, so look for
- * per-instance props that we want to define on the
- * JSObject. Generally we do not want to cache these in JS, we
- * want to always pull them from the C object, or JS would not
- * see any changes made from C. So we use the get/set prop
- * hooks, not this resolve hook.
- */
- *resolved = false;
- return true;
- }
+UnionInstance::UnionInstance(JSContext* cx, JS::HandleObject obj)
+ : GIWrapperInstance(cx, obj) {
+ GJS_INC_COUNTER(union_instance);
+}
- JS::UniqueChars name;
- if (!gjs_get_string_id(context, id, &name))
- return false;
- if (!name) {
- *resolved = false;
- return true; /* not resolved, but no error */
+UnionInstance::~UnionInstance(void) {
+ if (m_ptr) {
+ g_boxed_free(g_registered_type_info_get_g_type(info()), m_ptr);
+ m_ptr = nullptr;
}
+ GJS_DEC_COUNTER(union_instance);
+}
- /* We are the prototype, so look for methods and other class properties */
+// See GIWrapperBase::resolve().
+bool UnionPrototype::resolve_impl(JSContext* context, JS::HandleObject obj,
+ JS::HandleId id, const char* prop_name,
+ bool* resolved) {
+ // Look for methods and other class properties
GjsAutoFunctionInfo method_info =
- g_union_info_find_method(priv->info, name.get());
+ g_union_info_find_method(info(), prop_name);
if (method_info) {
#if GJS_VERBOSE_ENABLE_GI_USAGE
@@ -100,14 +76,12 @@ union_resolve(JSContext *context,
if (g_function_info_get_flags (method_info) & GI_FUNCTION_IS_METHOD) {
gjs_debug(GJS_DEBUG_GBOXED,
"Defining method %s in prototype for %s.%s",
- method_info.name(),
- g_base_info_get_namespace( (GIBaseInfo*) priv->info),
- g_base_info_get_name( (GIBaseInfo*) priv->info));
+ method_info.name(), ns(), name());
/* obj is union proto */
- if (!gjs_define_function(
- context, obj, g_registered_type_info_get_g_type(priv->info),
- method_info))
+ if (!gjs_define_function(context, obj,
+ g_registered_type_info_get_g_type(info()),
+ method_info))
return false;
*resolved = true; /* we defined the prop in object_proto */
@@ -173,52 +147,16 @@ union_new(JSContext *context,
return NULL;
}
-GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
-{
- GJS_NATIVE_CONSTRUCTOR_VARIABLES(union)
- Union *priv;
- Union *proto_priv;
- JS::RootedObject proto(context);
- void *gboxed;
-
- GJS_NATIVE_CONSTRUCTOR_PRELUDE(union);
-
- priv = g_slice_new0(Union);
-
- GJS_INC_COUNTER(union);
-
- g_assert(priv_from_js(context, object) == NULL);
- JS_SetPrivate(object, priv);
-
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
- "union constructor, obj %p priv %p",
- object.get(), priv);
-
- JS_GetPrototype(context, object, &proto);
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED, "union instance __proto__ is %p",
- proto.get());
-
- /* If we're the prototype, then post-construct we'll fill in priv->info.
- * If we are not the prototype, though, then we'll get ->info from the
- * prototype and then create a GObject if we don't have one already.
- */
- proto_priv = priv_from_js(context, proto);
- if (proto_priv == NULL) {
- gjs_debug(GJS_DEBUG_GBOXED,
- "Bad prototype set on union? Must match JSClass of object. JS error should have been
reported.");
- return false;
- }
-
- priv->info = proto_priv->info;
- g_base_info_ref( (GIBaseInfo*) priv->info);
- priv->gtype = proto_priv->gtype;
-
+// See GIWrapperBase::constructor().
+bool UnionInstance::constructor_impl(JSContext* context,
+ JS::HandleObject object,
+ const JS::CallArgs& args) {
/* union_new happens to be implemented by calling
* gjs_invoke_c_function(), which returns a JS::Value.
* The returned "gboxed" here is owned by that JS::Value,
* not by us.
*/
- gboxed = union_new(context, object, priv->info);
+ void* gboxed = union_new(context, object, info());
if (gboxed == NULL) {
return false;
@@ -228,89 +166,34 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
* be garbage collected, we make a copy here to be
* owned by us.
*/
- priv->gboxed = g_boxed_copy(priv->gtype, gboxed);
-
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
- "JSObject created with union instance %p type %s",
- priv->gboxed, g_type_name(priv->gtype));
-
- GJS_NATIVE_CONSTRUCTOR_FINISH(union);
+ copy_union(gboxed);
return true;
}
-static void
-union_finalize(JSFreeOp *fop,
- JSObject *obj)
-{
- Union *priv;
-
- priv = (Union*) JS_GetPrivate(obj);
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
- "finalize, obj %p priv %p", obj, priv);
- if (priv == NULL)
- return; /* wrong class? */
-
- if (priv->gboxed) {
- g_boxed_free(g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info),
- priv->gboxed);
- priv->gboxed = NULL;
- }
-
- if (priv->info) {
- g_base_info_unref( (GIBaseInfo*) priv->info);
- priv->info = NULL;
- }
-
- GJS_DEC_COUNTER(union);
- g_slice_free(Union, priv);
-}
-
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-to_string_func(JSContext *context,
- unsigned argc,
- JS::Value *vp)
-{
- GJS_GET_PRIV(context, argc, vp, rec, obj, Union, priv);
- return gjs_wrapper_to_string_func(context, obj, "union", priv->info,
- priv->gtype, priv->gboxed, rec.rval());
-}
-
-/* The bizarre thing about this vtable is that it applies to both
- * instances of the object, and to the prototype that instances of the
- * class have.
- */
-static const struct JSClassOps gjs_union_class_ops = {
+// clang-format off
+const struct JSClassOps UnionBase::class_ops = {
nullptr, // addProperty
nullptr, // deleteProperty
nullptr, // enumerate
nullptr, // newEnumerate
- union_resolve,
+ &UnionBase::resolve,
nullptr, // mayResolve
- union_finalize};
+ &UnionBase::finalize,
+};
-struct JSClass gjs_union_class = {
+const struct JSClass UnionBase::klass = {
"GObject_Union",
JSCLASS_HAS_PRIVATE | JSCLASS_FOREGROUND_FINALIZE,
- &gjs_union_class_ops
-};
-
-JSPropertySpec gjs_union_proto_props[] = {
- JS_PS_END
+ &UnionBase::class_ops
};
-
-JSFunctionSpec gjs_union_proto_funcs[] = {
- JS_FN("toString", to_string_func, 0, 0),
- JS_FS_END};
+// clang-format on
bool
gjs_define_union_class(JSContext *context,
JS::HandleObject in_object,
GIUnionInfo *info)
{
- const char *constructor_name;
- Union *priv;
GType gtype;
JS::RootedObject prototype(context), constructor(context);
@@ -323,43 +206,8 @@ gjs_define_union_class(JSContext *context,
return false;
}
- /* See the comment in gjs_define_object_class() for an
- * explanation of how this all works; Union is pretty much the
- * same as Object.
- */
-
- constructor_name = g_base_info_get_name( (GIBaseInfo*) info);
-
- if (!gjs_init_class_dynamic(context, in_object, nullptr,
- g_base_info_get_namespace( (GIBaseInfo*) info),
- constructor_name,
- &gjs_union_class,
- gjs_union_constructor, 0,
- /* props of prototype */
- &gjs_union_proto_props[0],
- /* funcs of prototype */
- &gjs_union_proto_funcs[0],
- /* props of constructor, MyConstructor.myprop */
- NULL,
- /* funcs of constructor, MyConstructor.myfunc() */
- NULL,
- &prototype,
- &constructor)) {
- return false;
- }
-
- GJS_INC_COUNTER(union);
- priv = g_slice_new0(Union);
- priv->info = info;
- g_base_info_ref( (GIBaseInfo*) priv->info);
- priv->gtype = gtype;
- JS_SetPrivate(prototype, priv);
-
- gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p",
- constructor_name, prototype.get(), JS_GetClass(prototype),
- in_object.get());
-
- return gjs_wrapper_define_gtype_prop(context, constructor, gtype);
+ return !!UnionPrototype::create_class(context, in_object, info, gtype,
+ &constructor, &prototype);
}
JSObject*
@@ -367,8 +215,6 @@ gjs_union_from_c_union(JSContext *context,
GIUnionInfo *info,
void *gboxed)
{
- JSObject *obj;
- Union *priv;
GType gtype;
if (gboxed == NULL)
@@ -392,15 +238,13 @@ gjs_union_from_c_union(JSContext *context,
if (!proto)
return nullptr;
- obj = JS_NewObjectWithGivenProto(context, JS_GetClass(proto), proto);
+ JS::RootedObject obj(
+ context, JS_NewObjectWithGivenProto(context, JS_GetClass(proto), proto));
+ if (!obj)
+ return nullptr;
- GJS_INC_COUNTER(union);
- priv = g_slice_new0(Union);
- JS_SetPrivate(obj, priv);
- priv->info = info;
- g_base_info_ref( (GIBaseInfo *) priv->info);
- priv->gtype = gtype;
- priv->gboxed = g_boxed_copy(gtype, gboxed);
+ UnionInstance* priv = UnionInstance::new_for_js_object(context, obj);
+ priv->copy_union(gboxed);
return obj;
}
@@ -409,14 +253,14 @@ void*
gjs_c_union_from_union(JSContext *context,
JS::HandleObject obj)
{
- Union *priv;
-
if (!obj)
return NULL;
- priv = priv_from_js(context, obj);
+ UnionInstance* priv = UnionInstance::for_js(context, obj);
+ if (!priv)
+ return nullptr;
- return priv->gboxed;
+ return priv->ptr();
}
bool
@@ -426,48 +270,9 @@ gjs_typecheck_union(JSContext *context,
GType expected_type,
bool throw_error)
{
- Union *priv;
- bool result;
-
- if (!do_base_typecheck(context, object, throw_error))
- return false;
-
- priv = priv_from_js(context, object);
-
- if (priv->gboxed == NULL) {
- if (throw_error) {
- gjs_throw_custom(context, JSProto_TypeError, nullptr,
- "Object is %s.%s.prototype, not an object instance - cannot convert to a union
instance",
- g_base_info_get_namespace( (GIBaseInfo*) priv->info),
- g_base_info_get_name( (GIBaseInfo*) priv->info));
- }
-
- return false;
- }
-
- if (expected_type != G_TYPE_NONE)
- result = g_type_is_a (priv->gtype, expected_type);
- else if (expected_info != NULL)
- result = g_base_info_equal((GIBaseInfo*) priv->info, (GIBaseInfo*) expected_info);
- else
- result = true;
-
- if (!result && throw_error) {
- if (expected_info != NULL) {
- gjs_throw_custom(context, JSProto_TypeError, nullptr,
- "Object is of type %s.%s - cannot convert to %s.%s",
- g_base_info_get_namespace((GIBaseInfo*) priv->info),
- g_base_info_get_name((GIBaseInfo*) priv->info),
- g_base_info_get_namespace((GIBaseInfo*) expected_info),
- g_base_info_get_name((GIBaseInfo*) expected_info));
- } else {
- gjs_throw_custom(context, JSProto_TypeError, nullptr,
- "Object is of type %s.%s - cannot convert to %s",
- g_base_info_get_namespace((GIBaseInfo*) priv->info),
- g_base_info_get_name((GIBaseInfo*) priv->info),
- g_type_name(expected_type));
- }
- }
-
- return result;
+ if (throw_error)
+ return UnionBase::typecheck(context, object, expected_info,
+ expected_type);
+ return UnionBase::typecheck(context, object, expected_info, expected_type,
+ UnionBase::TypecheckNoThrow());
}
diff --git a/gi/union.h b/gi/union.h
index cf338e7f..2d1665e6 100644
--- a/gi/union.h
+++ b/gi/union.h
@@ -28,9 +28,69 @@
#include <glib.h>
#include <girepository.h>
+#include "gi/wrapperutils.h"
#include "gjs/jsapi-util.h"
#include "gjs/macros.h"
+class UnionPrototype;
+class UnionInstance;
+
+class UnionBase
+ : public GIWrapperBase<UnionBase, UnionPrototype, UnionInstance> {
+ friend class GIWrapperBase;
+
+ protected:
+ explicit UnionBase(UnionPrototype* proto = nullptr)
+ : GIWrapperBase(proto) {}
+ ~UnionBase(void) {}
+
+ static const GjsDebugTopic debug_topic = GJS_DEBUG_GBOXED;
+ static constexpr const char* debug_tag = "union";
+
+ static const JSClassOps class_ops;
+ static const JSClass klass;
+
+ GJS_USE static const char* to_string_kind(void) { return "union"; }
+};
+
+class UnionPrototype : public GIWrapperPrototype<UnionBase, UnionPrototype,
+ UnionInstance, GIUnionInfo> {
+ friend class GIWrapperPrototype;
+ friend class GIWrapperBase;
+
+ explicit UnionPrototype(GIUnionInfo* info, GType gtype);
+ ~UnionPrototype(void);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool resolve_impl(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
+ const char* prop_name, bool* resolved);
+
+ // Overrides GIWrapperPrototype::constructor_nargs().
+ GJS_USE unsigned constructor_nargs(void) const { return 0; }
+};
+
+class UnionInstance
+ : public GIWrapperInstance<UnionBase, UnionPrototype, UnionInstance> {
+ friend class GIWrapperInstance;
+ friend class GIWrapperBase;
+
+ explicit UnionInstance(JSContext* cx, JS::HandleObject obj);
+ ~UnionInstance(void);
+
+ GJS_JSAPI_RETURN_CONVENTION
+ bool constructor_impl(JSContext* cx, JS::HandleObject obj,
+ const JS::CallArgs& args);
+
+ public:
+ /*
+ * UnionInstance::copy_union:
+ *
+ * Allocate a new union pointer using g_boxed_copy(), from a raw union
+ * pointer.
+ */
+ void copy_union(void* ptr) { m_ptr = g_boxed_copy(gtype(), ptr); }
+};
+
G_BEGIN_DECLS
GJS_JSAPI_RETURN_CONVENTION
diff --git a/gjs/mem-private.h b/gjs/mem-private.h
index 75da541b..e9819ca0 100644
--- a/gjs/mem-private.h
+++ b/gjs/mem-private.h
@@ -51,7 +51,8 @@ GJS_DECLARE_COUNTER(object_instance)
GJS_DECLARE_COUNTER(object_prototype)
GJS_DECLARE_COUNTER(param)
GJS_DECLARE_COUNTER(repo)
-GJS_DECLARE_COUNTER(union)
+GJS_DECLARE_COUNTER(union_instance)
+GJS_DECLARE_COUNTER(union_prototype)
#define GJS_INC_COUNTER(name) \
do { \
diff --git a/gjs/mem.cpp b/gjs/mem.cpp
index 2e3a3e9b..2f54c30d 100644
--- a/gjs/mem.cpp
+++ b/gjs/mem.cpp
@@ -51,7 +51,8 @@ GJS_DEFINE_COUNTER(object_instance)
GJS_DEFINE_COUNTER(object_prototype)
GJS_DEFINE_COUNTER(param)
GJS_DEFINE_COUNTER(repo)
-GJS_DEFINE_COUNTER(union)
+GJS_DEFINE_COUNTER(union_instance)
+GJS_DEFINE_COUNTER(union_prototype)
#define GJS_LIST_COUNTER(name) \
& gjs_counter_ ## name
@@ -75,7 +76,8 @@ static GjsMemCounter* counters[] = {
GJS_LIST_COUNTER(object_prototype),
GJS_LIST_COUNTER(param),
GJS_LIST_COUNTER(repo),
- GJS_LIST_COUNTER(union),
+ GJS_LIST_COUNTER(union_instance),
+ GJS_LIST_COUNTER(union_prototype),
};
// clang-format on
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]