[gjs] Remove usage of JSCLASS_CONSTRUCT_PROTOTYPE
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] Remove usage of JSCLASS_CONSTRUCT_PROTOTYPE
- Date: Fri, 18 Nov 2011 00:19:40 +0000 (UTC)
commit f9276d77652cb0acecd8347610924053a8fc7649
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Fri Nov 4 22:11:39 2011 -0400
Remove usage of JSCLASS_CONSTRUCT_PROTOTYPE
JSCLASS_CONSTRUCT_PROTOTYPE is an old hack that upstream wants to remove. We're
only using it to set the private instance, something we can do ourselves after
initting the class.
https://bugzilla.gnome.org/show_bug.cgi?id=663441
gi/boxed.c | 215 +++++++++++++++++++++-----------------------------
gi/function.c | 8 --
gi/keep-alive.c | 8 --
gi/ns.c | 8 --
gi/object.c | 237 ++++++++++++++++++++++++-------------------------------
gi/param.c | 73 ++++++-----------
gi/repo.c | 8 --
gi/union.c | 126 ++++++++++++------------------
8 files changed, 267 insertions(+), 416 deletions(-)
---
diff --git a/gi/boxed.c b/gi/boxed.c
index 0d09b79..2be87e5 100644
--- a/gi/boxed.c
+++ b/gi/boxed.c
@@ -427,23 +427,12 @@ boxed_init(JSContext *context,
return JS_FALSE;
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(boxed)
Boxed *priv;
Boxed *proto_priv;
- JSClass *obj_class;
- JSClass *proto_class;
JSObject *proto;
- gboolean is_proto;
GJS_NATIVE_CONSTRUCTOR_PRELUDE(boxed);
@@ -460,127 +449,111 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
proto = JS_GetPrototype(context, object);
gjs_debug_lifecycle(GJS_DEBUG_GBOXED, "boxed instance __proto__ is %p", proto);
+ /* 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 boxed? Must match JSClass of object. JS error should have been reported.");
+ return JS_FALSE;
+ }
- /* If we're constructing the prototype, its __proto__ is not the same
- * class as us, but if we're constructing an instance, the prototype
- * has the same class.
+ priv->info = proto_priv->info;
+ priv->can_allocate_directly = proto_priv->can_allocate_directly;
+ g_base_info_ref( (GIBaseInfo*) priv->info);
+
+ /* Since gobject-introspection is always creating new info
+ * objects, == is not meaningful on them, only comparison of
+ * their names. We prefer to use the info that is already ref'd
+ * by the prototype for the class.
*/
- obj_class = JS_GET_CLASS(context, object);
- proto_class = JS_GET_CLASS(context, proto);
+ g_assert(unthreadsafe_template_for_constructor.info == NULL ||
+ strcmp(g_base_info_get_name( (GIBaseInfo*) priv->info),
+ g_base_info_get_name( (GIBaseInfo*) unthreadsafe_template_for_constructor.info))
+ == 0);
+ unthreadsafe_template_for_constructor.info = NULL;
- is_proto = (obj_class != proto_class);
+ if (unthreadsafe_template_for_constructor.gboxed == NULL) {
+ Boxed *source_priv;
+ GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
- "boxed instance constructing proto %d, obj class %s proto class %s",
- is_proto, obj_class->name, proto_class->name);
+ /* Short-circuit copy-construction in the case where we can use g_boxed_copy */
+ if (argc == 1 &&
+ boxed_get_copy_source(context, priv, argv[0], &source_priv)) {
- if (!is_proto) {
- /* 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 boxed? Must match JSClass of object. JS error should have been reported.");
- return JS_FALSE;
+ if (gtype != G_TYPE_NONE && g_type_is_a (gtype, G_TYPE_BOXED)) {
+ priv->gboxed = g_boxed_copy(gtype, source_priv->gboxed);
+ GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
+ return JS_TRUE;
+ }
}
- priv->info = proto_priv->info;
- priv->can_allocate_directly = proto_priv->can_allocate_directly;
- g_base_info_ref( (GIBaseInfo*) priv->info);
-
- /* Since gobject-introspection is always creating new info
- * objects, == is not meaningful on them, only comparison of
- * their names. We prefer to use the info that is already ref'd
- * by the prototype for the class.
- */
- g_assert(unthreadsafe_template_for_constructor.info == NULL ||
- strcmp(g_base_info_get_name( (GIBaseInfo*) priv->info),
- g_base_info_get_name( (GIBaseInfo*) unthreadsafe_template_for_constructor.info))
- == 0);
- unthreadsafe_template_for_constructor.info = NULL;
-
- if (unthreadsafe_template_for_constructor.gboxed == NULL) {
- Boxed *source_priv;
- GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ /* Short-circuit construction for GVariants (simply cannot construct here,
+ the constructor should be overridden) */
+ if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
+ gjs_throw(context,
+ "Can't create instance of GVariant directly, use GVariant.new_*");
+ return JS_FALSE;
+ }
- /* Short-circuit copy-construction in the case where we can use g_boxed_copy */
- if (argc == 1 &&
- boxed_get_copy_source(context, priv, argv[0], &source_priv)) {
+ if (!boxed_new(context, object, priv))
+ return JS_FALSE;
- if (gtype != G_TYPE_NONE && g_type_is_a (gtype, G_TYPE_BOXED)) {
- priv->gboxed = g_boxed_copy(gtype, source_priv->gboxed);
- GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
- return JS_TRUE;
- }
- }
+ if (!boxed_init(context, object, priv, argc, argv))
+ return JS_FALSE;
- /* Short-circuit construction for GVariants (simply cannot construct here,
- the constructor should be overridden) */
- if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
- gjs_throw(context,
- "Can't create instance of GVariant directly, use GVariant.new_*");
- return JS_FALSE;
- }
+ } else if (!JSVAL_IS_NULL(unthreadsafe_template_for_constructor.parent_jsval)) {
+ /* A structure nested inside a parent object; doens't have an independent allocation */
- if (!boxed_new(context, object, priv))
- return JS_FALSE;
+ priv->gboxed = unthreadsafe_template_for_constructor.gboxed;
+ priv->not_owning_gboxed = TRUE;
- if (!boxed_init(context, object, priv, argc, argv))
+ /* We never actually read the reserved slot, but we put the parent object
+ * into it to hold onto the parent object.
+ */
+ JS_SetReservedSlot(context, object, 0,
+ unthreadsafe_template_for_constructor.parent_jsval);
+
+ unthreadsafe_template_for_constructor.parent_jsval = JSVAL_NULL;
+ unthreadsafe_template_for_constructor.gboxed = NULL;
+ } else if (unthreadsafe_template_for_constructor.no_copy) {
+ /* we need to create a JS Boxed which references the
+ * original C struct, not a copy of it. Used for
+ * G_SIGNAL_TYPE_STATIC_SCOPE
+ */
+ priv->gboxed = unthreadsafe_template_for_constructor.gboxed;
+ priv->not_owning_gboxed = TRUE;
+ unthreadsafe_template_for_constructor.gboxed = NULL;
+ } else {
+ GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ JSBool retval;
+
+ if (gtype != G_TYPE_NONE && g_type_is_a (gtype, G_TYPE_BOXED)) {
+ priv->gboxed = g_boxed_copy(gtype,
+ unthreadsafe_template_for_constructor.gboxed);
+ } else if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
+ priv->gboxed = g_variant_ref_sink (unthreadsafe_template_for_constructor.gboxed);
+ } else if (priv->can_allocate_directly) {
+ if (!boxed_new_direct(context, object, priv))
return JS_FALSE;
- } else if (!JSVAL_IS_NULL(unthreadsafe_template_for_constructor.parent_jsval)) {
- /* A structure nested inside a parent object; doens't have an independent allocation */
-
- priv->gboxed = unthreadsafe_template_for_constructor.gboxed;
- priv->not_owning_gboxed = TRUE;
-
- /* We never actually read the reserved slot, but we put the parent object
- * into it to hold onto the parent object.
- */
- JS_SetReservedSlot(context, object, 0,
- unthreadsafe_template_for_constructor.parent_jsval);
-
- unthreadsafe_template_for_constructor.parent_jsval = JSVAL_NULL;
- unthreadsafe_template_for_constructor.gboxed = NULL;
- } else if (unthreadsafe_template_for_constructor.no_copy) {
- /* we need to create a JS Boxed which references the
- * original C struct, not a copy of it. Used for
- * G_SIGNAL_TYPE_STATIC_SCOPE
- */
- priv->gboxed = unthreadsafe_template_for_constructor.gboxed;
- priv->not_owning_gboxed = TRUE;
- unthreadsafe_template_for_constructor.gboxed = NULL;
+ memcpy(priv->gboxed,
+ unthreadsafe_template_for_constructor.gboxed,
+ g_struct_info_get_size (priv->info));
} else {
- GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
- JSBool retval;
-
- if (gtype != G_TYPE_NONE && g_type_is_a (gtype, G_TYPE_BOXED)) {
- priv->gboxed = g_boxed_copy(gtype,
- unthreadsafe_template_for_constructor.gboxed);
- } else if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
- priv->gboxed = g_variant_ref_sink (unthreadsafe_template_for_constructor.gboxed);
- } else if (priv->can_allocate_directly) {
- if (!boxed_new_direct(context, object, priv))
- return JS_FALSE;
-
- memcpy(priv->gboxed,
- unthreadsafe_template_for_constructor.gboxed,
- g_struct_info_get_size (priv->info));
- } else {
- gjs_throw(context,
- "Can't create a Javascript object for %s; no way to copy",
- g_base_info_get_name( (GIBaseInfo*) priv->info));
- }
+ gjs_throw(context,
+ "Can't create a Javascript object for %s; no way to copy",
+ g_base_info_get_name( (GIBaseInfo*) priv->info));
+ }
- unthreadsafe_template_for_constructor.gboxed = NULL;
+ unthreadsafe_template_for_constructor.gboxed = NULL;
- retval = priv->gboxed != NULL;
- if (retval)
- GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
- return retval;
- }
+ retval = priv->gboxed != NULL;
+ if (retval)
+ GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
+ return retval;
}
GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
@@ -974,11 +947,6 @@ define_boxed_class_fields (JSContext *context,
* instances of the object, and to the prototype that instances of the
* class have.
*
- * Also, there's a constructor field in here, but as far as I can
- * tell, it would only be used if no constructor were provided to
- * JS_InitClass. The constructor from JS_InitClass is not applied to
- * the prototype unless JSCLASS_CONSTRUCT_PROTOTYPE is in flags.
- *
* We allocate 1 reserved slot; this is typically unused, but if the
* boxed is for a nested structure inside a parent structure, the
* reserved slot is used to hold onto the parent Javascript object and
@@ -989,7 +957,6 @@ static struct JSClass gjs_boxed_class = {
JSCLASS_HAS_PRIVATE |
JSCLASS_NEW_RESOLVE |
JSCLASS_NEW_RESOLVE_GETS_START |
- JSCLASS_CONSTRUCT_PROTOTYPE |
JSCLASS_HAS_RESERVED_SLOTS(1),
JS_PropertyStub,
JS_PropertyStub,
@@ -1251,12 +1218,10 @@ gjs_define_boxed_class(JSContext *context,
g_assert(gjs_object_has_property(context, in_object, constructor_name));
- /* Put the info in the prototype */
- priv = priv_from_js(context, prototype);
- g_assert(priv != NULL);
- g_assert(priv->info == NULL);
+ priv = g_slice_new0(Boxed);
priv->info = info;
g_base_info_ref( (GIBaseInfo*) priv->info);
+ JS_SetPrivate(context, prototype, priv);
gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p",
constructor_name, prototype, JS_GET_CLASS(context, prototype), in_object);
diff --git a/gi/function.c b/gi/function.c
index ef644da..5da2a9c 100644
--- a/gi/function.c
+++ b/gi/function.c
@@ -977,14 +977,6 @@ function_call(JSContext *context,
return success;
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
#ifdef JSFUN_CONSTRUCTOR
static JSBool
function_constructor(JSContext *context,
diff --git a/gi/keep-alive.c b/gi/keep-alive.c
index 28a7259..7553918 100644
--- a/gi/keep-alive.c
+++ b/gi/keep-alive.c
@@ -80,14 +80,6 @@ child_free(void *data)
g_slice_free(Child, child);
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(keep_alive)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(keep_alive)
diff --git a/gi/ns.c b/gi/ns.c
index 1033969..25057c0 100644
--- a/gi/ns.c
+++ b/gi/ns.c
@@ -145,14 +145,6 @@ ns_new_resolve(JSContext *context,
return ret;
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(ns)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(ns)
diff --git a/gi/object.c b/gi/object.c
index 6fefc61..a97bd8d 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -599,21 +599,13 @@ wrapped_gobj_toggle_notify(gpointer data,
}
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(object_instance)
ObjectInstance *priv;
ObjectInstance *proto_priv;
JSObject *proto;
- gboolean is_proto;
- JSClass *obj_class;
- JSClass *proto_class;
+ GType gtype;
GJS_NATIVE_CONSTRUCTOR_PRELUDE(object_instance);
@@ -630,135 +622,122 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
proto = JS_GetPrototype(context, object);
gjs_debug_lifecycle(GJS_DEBUG_GOBJECT, "obj instance __proto__ is %p", proto);
- /* If we're constructing the prototype, its __proto__ is not the same
- * class as us, but if we're constructing an instance, the prototype
- * has the same class.
- */
- obj_class = JS_GET_CLASS(context, object);
- proto_class = JS_GET_CLASS(context, proto);
-
- is_proto = (obj_class != proto_class);
-
gjs_debug_lifecycle(GJS_DEBUG_GOBJECT,
- "obj instance constructing proto %d, obj class %s proto class %s",
- is_proto, obj_class->name, proto_class->name);
+ "obj instance constructing, obj class %s proto class %s",
+ obj_class->name, proto_class->name);
- if (!is_proto) {
- GType gtype;
+ /* 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_GOBJECT,
+ "Bad prototype set on object? Must match JSClass of object. JS error should have been reported.");
+ return JS_FALSE;
+ }
- /* 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_GOBJECT,
- "Bad prototype set on object? Must match JSClass of object. JS error should have been reported.");
+ priv->info = proto_priv->info;
+ g_base_info_ref( (GIBaseInfo*) priv->info);
+
+ /* Since gobject-introspection is always creating new info
+ * objects, == is not meaningful on them, only comparison of
+ * their names. We prefer to use the info that is already ref'd
+ * by the prototype for the class.
+ */
+ g_assert(unthreadsafe_template_for_constructor.info == NULL ||
+ strcmp(g_base_info_get_name( (GIBaseInfo*) priv->info),
+ g_base_info_get_name( (GIBaseInfo*) unthreadsafe_template_for_constructor.info))
+ == 0);
+ unthreadsafe_template_for_constructor.info = NULL;
+
+ if (unthreadsafe_template_for_constructor.gobj == NULL) {
+ GParameter *params;
+ int n_params;
+ GTypeQuery query;
+
+ gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ if (gtype == G_TYPE_NONE) {
+ gjs_throw(context,
+ "No GType for object '%s'???",
+ g_base_info_get_name( (GIBaseInfo*) priv->info));
return JS_FALSE;
}
- priv->info = proto_priv->info;
- g_base_info_ref( (GIBaseInfo*) priv->info);
-
- /* Since gobject-introspection is always creating new info
- * objects, == is not meaningful on them, only comparison of
- * their names. We prefer to use the info that is already ref'd
- * by the prototype for the class.
- */
- g_assert(unthreadsafe_template_for_constructor.info == NULL ||
- strcmp(g_base_info_get_name( (GIBaseInfo*) priv->info),
- g_base_info_get_name( (GIBaseInfo*) unthreadsafe_template_for_constructor.info))
- == 0);
- unthreadsafe_template_for_constructor.info = NULL;
-
- if (unthreadsafe_template_for_constructor.gobj == NULL) {
- GParameter *params;
- int n_params;
- GTypeQuery query;
-
- gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
- if (gtype == G_TYPE_NONE) {
- gjs_throw(context,
- "No GType for object '%s'???",
- g_base_info_get_name( (GIBaseInfo*) priv->info));
- return JS_FALSE;
- }
+ if (!object_instance_props_to_g_parameters(context, object, argc, argv,
+ gtype,
+ ¶ms, &n_params)) {
+ return JS_FALSE;
+ }
- if (!object_instance_props_to_g_parameters(context, object, argc, argv,
- gtype,
- ¶ms, &n_params)) {
- return JS_FALSE;
- }
+ priv->gobj = g_object_newv(gtype, n_params, params);
+ free_g_params(params, n_params);
- priv->gobj = g_object_newv(gtype, n_params, params);
- free_g_params(params, n_params);
-
- g_type_query(gtype, &query);
- JS_updateMallocCounter(context, query.instance_size);
-
- if (G_IS_INITIALLY_UNOWNED(priv->gobj) &&
- !g_object_is_floating(priv->gobj)) {
- /* GtkWindow does not return a ref to caller of g_object_new.
- * Need a flag in gobject-introspection to tell us this.
- */
- gjs_debug(GJS_DEBUG_GOBJECT,
- "Newly-created object is initially unowned but we did not get the "
- "floating ref, probably GtkWindow, using hacky workaround");
- g_object_ref(priv->gobj);
- } else if (g_object_is_floating(priv->gobj)) {
- g_object_ref_sink(priv->gobj);
- } else {
- /* we should already have a ref */
- }
- } else {
- priv->gobj = unthreadsafe_template_for_constructor.gobj;
- unthreadsafe_template_for_constructor.gobj = NULL;
+ g_type_query(gtype, &query);
+ JS_updateMallocCounter(context, query.instance_size);
+ if (G_IS_INITIALLY_UNOWNED(priv->gobj) &&
+ !g_object_is_floating(priv->gobj)) {
+ /* GtkWindow does not return a ref to caller of g_object_new.
+ * Need a flag in gobject-introspection to tell us this.
+ */
+ gjs_debug(GJS_DEBUG_GOBJECT,
+ "Newly-created object is initially unowned but we did not get the "
+ "floating ref, probably GtkWindow, using hacky workaround");
+ g_object_ref(priv->gobj);
+ } else if (g_object_is_floating(priv->gobj)) {
g_object_ref_sink(priv->gobj);
+ } else {
+ /* we should already have a ref */
}
+ } else {
+ priv->gobj = unthreadsafe_template_for_constructor.gobj;
+ unthreadsafe_template_for_constructor.gobj = NULL;
- g_assert(peek_js_obj(context, priv->gobj) == NULL);
- set_js_obj(context, priv->gobj, object);
+ g_object_ref_sink(priv->gobj);
+ }
+
+ g_assert(peek_js_obj(context, priv->gobj) == NULL);
+ set_js_obj(context, priv->gobj, object);
#if DEBUG_DISPOSE
- g_object_weak_ref(priv->gobj, wrapped_gobj_dispose_notify, object);
+ g_object_weak_ref(priv->gobj, wrapped_gobj_dispose_notify, object);
#endif
- /* OK, here is where things get complicated. We want the
- * wrapped gobj to keep the JSObject* wrapper alive, because
- * people might set properties on the JSObject* that they care
- * about. Therefore, whenever the refcount on the wrapped gobj
- * is >1, i.e. whenever something other than the wrapper is
- * referencing the wrapped gobj, the wrapped gobj has a strong
- * ref (gc-roots the wrapper). When the refcount on the
- * wrapped gobj is 1, then we change to a weak ref to allow
- * the wrapper to be garbage collected (and thus unref the
- * wrappee).
- */
- priv->keep_alive = gjs_keep_alive_get_for_import_global(context);
- gjs_keep_alive_add_child(context,
- priv->keep_alive,
- gobj_no_longer_kept_alive_func,
- object,
- priv);
-
- g_object_add_toggle_ref(priv->gobj,
- wrapped_gobj_toggle_notify,
- JS_GetRuntime(context));
-
- /* We now have both a ref and a toggle ref, we only want the
- * toggle ref. This may immediately remove the GC root
- * we just added, since refcount may drop to 1.
- */
- g_object_unref(priv->gobj);
+ /* OK, here is where things get complicated. We want the
+ * wrapped gobj to keep the JSObject* wrapper alive, because
+ * people might set properties on the JSObject* that they care
+ * about. Therefore, whenever the refcount on the wrapped gobj
+ * is >1, i.e. whenever something other than the wrapper is
+ * referencing the wrapped gobj, the wrapped gobj has a strong
+ * ref (gc-roots the wrapper). When the refcount on the
+ * wrapped gobj is 1, then we change to a weak ref to allow
+ * the wrapper to be garbage collected (and thus unref the
+ * wrappee).
+ */
+ priv->keep_alive = gjs_keep_alive_get_for_import_global(context);
+ gjs_keep_alive_add_child(context,
+ priv->keep_alive,
+ gobj_no_longer_kept_alive_func,
+ object,
+ priv);
+
+ g_object_add_toggle_ref(priv->gobj,
+ wrapped_gobj_toggle_notify,
+ JS_GetRuntime(context));
+
+ /* We now have both a ref and a toggle ref, we only want the
+ * toggle ref. This may immediately remove the GC root
+ * we just added, since refcount may drop to 1.
+ */
+ g_object_unref(priv->gobj);
- gjs_debug_lifecycle(GJS_DEBUG_GOBJECT,
- "JSObject created with GObject %p %s",
- priv->gobj, g_type_name_from_instance((GTypeInstance*) priv->gobj));
+ gjs_debug_lifecycle(GJS_DEBUG_GOBJECT,
+ "JSObject created with GObject %p %s",
+ priv->gobj, g_type_name_from_instance((GTypeInstance*) priv->gobj));
- TRACE(GJS_OBJECT_PROXY_NEW(priv, priv->gobj, g_base_info_get_namespace ( (GIBaseInfo*) priv->info),
- g_base_info_get_name ( (GIBaseInfo*) priv->info) ));
- }
+ TRACE(GJS_OBJECT_PROXY_NEW(priv, priv->gobj, g_base_info_get_namespace ( (GIBaseInfo*) priv->info),
+ g_base_info_get_name ( (GIBaseInfo*) priv->info) ));
GJS_NATIVE_CONSTRUCTOR_FINISH(object_instance);
@@ -1129,21 +1108,11 @@ to_string_func(JSContext *context,
return ret;
}
-/* 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.
- *
- * Also, there's a constructor field in here, but as far as I can
- * tell, it would only be used if no constructor were provided to
- * JS_InitClass. The constructor from JS_InitClass is not applied to
- * the prototype unless JSCLASS_CONSTRUCT_PROTOTYPE is in flags.
- */
static struct JSClass gjs_object_instance_class = {
NULL, /* We copy this class struct with multiple names */
JSCLASS_HAS_PRIVATE |
JSCLASS_NEW_RESOLVE |
- JSCLASS_NEW_RESOLVE_GETS_START |
- JSCLASS_CONSTRUCT_PROTOTYPE,
+ JSCLASS_NEW_RESOLVE_GETS_START,
JS_PropertyStub,
JS_PropertyStub,
object_instance_get_prop,
@@ -1388,13 +1357,11 @@ gjs_define_object_class(JSContext *context,
g_assert(gjs_object_has_property(context, in_object, constructor_name));
- /* Put the info in the prototype */
- priv = priv_from_js(context, prototype);
- g_assert(priv != NULL);
- g_assert(priv->info == NULL);
+ priv = g_slice_new0(ObjectInstance);
priv->info = info;
g_base_info_ref( (GIBaseInfo*) priv->info);
priv->gtype = gtype;
+ JS_SetPrivate(context, prototype, priv);
gjs_debug(GJS_DEBUG_GOBJECT, "Defined class %s prototype %p class %p in object %p",
constructor_name, prototype, JS_GET_CLASS(context, prototype), in_object);
diff --git a/gi/param.c b/gi/param.c
index 7949f7e..8114a4a 100644
--- a/gi/param.c
+++ b/gi/param.c
@@ -140,23 +140,12 @@ param_new_resolve(JSContext *context,
return JS_TRUE;
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(param)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(param)
Param *priv;
Param *proto_priv;
- JSClass *obj_class;
- JSClass *proto_class;
JSObject *proto;
- gboolean is_proto;
GJS_NATIVE_CONSTRUCTOR_PRELUDE(param);
@@ -175,48 +164,37 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(param)
proto = JS_GetPrototype(context, object);
gjs_debug_lifecycle(GJS_DEBUG_GPARAM, "param instance __proto__ is %p", proto);
- /* If we're constructing the prototype, its __proto__ is not the same
- * class as us, but if we're constructing an instance, the prototype
- * has the same class.
- */
- obj_class = JS_GET_CLASS(context, object);
- proto_class = JS_GET_CLASS(context, proto);
-
- is_proto = (obj_class != proto_class);
-
gjs_debug_lifecycle(GJS_DEBUG_GPARAM,
"param instance constructing proto %d, obj class %s proto class %s",
is_proto, obj_class->name, proto_class->name);
- if (!is_proto) {
- /* 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_GPARAM,
- "Bad prototype set on object? Must match JSClass of object. JS error should have been reported.");
- return JS_FALSE;
- }
-
- if (unthreadsafe_template_for_constructor.gparam == NULL) {
- /* To construct these we'd have to wrap all the annoying subclasses.
- * Since we only bind ParamSpec for purposes of the GObject::notify signal,
- * there isn't much point.
- */
- gjs_throw(context, "Unable to construct ParamSpec, can only wrap an existing one");
- return JS_FALSE;
- } else {
- priv->gparam = g_param_spec_ref(unthreadsafe_template_for_constructor.gparam);
- unthreadsafe_template_for_constructor.gparam = NULL;
- }
-
+ /* 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_GPARAM,
- "JSObject created with param instance %p type %s",
- priv->gparam, g_type_name(G_TYPE_FROM_INSTANCE((GTypeInstance*) priv->gparam)));
+ "Bad prototype set on object? Must match JSClass of object. JS error should have been reported.");
+ return JS_FALSE;
}
+ if (unthreadsafe_template_for_constructor.gparam == NULL) {
+ /* To construct these we'd have to wrap all the annoying subclasses.
+ * Since we only bind ParamSpec for purposes of the GObject::notify signal,
+ * there isn't much point.
+ */
+ gjs_throw(context, "Unable to construct ParamSpec, can only wrap an existing one");
+ return JS_FALSE;
+ } else {
+ priv->gparam = g_param_spec_ref(unthreadsafe_template_for_constructor.gparam);
+ unthreadsafe_template_for_constructor.gparam = NULL;
+ }
+
+ gjs_debug(GJS_DEBUG_GPARAM,
+ "JSObject created with param instance %p type %s",
+ priv->gparam, g_type_name(G_TYPE_FROM_INSTANCE((GTypeInstance*) priv->gparam)));
+
GJS_NATIVE_CONSTRUCTOR_FINISH(param);
return JS_TRUE;
@@ -256,8 +234,7 @@ static struct JSClass gjs_param_class = {
NULL, /* dynamic */
JSCLASS_HAS_PRIVATE |
JSCLASS_NEW_RESOLVE |
- JSCLASS_NEW_RESOLVE_GETS_START |
- JSCLASS_CONSTRUCT_PROTOTYPE,
+ JSCLASS_NEW_RESOLVE_GETS_START,
JS_PropertyStub,
JS_PropertyStub,
param_get_prop,
diff --git a/gi/repo.c b/gi/repo.c
index 6a92f08..b7637b8 100644
--- a/gi/repo.c
+++ b/gi/repo.c
@@ -189,14 +189,6 @@ repo_new_resolve(JSContext *context,
return ret;
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(repo)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(repo)
diff --git a/gi/union.c b/gi/union.c
index b5f8f9a..06d9300 100644
--- a/gi/union.c
+++ b/gi/union.c
@@ -188,23 +188,13 @@ union_new(JSContext *context,
return NULL;
}
-/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
- * the prototype in addition to on each instance. When called on the
- * prototype, "obj" is the prototype, and "retval" is the prototype
- * also, but can be replaced with another object to use instead as the
- * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
- * identify the prototype as an object of our class with NULL private
- * data.
- */
GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(union)
Union *priv;
Union *proto_priv;
- JSClass *obj_class;
- JSClass *proto_class;
JSObject *proto;
- gboolean is_proto;
+ GType gtype;
GJS_NATIVE_CONSTRUCTOR_PRELUDE(union);
@@ -224,78 +214,65 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
proto = JS_GetPrototype(context, object);
gjs_debug_lifecycle(GJS_DEBUG_GBOXED, "union instance __proto__ is %p", proto);
- /* If we're constructing the prototype, its __proto__ is not the same
- * class as us, but if we're constructing an instance, the prototype
- * has the same class.
- */
- obj_class = JS_GET_CLASS(context, object);
- proto_class = JS_GET_CLASS(context, proto);
-
- is_proto = (obj_class != proto_class);
-
gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
"union instance constructing proto %d, obj class %s proto class %s",
is_proto, obj_class->name, proto_class->name);
- if (!is_proto) {
- GType gtype;
-
- /* 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 JS_FALSE;
- }
+ /* 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 JS_FALSE;
+ }
- priv->info = proto_priv->info;
- g_base_info_ref( (GIBaseInfo*) priv->info);
+ priv->info = proto_priv->info;
+ g_base_info_ref( (GIBaseInfo*) priv->info);
- gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
- /* Since gobject-introspection is always creating new info
- * objects, == is not meaningful on them, only comparison of
- * their names. We prefer to use the info that is already ref'd
- * by the prototype for the class.
+ /* Since gobject-introspection is always creating new info
+ * objects, == is not meaningful on them, only comparison of
+ * their names. We prefer to use the info that is already ref'd
+ * by the prototype for the class.
+ */
+ g_assert(unthreadsafe_template_for_constructor.info == NULL ||
+ strcmp(g_base_info_get_name( (GIBaseInfo*) priv->info),
+ g_base_info_get_name( (GIBaseInfo*) unthreadsafe_template_for_constructor.info))
+ == 0);
+ unthreadsafe_template_for_constructor.info = NULL;
+
+ if (unthreadsafe_template_for_constructor.gboxed == NULL) {
+ void *gboxed;
+
+ /* union_new happens to be implemented by calling
+ * gjs_invoke_c_function(), which returns a jsval.
+ * The returned "gboxed" here is owned by that jsval,
+ * not by us.
*/
- g_assert(unthreadsafe_template_for_constructor.info == NULL ||
- strcmp(g_base_info_get_name( (GIBaseInfo*) priv->info),
- g_base_info_get_name( (GIBaseInfo*) unthreadsafe_template_for_constructor.info))
- == 0);
- unthreadsafe_template_for_constructor.info = NULL;
-
- if (unthreadsafe_template_for_constructor.gboxed == NULL) {
- void *gboxed;
-
- /* union_new happens to be implemented by calling
- * gjs_invoke_c_function(), which returns a jsval.
- * The returned "gboxed" here is owned by that jsval,
- * not by us.
- */
- gboxed = union_new(context, object, priv->info);
+ gboxed = union_new(context, object, priv->info);
- if (gboxed == NULL) {
- return JS_FALSE;
- }
-
- /* Because "gboxed" is owned by a jsval and will
- * be garbage colleced, we make a copy here to be
- * owned by us.
- */
- priv->gboxed = g_boxed_copy(gtype, gboxed);
- } else {
- priv->gboxed = g_boxed_copy(gtype, unthreadsafe_template_for_constructor.gboxed);
- unthreadsafe_template_for_constructor.gboxed = NULL;
+ if (gboxed == NULL) {
+ return JS_FALSE;
}
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
- "JSObject created with union instance %p type %s",
- priv->gboxed, g_type_name(gtype));
+ /* Because "gboxed" is owned by a jsval and will
+ * be garbage colleced, we make a copy here to be
+ * owned by us.
+ */
+ priv->gboxed = g_boxed_copy(gtype, gboxed);
+ } else {
+ priv->gboxed = g_boxed_copy(gtype, unthreadsafe_template_for_constructor.gboxed);
+ unthreadsafe_template_for_constructor.gboxed = NULL;
}
+ gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
+ "JSObject created with union instance %p type %s",
+ priv->gboxed, g_type_name(gtype));
+
GJS_NATIVE_CONSTRUCTOR_FINISH(union);
return JS_TRUE;
@@ -341,8 +318,7 @@ static struct JSClass gjs_union_class = {
NULL, /* dynamic class, no name here */
JSCLASS_HAS_PRIVATE |
JSCLASS_NEW_RESOLVE |
- JSCLASS_NEW_RESOLVE_GETS_START |
- JSCLASS_CONSTRUCT_PROTOTYPE,
+ JSCLASS_NEW_RESOLVE_GETS_START,
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
@@ -498,12 +474,10 @@ gjs_define_union_class(JSContext *context,
g_assert(gjs_object_has_property(context, in_object, constructor_name));
- /* Put the info in the prototype */
- priv = priv_from_js(context, prototype);
- g_assert(priv != NULL);
- g_assert(priv->info == NULL);
+ priv = g_slice_new0(Union);
priv->info = info;
g_base_info_ref( (GIBaseInfo*) priv->info);
+ JS_SetPrivate(context, prototype, priv);
gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p",
constructor_name, prototype, JS_GET_CLASS(context, prototype), in_object);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]