[gjs] Remove the unthreadsafe_template_for_constructor
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] Remove the unthreadsafe_template_for_constructor
- Date: Mon, 28 Nov 2011 19:45:32 +0000 (UTC)
commit 740cf9dbb8a6c9e441a2d4b60352314e2282c288
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Fri Nov 4 22:54:23 2011 -0400
Remove the unthreadsafe_template_for_constructor
Rather than setting a magic global which can get un-stuck at times, use the
JSAPI equivalent of ES5's Object.create to create an object without running
the constructor, so we can set a gobject ourselves
https://bugzilla.gnome.org/show_bug.cgi?id=663441
gi/boxed.c | 205 +++++++++++++++++++++++++----------------------------------
gi/object.c | 159 +++++++++++++++++++++++++---------------------
gi/param.c | 69 ++++----------------
gi/union.c | 74 ++++++++++-----------
4 files changed, 221 insertions(+), 286 deletions(-)
---
diff --git a/gi/boxed.c b/gi/boxed.c
index 2be87e5..2edb2fc 100644
--- a/gi/boxed.c
+++ b/gi/boxed.c
@@ -48,13 +48,6 @@ typedef struct {
the reference to the C gboxed */
} Boxed;
-typedef struct {
- GIBoxedInfo *info;
- void *gboxed;
- jsval parent_jsval;
- gboolean no_copy;
-} BoxedConstructInfo;
-
static gboolean struct_is_simple(GIStructInfo *info);
static JSBool boxed_set_field_from_value(JSContext *context,
@@ -62,8 +55,6 @@ static JSBool boxed_set_field_from_value(JSContext *context,
GIFieldInfo *field_info,
jsval value);
-static BoxedConstructInfo unthreadsafe_template_for_constructor = { NULL, NULL, JSVAL_NULL, FALSE };
-
static struct JSClass gjs_boxed_class;
GJS_DEFINE_DYNAMIC_PRIV_FROM_JS(Boxed, gjs_boxed_class)
@@ -433,6 +424,8 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
Boxed *priv;
Boxed *proto_priv;
JSObject *proto;
+ Boxed *source_priv;
+ GType gtype;
GJS_NATIVE_CONSTRUCTOR_PRELUDE(boxed);
@@ -464,98 +457,32 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(boxed)
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 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 (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;
- }
- }
-
- /* 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;
- }
-
- if (!boxed_new(context, object, priv))
- return JS_FALSE;
-
- if (!boxed_init(context, object, priv, argc, argv))
- 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;
- } else {
- GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
- JSBool retval;
+ gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ /* 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 (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));
+ priv->gboxed = g_boxed_copy(gtype, source_priv->gboxed);
+ GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
+ return JS_TRUE;
}
+ }
- unthreadsafe_template_for_constructor.gboxed = NULL;
-
- retval = priv->gboxed != NULL;
- if (retval)
- GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
- return retval;
+ /* 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;
}
+ if (!boxed_new(context, object, priv))
+ return JS_FALSE;
+
+ if (!boxed_init(context, object, priv, argc, argv))
+ return JS_FALSE;
+
GJS_NATIVE_CONSTRUCTOR_FINISH(boxed);
return JS_TRUE;
@@ -639,6 +566,8 @@ get_nested_interface_object (JSContext *context,
JSObject *obj;
JSObject *proto;
int offset;
+ Boxed *priv;
+ Boxed *proto_priv;
if (!struct_is_simple ((GIStructInfo *)interface_info)) {
gjs_throw(context, "Reading field %s.%s is not supported",
@@ -649,28 +578,35 @@ get_nested_interface_object (JSContext *context,
}
proto = gjs_lookup_boxed_prototype(context, (GIBoxedInfo*) interface_info);
+ proto_priv = priv_from_js(context, proto);
offset = g_field_info_get_offset (field_info);
- unthreadsafe_template_for_constructor.info = (GIBoxedInfo*) interface_info;
- unthreadsafe_template_for_constructor.gboxed = ((char *)parent_priv->gboxed) + offset;
- /* Rooting the object here is a little paranoid; the JSObject has to be kept
- * alive anyways by our caller; so this would matter only if there was an
- * aggressive GC that moved rooted objects */
- JS_AddValueRoot(context, &unthreadsafe_template_for_constructor.parent_jsval);
- unthreadsafe_template_for_constructor.parent_jsval = OBJECT_TO_JSVAL(parent_obj);
+ obj = JS_NewObjectWithGivenProto(context,
+ JS_GET_CLASS(context, proto), proto,
+ gjs_get_import_global (context));
- obj = gjs_construct_object_dynamic(context, proto,
- 0, NULL);
+ if (obj == NULL)
+ return JS_FALSE;
- JS_RemoveValueRoot(context, &unthreadsafe_template_for_constructor.parent_jsval);
+ priv = g_slice_new0(Boxed);
+ JS_SetPrivate(context, obj, priv);
+ priv->info = (GIBoxedInfo*) interface_info;
+ g_base_info_ref( (GIBaseInfo*) priv->info);
+ priv->can_allocate_directly = proto_priv->can_allocate_directly;
- if (obj != NULL) {
- *value = OBJECT_TO_JSVAL(obj);
- return JS_TRUE;
- } else {
- return JS_FALSE;
- }
+ /* A structure nested inside a parent object; doesn't have an independent allocation */
+ priv->gboxed = ((char *)parent_priv->gboxed) + offset;
+ 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, obj, 0,
+ OBJECT_TO_JSVAL (parent_obj));
+
+ *value = OBJECT_TO_JSVAL(obj);
+ return JS_TRUE;
}
static JSBool
@@ -1258,7 +1194,10 @@ gjs_boxed_from_c_struct(JSContext *context,
void *gboxed,
GjsBoxedCreationFlags flags)
{
+ JSObject *obj;
JSObject *proto;
+ Boxed *priv;
+ Boxed *proto_priv;
if (gboxed == NULL)
return NULL;
@@ -1268,15 +1207,45 @@ gjs_boxed_from_c_struct(JSContext *context,
g_base_info_get_name((GIBaseInfo *)info), gboxed);
proto = gjs_lookup_boxed_prototype(context, info);
+ proto_priv = priv_from_js(context, proto);
- /* can't come up with a better approach... */
- unthreadsafe_template_for_constructor.info = info;
- unthreadsafe_template_for_constructor.gboxed = gboxed;
- unthreadsafe_template_for_constructor.parent_jsval = JSVAL_NULL;
- unthreadsafe_template_for_constructor.no_copy = (flags & GJS_BOXED_CREATION_NO_COPY) != 0;
+ obj = JS_NewObjectWithGivenProto(context,
+ JS_GET_CLASS(context, proto), proto,
+ gjs_get_import_global (context));
+
+ priv = g_slice_new0(Boxed);
+ JS_SetPrivate(context, obj, priv);
+ priv->info = info;
+ g_base_info_ref( (GIBaseInfo*) priv->info);
+ priv->can_allocate_directly = proto_priv->can_allocate_directly;
+
+ if ((flags & GJS_BOXED_CREATION_NO_COPY) != 0) {
+ /* 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 = gboxed;
+ priv->not_owning_gboxed = TRUE;
+ } else {
+ GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) info);
+
+ if (gtype != G_TYPE_NONE && g_type_is_a (gtype, G_TYPE_BOXED)) {
+ priv->gboxed = g_boxed_copy(gtype, gboxed);
+ } else if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
+ priv->gboxed = g_variant_ref_sink (gboxed);
+ } else if (priv->can_allocate_directly) {
+ if (!boxed_new_direct(context, obj, priv))
+ return JS_FALSE;
+
+ memcpy(priv->gboxed, 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));
+ }
+ }
- return gjs_construct_object_dynamic(context, proto,
- 0, NULL);
+ return obj;
}
void*
diff --git a/gi/object.c b/gi/object.c
index a97bd8d..90993a3 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -49,8 +49,6 @@ typedef struct {
GType gtype;
} ObjectInstance;
-static ObjectInstance unthreadsafe_template_for_constructor = { NULL, NULL };
-
static struct JSClass gjs_object_instance_class;
GJS_DEFINE_DYNAMIC_PRIV_FROM_JS(ObjectInstance, gjs_object_instance_class)
@@ -599,15 +597,15 @@ wrapped_gobj_toggle_notify(gpointer data,
}
}
-GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
+static ObjectInstance *
+init_object_private (JSContext *context,
+ JSObject *object)
{
- GJS_NATIVE_CONSTRUCTOR_VARIABLES(object_instance)
- ObjectInstance *priv;
ObjectInstance *proto_priv;
+ ObjectInstance *priv;
JSObject *proto;
- GType gtype;
- GJS_NATIVE_CONSTRUCTOR_PRELUDE(object_instance);
+ JS_BeginRequest(context);
priv = g_slice_new0(ObjectInstance);
@@ -626,77 +624,27 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
"obj instance constructing, obj class %s proto class %s",
obj_class->name, proto_class->name);
- /* 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;
+ priv = NULL;
+ goto out;
}
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;
- }
-
- 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_object_ref_sink(priv->gobj);
- }
+ out:
+ JS_EndRequest(context);
+ return priv;
+}
+static void
+manage_js_gobject (JSContext *context,
+ JSObject *object,
+ ObjectInstance *priv)
+{
g_assert(peek_js_obj(context, priv->gobj) == NULL);
set_js_obj(context, priv->gobj, object);
@@ -731,6 +679,57 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
* we just added, since refcount may drop to 1.
*/
g_object_unref(priv->gobj);
+}
+
+GJS_NATIVE_CONSTRUCTOR_DECLARE(object_instance)
+{
+ GJS_NATIVE_CONSTRUCTOR_VARIABLES(object_instance)
+ ObjectInstance *priv;
+ GType gtype;
+ GParameter *params;
+ int n_params;
+ GTypeQuery query;
+
+ GJS_NATIVE_CONSTRUCTOR_PRELUDE(object_instance);
+
+ priv = init_object_private(context, object);
+
+ 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;
+ }
+
+ 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 */
+ }
+
+ manage_js_gobject(context, object, priv);
gjs_debug_lifecycle(GJS_DEBUG_GOBJECT,
"JSObject created with GObject %p %s",
@@ -1474,6 +1473,7 @@ gjs_object_from_g_object(JSContext *context,
/* We have to create a wrapper */
JSObject *proto;
GIObjectInfo *info;
+ ObjectInstance *priv;
gjs_debug_marshal(GJS_DEBUG_GOBJECT,
"Wrapping %s with JSObject",
@@ -1482,18 +1482,31 @@ gjs_object_from_g_object(JSContext *context,
if (!gjs_define_object_class(context, NULL, G_TYPE_FROM_INSTANCE(gobj), NULL, &proto, &info))
return NULL;
- /* can't come up with a better approach... */
- unthreadsafe_template_for_constructor.info = (GIObjectInfo*) info;
- unthreadsafe_template_for_constructor.gobj = gobj;
- obj = gjs_construct_object_dynamic(context, proto,
- 0, NULL);
+ JS_BeginRequest(context);
+
+ obj = JS_NewObjectWithGivenProto(context,
+ JS_GET_CLASS(context, proto), proto,
+ gjs_get_import_global (context));
+
+ JS_EndRequest(context);
+
+ if (obj == NULL)
+ goto out;
+
+ priv = init_object_private(context, obj);
+ priv->gobj = gobj;
+
+ g_object_ref_sink (gobj);
+
+ manage_js_gobject(context, obj, priv);
g_base_info_unref( (GIBaseInfo*) info);
g_assert(peek_js_obj(context, gobj) == obj);
}
+ out:
return obj;
}
diff --git a/gi/param.c b/gi/param.c
index 8114a4a..a4acc18 100644
--- a/gi/param.c
+++ b/gi/param.c
@@ -38,8 +38,6 @@ typedef struct {
GParamSpec *gparam; /* NULL if we are the prototype and not an instance */
} Param;
-static Param unthreadsafe_template_for_constructor = { NULL };
-
static struct JSClass gjs_param_class;
GJS_DEFINE_DYNAMIC_PRIV_FROM_JS(Param, gjs_param_class)
@@ -143,60 +141,9 @@ param_new_resolve(JSContext *context,
GJS_NATIVE_CONSTRUCTOR_DECLARE(param)
{
GJS_NATIVE_CONSTRUCTOR_VARIABLES(param)
- Param *priv;
- Param *proto_priv;
- JSObject *proto;
-
GJS_NATIVE_CONSTRUCTOR_PRELUDE(param);
-
- (void) argv;
-
- priv = g_slice_new0(Param);
-
GJS_INC_COUNTER(param);
-
- g_assert(priv_from_js(context, object) == NULL);
- JS_SetPrivate(context, object, priv);
-
- gjs_debug_lifecycle(GJS_DEBUG_GPARAM,
- "param constructor, obj %p priv %p", object, priv);
-
- proto = JS_GetPrototype(context, object);
- gjs_debug_lifecycle(GJS_DEBUG_GPARAM, "param instance __proto__ is %p", proto);
-
- 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 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;
- }
-
- 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;
}
@@ -358,6 +305,7 @@ gjs_param_from_g_param(JSContext *context,
{
JSObject *obj;
JSObject *proto;
+ Param *priv;
if (gparam == NULL)
return NULL;
@@ -370,11 +318,18 @@ gjs_param_from_g_param(JSContext *context,
proto = gjs_lookup_param_prototype(context);
- /* can't come up with a better approach... */
- unthreadsafe_template_for_constructor.gparam = gparam;
+ obj = JS_NewObjectWithGivenProto(context,
+ JS_GET_CLASS(context, proto), proto,
+ gjs_get_import_global (context));
+
+ priv = g_slice_new0(Param);
+ JS_SetPrivate(context, obj, priv);
+ priv->gparam = gparam;
+ g_param_spec_ref (gparam);
- obj = gjs_construct_object_dynamic(context, proto,
- 0, 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)));
return obj;
}
diff --git a/gi/union.c b/gi/union.c
index 06d9300..09a26b6 100644
--- a/gi/union.c
+++ b/gi/union.c
@@ -46,8 +46,6 @@ typedef struct {
void *gboxed; /* NULL if we are the prototype and not an instance */
} Union;
-static Union unthreadsafe_template_for_constructor = { NULL, NULL };
-
static struct JSClass gjs_union_class;
GJS_DEFINE_DYNAMIC_PRIV_FROM_JS(Union, gjs_union_class)
@@ -195,6 +193,7 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
Union *proto_priv;
JSObject *proto;
GType gtype;
+ void *gboxed;
GJS_NATIVE_CONSTRUCTOR_PRELUDE(union);
@@ -234,41 +233,23 @@ GJS_NATIVE_CONSTRUCTOR_DECLARE(union)
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.
+ /* 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);
-
- if (gboxed == NULL) {
- return JS_FALSE;
- }
+ gboxed = union_new(context, object, priv->info);
- /* 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;
}
+ /* Because "gboxed" is owned by a jsval and will
+ * be garbage collected, we make a copy here to be
+ * owned by us.
+ */
+ priv->gboxed = g_boxed_copy(gtype, gboxed);
+
gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
"JSObject created with union instance %p type %s",
priv->gboxed, g_type_name(gtype));
@@ -507,23 +488,40 @@ gjs_union_from_c_union(JSContext *context,
GIUnionInfo *info,
void *gboxed)
{
+ JSObject *obj;
JSObject *proto;
+ Union *priv;
+ GType gtype;
if (gboxed == NULL)
return NULL;
+ /* For certain unions, we may be able to relax this in the future by
+ * directly allocating union memory, as we do for structures in boxed.c
+ */
+ gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) info);
+ if (gtype == G_TYPE_NONE) {
+ gjs_throw(context, "Unions must currently be registered as boxed types");
+ return NULL;
+ }
+
gjs_debug_marshal(GJS_DEBUG_GBOXED,
"Wrapping union %s %p with JSObject",
g_base_info_get_name((GIBaseInfo *)info), gboxed);
proto = gjs_lookup_union_prototype(context, (GIUnionInfo*) info);
- /* can't come up with a better approach... */
- unthreadsafe_template_for_constructor.info = (GIUnionInfo*) info;
- unthreadsafe_template_for_constructor.gboxed = gboxed;
+ obj = JS_NewObjectWithGivenProto(context,
+ JS_GET_CLASS(context, proto), proto,
+ gjs_get_import_global (context));
+
+ priv = g_slice_new0(Union);
+ JS_SetPrivate(context, obj, priv);
+ priv->info = info;
+ g_base_info_ref( (GIBaseInfo *) priv->info);
+ priv->gboxed = g_boxed_copy(gtype, gboxed);
- return gjs_construct_object_dynamic(context, proto,
- 0, NULL);
+ return obj;
}
void*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]