Beispiel #1
0
static JSObject*
importer_new(JSContext    *context)
{
    JSObject *importer;
    Importer *priv;
    JSObject *global;
    (void) priv;

    global = gjs_get_import_global(context);

    if (!gjs_object_has_property(context, global, gjs_importer_class.name)) {
        JSObject *prototype;
        prototype = JS_InitClass(context, global,
                                 /* parent prototype JSObject* for
                                  * prototype; NULL for
                                  * Object.prototype
                                  */
                                 NULL,
                                 &gjs_importer_class,
                                 /* constructor for instances (NULL for
                                  * none - just name the prototype like
                                  * Math - rarely correct)
                                  */
                                 gjs_importer_constructor,
                                 /* number of constructor args */
                                 0,
                                 /* props of prototype */
                                 &gjs_importer_proto_props[0],
                                 /* funcs of prototype */
                                 &gjs_importer_proto_funcs[0],
                                 /* props of constructor, MyConstructor.myprop */
                                 NULL,
                                 /* funcs of constructor, MyConstructor.myfunc() */
                                 NULL);
        if (prototype == NULL)
            gjs_fatal("Can't init class %s", gjs_importer_class.name);

        g_assert(gjs_object_has_property(context, global, gjs_importer_class.name));

        gjs_debug(GJS_DEBUG_IMPORTER, "Initialized class %s prototype %p",
                  gjs_importer_class.name, prototype);
    }

    importer = JS_NewObject(context, &gjs_importer_class, NULL, global);
    if (importer == NULL)
        gjs_fatal("No memory to create importer importer");

    priv = g_slice_new0(Importer);

    GJS_INC_COUNTER(importer);

    g_assert(priv_from_js(context, importer) == NULL);
    JS_SetPrivate(importer, priv);

    gjs_debug_lifecycle(GJS_DEBUG_IMPORTER,
                        "importer constructor, obj %p priv %p", importer, priv);

    return importer;
}
Beispiel #2
0
/* If this were called twice for the same runtime with different args it
 * would basically be a bug, but checking for that is a lot of code so
 * we just ignore all calls after the first and hope the args are the same.
 */
JSBool
gjs_create_root_importer(JSContext   *context,
                         const char **initial_search_path,
                         gboolean     add_standard_search_path)
{
    JSObject *global;

    global = gjs_get_import_global(context);

    JS_BeginRequest(context);

    if (!gjs_object_has_property(context,
                                 global,
                                 "imports")) {
        if (gjs_define_importer(context, global,
                                "imports",
                                initial_search_path, add_standard_search_path) == NULL) {
            JS_EndRequest(context);
            return JS_FALSE;
        }
    } else {
        gjs_debug(GJS_DEBUG_IMPORTER,
                  "Someone else already created root importer, ignoring second request");
        JS_EndRequest(context);
        return JS_TRUE;
    }

    JS_EndRequest(context);
    return JS_TRUE;
}
Beispiel #3
0
void
gjs_log_exception_props(JSContext *context,
                        jsval      exc)
{
    JS_BeginRequest(context);

    /* This is useful when the exception was never sent to an error reporter
     * due to JSOPTION_DONT_REPORT_UNCAUGHT, or if the exception was not
     * a normal Error object so jsapi didn't know how to report it sensibly.
     */
    if (JSVAL_IS_NULL(exc)) {
        gjs_debug(GJS_DEBUG_ERROR,
                  "Exception was null");
    } else if (JSVAL_IS_OBJECT(exc)) {
        JSObject *exc_obj;

        exc_obj = JSVAL_TO_OBJECT(exc);

        /* I guess this is a SpiderMonkey bug.  If we don't get these
         * properties here, only 'message' shows up when we enumerate
         * all properties below. I did not debug in detail, so maybe
         * it's something wrong with our enumeration loop below. In
         * any case, if you remove this code block, check that "throw
         * Error()" still results in printing all four of these props.
         * For me right now, if you remove this block, only message
         * gets printed.
         */
        gjs_object_has_property(context, exc_obj, "stack");
        gjs_object_has_property(context, exc_obj, "fileName");
        gjs_object_has_property(context, exc_obj, "lineNumber");
        gjs_object_has_property(context, exc_obj, "message");

        gjs_log_object_props(context, exc_obj,
                             GJS_DEBUG_ERROR,
                             "  ");
    } else if (JSVAL_IS_STRING(exc)) {
        gjs_debug(GJS_DEBUG_ERROR,
                  "Exception was a String");
    } else {
        gjs_debug(GJS_DEBUG_ERROR,
                  "Exception had some strange type");
    }
    JS_EndRequest(context);
}
Beispiel #4
0
JSObject*
gjs_keep_alive_new(JSContext *context)
{
    JSObject *keep_alive;
    JSObject *global;

    /* This function creates an unattached KeepAlive object; following our
     * general strategy, we have a single KeepAlive class with a constructor
     * stored on our single "load global" pseudo-global object, and we create
     * instances with the load global as parent.
     */

    g_assert(context != NULL);

    JS_BeginRequest(context);

    global = gjs_get_import_global(context);

    g_assert(global != NULL);

    if (!gjs_object_has_property(context, global, gjs_keep_alive_class.name)) {
        JSObject *prototype;

        gjs_debug(GJS_DEBUG_KEEP_ALIVE,
                  "Initializing keep-alive class in context %p global %p",
                  context, global);

        prototype = JS_InitClass(context, global,
                                 /* parent prototype JSObject* for
                                  * prototype; NULL for
                                  * Object.prototype
                                  */
                                 NULL,
                                 &gjs_keep_alive_class,
                                 /* constructor for instances (NULL for
                                  * none - just name the prototype like
                                  * Math - rarely correct)
                                  */
                                 gjs_keep_alive_constructor,
                                 /* number of constructor args */
                                 0,
                                 /* props of prototype */
                                 &gjs_keep_alive_proto_props[0],
                                 /* funcs of prototype */
                                 &gjs_keep_alive_proto_funcs[0],
                                 /* props of constructor, MyConstructor.myprop */
                                 NULL,
                                 /* funcs of constructor, MyConstructor.myfunc() */
                                 NULL);
        if (prototype == NULL)
            gjs_fatal("Can't init class %s", gjs_keep_alive_class.name);

        g_assert(gjs_object_has_property(context, global, gjs_keep_alive_class.name));

        gjs_debug(GJS_DEBUG_KEEP_ALIVE, "Initialized class %s prototype %p",
                  gjs_keep_alive_class.name, prototype);
    }

    gjs_debug(GJS_DEBUG_KEEP_ALIVE,
              "Creating new keep-alive object for context %p global %p",
              context, global);

    keep_alive = JS_ConstructObject(context, &gjs_keep_alive_class, NULL, global);
    if (keep_alive == NULL) {
        gjs_log_exception(context, NULL);
        gjs_fatal("Failed to create keep_alive object");
    }

    JS_EndRequest(context);

    return keep_alive;
}
Beispiel #5
0
JSBool
gjs_define_error_class(JSContext    *context,
                       JSObject     *in_object,
                       GIEnumInfo   *info,
                       JSObject    **constructor_p,
                       JSObject    **prototype_p)
{
    const char *constructor_name;
    GIBoxedInfo *glib_error_info;
    JSObject *prototype, *parent_proto;
    JSObject *constructor;
    jsval value;
    Error *priv;

    /* See the comment in gjs_define_boxed_class() for an
     * explanation of how this all works; Error is pretty much the
     * same as Boxed (except that we inherit from GLib.Error).
     */

    constructor_name = g_base_info_get_name( (GIBaseInfo*) info);

    if (gjs_object_get_property(context, in_object, constructor_name, &value)) {
        JSObject *constructor;

        if (!JSVAL_IS_OBJECT(value)) {
            gjs_throw(context, "Existing property '%s' does not look like a constructor",
                         constructor_name);
            return JS_FALSE;
        }

        constructor = JSVAL_TO_OBJECT(value);

        gjs_object_get_property(context, constructor, "prototype", &value);
        if (!JSVAL_IS_OBJECT(value)) {
            gjs_throw(context, "error %s prototype property does not appear to exist or has wrong type", constructor_name);
            return JS_FALSE;
        } else {
            if (prototype_p)
                *prototype_p = JSVAL_TO_OBJECT(value);
            if (constructor_p)
                *constructor_p = constructor;

            return JS_TRUE;
        }
    }

    g_irepository_require(NULL, "GLib", "2.0", 0, NULL);
    glib_error_info = (GIBoxedInfo*) g_irepository_find_by_name(NULL, "GLib", "Error");
    parent_proto = gjs_lookup_boxed_prototype(context, glib_error_info);
    g_base_info_unref((GIBaseInfo*)glib_error_info);

    prototype = gjs_init_class_dynamic(context, in_object,
                                          parent_proto,
                                          g_base_info_get_namespace( (GIBaseInfo*) info),
                                          constructor_name,
                                          &gjs_error_class,
                                          gjs_error_constructor,
                                          /* number of constructor args (less can be passed) */
                                          1,
                                          /* props of prototype */
                                          &gjs_error_proto_props[0],
                                          /* funcs of prototype */
                                          &gjs_error_proto_funcs[0],
                                          /* props of constructor, MyConstructor.myprop */
                                          NULL,
                                          /* funcs of constructor, MyConstructor.myfunc() */
                                          &gjs_error_constructor_funcs[0]);
    if (prototype == NULL) {
        gjs_log_exception(context, NULL);
        gjs_fatal("Can't init class %s", constructor_name);
    }

    g_assert(gjs_object_has_property(context, in_object, constructor_name));

    GJS_INC_COUNTER(gerror);
    priv = g_slice_new0(Error);
    priv->info = info;
    g_base_info_ref( (GIBaseInfo*) priv->info);
    priv->domain = g_quark_from_string (g_enum_info_get_error_domain(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);

    constructor = NULL;
    gjs_object_get_property(context, in_object, constructor_name, &value);
    if (!JSVAL_IS_VOID(value)) {
        if (!JSVAL_IS_OBJECT(value)) {
            gjs_throw(context, "Property '%s' does not look like a constructor",
                      constructor_name);
            return JS_FALSE;
        }
    }

    constructor = JSVAL_TO_OBJECT(value);

    gjs_define_enum_values(context, constructor, priv->info);

    if (constructor_p)
        *constructor_p = constructor;

    if (prototype_p)
        *prototype_p = prototype;

    return JS_TRUE;
}
Beispiel #6
0
JSObject*
gjs_keep_alive_new(JSContext *context)
{
    JSObject *keep_alive;
    JSObject *global;

    g_assert(context != NULL);

    JS_BeginRequest(context);

    /* put constructor in the global namespace */
    global = JS_GetGlobalObject(context);

    g_assert(global != NULL);

    if (!gjs_object_has_property(context, global, gjs_keep_alive_class.name)) {
        JSObject *prototype;

        gjs_debug(GJS_DEBUG_KEEP_ALIVE,
                  "Initializing keep-alive class in context %p global %p",
                  context, global);

        prototype = JS_InitClass(context, global,
                                 /* parent prototype JSObject* for
                                  * prototype; NULL for
                                  * Object.prototype
                                  */
                                 NULL,
                                 &gjs_keep_alive_class,
                                 /* constructor for instances (NULL for
                                  * none - just name the prototype like
                                  * Math - rarely correct)
                                  */
                                 keep_alive_constructor,
                                 /* number of constructor args */
                                 0,
                                 /* props of prototype */
                                 &gjs_keep_alive_proto_props[0],
                                 /* funcs of prototype */
                                 &gjs_keep_alive_proto_funcs[0],
                                 /* props of constructor, MyConstructor.myprop */
                                 NULL,
                                 /* funcs of constructor, MyConstructor.myfunc() */
                                 NULL);
        if (prototype == NULL)
            gjs_fatal("Can't init class %s", gjs_keep_alive_class.name);

        g_assert(gjs_object_has_property(context, global, gjs_keep_alive_class.name));

        gjs_debug(GJS_DEBUG_KEEP_ALIVE, "Initialized class %s prototype %p",
                  gjs_keep_alive_class.name, prototype);
    }

    gjs_debug(GJS_DEBUG_KEEP_ALIVE,
              "Creating new keep-alive object for context %p global %p",
              context, global);

    /* Without the "global" parent object, this craters inside of
     * xulrunner because in jsobj.c:js_ConstructObject it looks up
     * VOID as the constructor.  Exploring in gdb, it is walking up
     * the scope chain in a way that involves scary xpconnect-looking
     * stuff. Having "global" as parent seems to fix it. But, it would
     * not hurt to understand this better.
     */
    keep_alive = JS_ConstructObject(context, &gjs_keep_alive_class, NULL, global);
    if (keep_alive == NULL) {
        gjs_log_exception(context, NULL);
        gjs_fatal("Failed to create keep_alive object");
    }

    JS_EndRequest(context);

    return keep_alive;
}
Beispiel #7
0
static JSObject *
load_module_init(JSContext  *context,
                 JSObject   *in_object,
                 const char *full_path)
{
    char *script;
    gsize script_len;
    jsval script_retval;
    JSObject *module_obj;

    /* First we check if js module has already been loaded  */
    if (gjs_object_has_property(context, in_object, MODULE_INIT_PROPERTY)) {
        jsval module_obj_val;

        if (gjs_object_get_property(context,
                                    in_object,
                                    MODULE_INIT_PROPERTY,
                                    &module_obj_val)) {
            return JSVAL_TO_OBJECT(module_obj_val);
        }
    }

    module_obj = JS_NewObject(context, NULL, NULL, NULL);
    if (module_obj == NULL) {
        return JS_FALSE;
    }

    /* https://bugzilla.mozilla.org/show_bug.cgi?id=599651 means we
     * can't just pass in the global as the parent */
    JS_SetParent(context, module_obj,
                 gjs_get_import_global (context));

    /* Define module in importer for future use and to avoid module_obj
     * object to be garbage collected during the evaluation of the script */
    JS_DefineProperty(context, in_object,
                      MODULE_INIT_PROPERTY, OBJECT_TO_JSVAL(module_obj),
                      NULL, NULL,
                      GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT);

    script = NULL;
    script_len = 0;

    if (!g_file_get_contents(full_path, &script, &script_len, NULL)) {
        return NULL;
    }

    g_assert(script != NULL);

    gjs_debug(GJS_DEBUG_IMPORTER, "Importing %s", full_path);

    if (!JS_EvaluateScript(context,
                           module_obj,
                           script,
                           script_len,
                           full_path,
                           1, /* line number */
                           &script_retval)) {
        g_free(script);

        /* If JSOPTION_DONT_REPORT_UNCAUGHT is set then the exception
         * would be left set after the evaluate and not go to the error
         * reporter function.
         */
        if (JS_IsExceptionPending(context)) {
            gjs_debug(GJS_DEBUG_IMPORTER,
                      "Module " MODULE_INIT_FILENAME " left an exception set");
            gjs_log_and_keep_exception(context, NULL);
        } else {
            gjs_throw(context,
                      "JS_EvaluateScript() returned FALSE but did not set exception");
        }

        return NULL;
    }

    g_free(script);

    return module_obj;
}
Beispiel #8
0
static JSBool
gjs_value_to_g_value_internal(JSContext    *context,
                              jsval         value,
                              GValue       *gvalue,
                              gboolean      no_copy)
{
    GType gtype;

    gtype = G_VALUE_TYPE(gvalue);

    if (gtype == 0) {
        gtype = gjs_value_guess_g_type(context, value);

        if (gtype == G_TYPE_INVALID) {
            gjs_throw(context, "Could not guess unspecified GValue type");
            return JS_FALSE;
        }

        gjs_debug_marshal(GJS_DEBUG_GCLOSURE,
                          "Guessed GValue type %s from JS Value",
                          g_type_name(gtype));

        g_value_init(gvalue, gtype);
    }

    gjs_debug_marshal(GJS_DEBUG_GCLOSURE,
                      "Converting jsval to gtype %s",
                      g_type_name(gtype));


    if (gtype == G_TYPE_STRING) {
        /* Don't use ValueToString since we don't want to just toString()
         * everything automatically
         */
        if (JSVAL_IS_NULL(value)) {
            g_value_set_string(gvalue, NULL);
        } else if (JSVAL_IS_STRING(value)) {
            gchar *utf8_string;

            if (!gjs_string_to_utf8(context, value, &utf8_string))
                return JS_FALSE;

            g_value_take_string(gvalue, utf8_string);
        } else {
            gjs_throw(context,
                      "Wrong type %s; string expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_CHAR) {
        gint32 i;
        if (JS_ValueToInt32(context, value, &i) && i >= SCHAR_MIN && i <= SCHAR_MAX) {
            g_value_set_schar(gvalue, (signed char)i);
        } else {
            gjs_throw(context,
                      "Wrong type %s; char expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_UCHAR) {
        guint16 i;
        if (JS_ValueToUint16(context, value, &i) && i <= UCHAR_MAX) {
            g_value_set_uchar(gvalue, (unsigned char)i);
        } else {
            gjs_throw(context,
                      "Wrong type %s; unsigned char expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_INT) {
        gint32 i;
        if (JS_ValueToInt32(context, value, &i)) {
            g_value_set_int(gvalue, i);
        } else {
            gjs_throw(context,
                      "Wrong type %s; integer expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_DOUBLE) {
        gdouble d;
        if (JS_ValueToNumber(context, value, &d)) {
            g_value_set_double(gvalue, d);
        } else {
            gjs_throw(context,
                      "Wrong type %s; double expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_FLOAT) {
        gdouble d;
        if (JS_ValueToNumber(context, value, &d)) {
            g_value_set_float(gvalue, d);
        } else {
            gjs_throw(context,
                      "Wrong type %s; float expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_UINT) {
        guint32 i;
        if (JS_ValueToECMAUint32(context, value, &i)) {
            g_value_set_uint(gvalue, i);
        } else {
            gjs_throw(context,
                      "Wrong type %s; unsigned integer expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (gtype == G_TYPE_BOOLEAN) {
        JSBool b;

        /* JS_ValueToBoolean() pretty much always succeeds,
         * which is maybe surprising sometimes, but could
         * be handy also...
         */
        if (JS_ValueToBoolean(context, value, &b)) {
            g_value_set_boolean(gvalue, b);
        } else {
            gjs_throw(context,
                      "Wrong type %s; boolean expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
        GObject *gobj;

        gobj = NULL;
        if (JSVAL_IS_NULL(value)) {
            /* nothing to do */
        } else if (JSVAL_IS_OBJECT(value)) {
            JSObject *obj;
            obj = JSVAL_TO_OBJECT(value);

            if (!gjs_typecheck_object(context, obj,
                                      gtype, JS_TRUE))
                return JS_FALSE;

            gobj = gjs_g_object_from_object(context, obj);
        } else {
            gjs_throw(context,
                      "Wrong type %s; object %s expected",
                      gjs_get_type_name(value),
                      g_type_name(gtype));
            return JS_FALSE;
        }

        g_value_set_object(gvalue, gobj);
    } else if (gtype == G_TYPE_STRV) {
        if (JSVAL_IS_NULL(value)) {
            /* do nothing */
        } else if (gjs_object_has_property(context,
                                           JSVAL_TO_OBJECT(value),
                                           "length")) {
            jsval length_value;
            guint32 length;

            if (!gjs_object_require_property(context,
                                             JSVAL_TO_OBJECT(value), NULL,
                                             "length",
                                             &length_value) ||
                !JS_ValueToECMAUint32(context, length_value, &length)) {
                gjs_throw(context,
                          "Wrong type %s; strv expected",
                          gjs_get_type_name(value));
                return JS_FALSE;
            } else {
                void *result;
                char **strv;

                if (!gjs_array_to_strv (context,
                                        value,
                                        length, &result))
                    return JS_FALSE;
                /* cast to strv in a separate step to avoid type-punning */
                strv = result;
                g_value_take_boxed (gvalue, strv);
            }
        } else {
            gjs_throw(context,
                      "Wrong type %s; strv expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else if (g_type_is_a(gtype, G_TYPE_BOXED)) {
        void *gboxed;

        gboxed = NULL;
        if (JSVAL_IS_NULL(value)) {
            /* nothing to do */
        } else if (JSVAL_IS_OBJECT(value)) {
            JSObject *obj;
            obj = JSVAL_TO_OBJECT(value);

            if (g_type_is_a(gtype, G_TYPE_ERROR)) {
                /* special case GError */
                if (!gjs_typecheck_gerror(context, obj, JS_TRUE))
                    return JS_FALSE;

                gboxed = gjs_gerror_from_error(context, obj);
            } else {
                /* First try a union, if that fails,
                   assume a boxed struct. Distinguishing
                   which one is expected would require checking
                   the associated GIBaseInfo, which is not necessary
                   possible, if e.g. we see the GType without
                   loading the typelib.
                */
                if (gjs_typecheck_union(context, obj,
                                        NULL, gtype, JS_FALSE)) {
                    gboxed = gjs_c_union_from_union(context, obj);
                } else {
                    if (!gjs_typecheck_boxed(context, obj,
                                             NULL, gtype, JS_TRUE))
                        return JS_FALSE;

                    gboxed = gjs_c_struct_from_boxed(context, obj);
                }
            }
        } else {
            gjs_throw(context,
                      "Wrong type %s; boxed type %s expected",
                      gjs_get_type_name(value),
                      g_type_name(gtype));
            return JS_FALSE;
        }

        if (no_copy)
            g_value_set_static_boxed(gvalue, gboxed);
        else
            g_value_set_boxed(gvalue, gboxed);
    } else if (g_type_is_a(gtype, G_TYPE_VARIANT)) {
        GVariant *variant = NULL;

        if (JSVAL_IS_NULL(value)) {
            /* nothing to do */
        } else if (JSVAL_IS_OBJECT(value)) {
            JSObject *obj = JSVAL_TO_OBJECT(value);

            if (!gjs_typecheck_boxed(context, obj,
                                     NULL, G_TYPE_VARIANT, JS_TRUE))
                return JS_FALSE;

            variant = gjs_c_struct_from_boxed(context, obj);
        } else {
            gjs_throw(context,
                      "Wrong type %s; boxed type %s expected",
                      gjs_get_type_name(value),
                      g_type_name(gtype));
            return JS_FALSE;
        }

        g_value_set_variant (gvalue, variant);
    } else if (g_type_is_a(gtype, G_TYPE_ENUM)) {
        gint64 value_int64;

        if (gjs_value_to_int64 (context, value, &value_int64)) {
            GEnumValue *v;

            /* See arg.c:_gjs_enum_to_int() */
            v = g_enum_get_value(G_ENUM_CLASS(g_type_class_peek(gtype)),
                                 (int)value_int64);
            if (v == NULL) {
                gjs_throw(context,
                          "%d is not a valid value for enumeration %s",
                          JSVAL_TO_INT(value), g_type_name(gtype));
                return JS_FALSE;
            }

            g_value_set_enum(gvalue, v->value);
        } else {
            gjs_throw(context,
                         "Wrong type %s; enum %s expected",
                         gjs_get_type_name(value),
                         g_type_name(gtype));
            return JS_FALSE;
        }
    } else if (g_type_is_a(gtype, G_TYPE_FLAGS)) {
        gint64 value_int64;

        if (gjs_value_to_int64 (context, value, &value_int64)) {
            if (!_gjs_flags_value_is_valid(context, gtype, value_int64))
                return JS_FALSE;

            /* See arg.c:_gjs_enum_to_int() */
            g_value_set_flags(gvalue, (int)value_int64);
        } else {
            gjs_throw(context,
                      "Wrong type %s; flags %s expected",
                      gjs_get_type_name(value),
                      g_type_name(gtype));
            return JS_FALSE;
        }
    } else if (g_type_is_a(gtype, G_TYPE_PARAM)) {
        void *gparam;

        gparam = NULL;
        if (JSVAL_IS_NULL(value)) {
            /* nothing to do */
        } else if (JSVAL_IS_OBJECT(value)) {
            JSObject *obj;
            obj = JSVAL_TO_OBJECT(value);

            if (!gjs_typecheck_param(context, obj, gtype, JS_TRUE))
                return JS_FALSE;

            gparam = gjs_g_param_from_param(context, obj);
        } else {
            gjs_throw(context,
                      "Wrong type %s; param type %s expected",
                      gjs_get_type_name(value),
                      g_type_name(gtype));
            return JS_FALSE;
        }

        g_value_set_param(gvalue, gparam);
    } else if (g_type_is_a(gtype, G_TYPE_GTYPE)) {
        GType type;

        if (!JSVAL_IS_OBJECT(value)) {
            gjs_throw(context, "Wrong type %s; expect a GType object",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }

        type = gjs_gtype_get_actual_gtype(context, JSVAL_TO_OBJECT(value));
        g_value_set_gtype(gvalue, type);
    } else if (g_type_is_a(gtype, G_TYPE_POINTER)) {
        if (JSVAL_IS_NULL(value)) {
            /* Nothing to do */
        } else {
            gjs_throw(context,
                      "Cannot convert non-null JS value to G_POINTER");
            return JS_FALSE;
        }
    } else if (JSVAL_IS_NUMBER(value) &&
               g_value_type_transformable(G_TYPE_INT, gtype)) {
        /* Only do this crazy gvalue transform stuff after we've
         * exhausted everything else. Adding this for
         * e.g. ClutterUnit.
         */
        gint32 i;
        if (JS_ValueToInt32(context, value, &i)) {
            GValue int_value = { 0, };
            g_value_init(&int_value, G_TYPE_INT);
            g_value_set_int(&int_value, i);
            g_value_transform(&int_value, gvalue);
        } else {
            gjs_throw(context,
                      "Wrong type %s; integer expected",
                      gjs_get_type_name(value));
            return JS_FALSE;
        }
    } else {
        gjs_debug(GJS_DEBUG_GCLOSURE, "jsval is number %d gtype fundamental %d transformable to int %d from int %d",
                  JSVAL_IS_NUMBER(value),
                  G_TYPE_IS_FUNDAMENTAL(gtype),
                  g_value_type_transformable(gtype, G_TYPE_INT),
                  g_value_type_transformable(G_TYPE_INT, gtype));

        gjs_throw(context,
                  "Don't know how to convert JavaScript object to GType %s",
                  g_type_name(gtype));
        return JS_FALSE;
    }

    return JS_TRUE;
}