[gjs] Remove the unthreadsafe_template_for_constructor



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,
-                                                   &params, &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,
+                                               &params, &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]