示例#1
0
static JSObject*
gjs_lookup_param_prototype(JSContext    *context)
{
    JS::RootedId gobject_name(context, gjs_intern_string_to_id(context, "GObject"));
    JS::RootedObject in_object(context,
        gjs_lookup_namespace_object_by_name(context, gobject_name));

    if (G_UNLIKELY (!in_object))
        return NULL;

    JS::RootedValue value(context);
    if (!JS_GetProperty(context, in_object, "ParamSpec", &value))
        return NULL;

    if (G_UNLIKELY (!value.isObject()))
        return NULL;

    JS::RootedObject constructor(context, &value.toObject());
    g_assert(constructor);

    if (!gjs_object_get_property(context, constructor,
                                 GJS_STRING_PROTOTYPE, &value))
        return NULL;

    if (G_UNLIKELY (!value.isObjectOrNull()))
        return NULL;

    return value.toObjectOrNull();
}
示例#2
0
文件: jsapi-util.c 项目: sjokkis/gjs
/* Checks whether an object has a property; unlike JS_GetProperty(),
 * never sets an exception. Treats a property with a value of JSVAL_VOID
 * the same as an absent property and returns false in both cases.
 */
gboolean
gjs_object_has_property(JSContext  *context,
                        JSObject   *obj,
                        const char *property_name)
{
    return gjs_object_get_property(context, obj, property_name, NULL);
}
示例#3
0
文件: jsapi-util.c 项目: sjokkis/gjs
void
gjs_log_object_props(JSContext      *context,
                     JSObject       *obj,
                     GjsDebugTopic   topic,
                     const char     *prefix)
{
    JSObject *props_iter;
    jsid prop_id;

    JS_BeginRequest(context);

    /* We potentially create new strings, plus the property iterator,
     * that could get collected as we go through this process. So
     * create a local root scope.
     */
    JS_EnterLocalRootScope(context);

    props_iter = JS_NewPropertyIterator(context, obj);
    if (props_iter == NULL) {
        gjs_debug(GJS_DEBUG_ERROR,
                  "Failed to create property iterator for object props");
        goto done;
    }

    prop_id = JSVAL_VOID;
    if (!JS_NextProperty(context, props_iter, &prop_id))
        goto done;

    while (prop_id != JSVAL_VOID) {
        jsval nameval;
        const char *name;
        jsval propval;

        if (!JS_IdToValue(context, prop_id, &nameval))
            goto next;

        if (!gjs_get_string_id(nameval, &name))
            goto next;

        if (!gjs_object_get_property(context, obj, name, &propval))
            goto next;

        gjs_debug(topic,
                  "%s%s = '%s'",
                  prefix, name,
                  gjs_value_debug_string(context, propval));

    next:
        prop_id = JSVAL_VOID;
        if (!JS_NextProperty(context, props_iter, &prop_id))
            break;
    }

 done:
    JS_LeaveLocalRootScope(context);
    JS_EndRequest(context);
}
示例#4
0
文件: jsapi-util.c 项目: sjokkis/gjs
static void
try_to_chain_stack_trace(JSContext *src_context, JSContext *dst_context,
                         jsval src_exc) {
    /* append current stack of dst_context to stack trace for src_exc.
     * we bail if anything goes wrong, just using the src_exc unmodified
     * in that case. */
    jsval chained, src_stack, dst_stack, new_stack;
    JSString *new_stack_str;

    JS_BeginRequest(src_context);
    JS_BeginRequest(dst_context);

    if (!JSVAL_IS_OBJECT(src_exc))
        goto out; // src_exc doesn't have a stack trace

    /* create a new exception in dst_context to get a stack trace */
    gjs_throw_literal(dst_context, "Chained exception");
    if (!(JS_GetPendingException(dst_context, &chained) &&
          JSVAL_IS_OBJECT(chained)))
        goto out; // gjs_throw_literal didn't work?!
    JS_ClearPendingException(dst_context);

    /* get stack trace for src_exc and chained */
    if (!(gjs_object_get_property(dst_context, JSVAL_TO_OBJECT(chained),
                                  "stack", &dst_stack) &&
          JSVAL_IS_STRING(dst_stack)))
        goto out; // couldn't get chained stack
    if (!(gjs_object_get_property(src_context, JSVAL_TO_OBJECT(src_exc),
                                  "stack", &src_stack) &&
          JSVAL_IS_STRING(src_stack)))
        goto out; // couldn't get source stack

    /* add chained exception's stack trace to src_exc */
    new_stack_str = JS_ConcatStrings
        (dst_context, JSVAL_TO_STRING(src_stack), JSVAL_TO_STRING(dst_stack));
    if (new_stack_str==NULL)
        goto out; // couldn't concatenate src and dst stacks?!
    new_stack = STRING_TO_JSVAL(new_stack_str);
    JS_SetProperty(dst_context, JSVAL_TO_OBJECT(src_exc), "stack", &new_stack);

 out:
    JS_EndRequest(dst_context);
    JS_EndRequest(src_context);
}
static void _gjs_builder_connect_func (GtkBuilder *builder,
                                       GObject *object,
                                       const gchar *signal_name,
                                       const gchar *handler_name,
                                       GObject *connect_object,
                                       GConnectFlags flags,
                                       gpointer user_data)
{
    builder_ud *priv = (builder_ud *)user_data;
    JSContext *ctx = priv->ctx;
    JSObject *obj = priv->obj;
    GClosure *closure;
    JSObject *callable;
    builder_cd *cd;
    closure_data *c;
    jsval func;

    if (!gjs_object_get_property (ctx, obj, handler_name, &func))
        return;

    if (!JSVAL_IS_OBJECT(func))
        return;

    callable = JSVAL_TO_OBJECT (func);
    if (!JS_ObjectIsFunction(ctx, callable))
        return;

    /* Protect from garbage collection. */
    cd = g_object_get_data (G_OBJECT (builder), GJS_BUILDER_CLOSURE_KEY);
    if (!cd) {
        cd = g_new0 (builder_cd, 1);
        cd->context = ctx;
        cd->closures = NULL;
        g_object_set_data_full (G_OBJECT (builder),
                                GJS_BUILDER_CLOSURE_KEY,
                                cd,
                                (GDestroyNotify) _builder_cd_free);
    }

    g_assert (cd->context == ctx);

    c = g_new0 (closure_data, 1);
    c->jsobj = callable;
    cd->closures = g_slist_prepend (cd->closures, c);
    JS_AddObjectRoot (ctx, &c->jsobj);

    closure = gjs_closure_new_for_signal (ctx,
                                          callable,
                                          "signal handler (GtkBuilder)",
                                          0);
    if (connect_object != NULL)
        g_object_watch_closure (connect_object, closure);

    c->object = g_object_ref (object);
    c->handler_id = g_signal_connect_closure (object, signal_name, closure, FALSE);
}
示例#6
0
文件: native.c 项目: Cobinja/cjs
static char *
get_module_name(JSContext *context,
                JSObject  *module_obj,
                jsval     *tmp)
{
    if (gjs_object_get_property(context, module_obj, "__moduleName__", tmp) &&
        JSVAL_IS_STRING(*tmp))
        return gjs_string_get_ascii(context, *tmp);
    else
        return NULL;
}
示例#7
0
static JSObject*
gjs_keep_alive_get_from_parent(JSContext *context,
                               JSObject  *parent)
{
    jsval value;

    gjs_object_get_property(context, parent, GLOBAL_KEEP_ALIVE_NAME, &value);

    if (JSVAL_IS_OBJECT(value))
        return JSVAL_TO_OBJECT(value);
    else
        return NULL;
}
示例#8
0
文件: native.c 项目: Cobinja/cjs
static JSObject*
module_get_parent(JSContext *context,
                  JSObject  *module_obj)
{
    jsval value;

    if (gjs_object_get_property(context, module_obj, "__parentModule__", &value) &&
        !JSVAL_IS_NULL(value) &&
        JSVAL_IS_OBJECT(value)) {
        return JSVAL_TO_OBJECT(value);
    } else {
        return NULL;
    }
}
示例#9
0
static char *
get_module_name(JSContext *context,
                JSObject  *module_obj,
                jsval     *tmp)
{
    char *name;

    if (gjs_object_get_property(context, module_obj, "__moduleName__", tmp) &&
            JSVAL_IS_STRING(*tmp))
        if (gjs_string_to_utf8(context, *tmp, &name))
            return name;
        else
            return NULL;
    else
        return NULL;
}
示例#10
0
文件: keep-alive.c 项目: sjokkis/gjs
JSObject*
gjs_keep_alive_get_global(JSContext *context)
{
    jsval value;
    JSObject *global;
    JSObject *result;

    JS_BeginRequest(context);

    global = JS_GetGlobalObject(context);

    gjs_object_get_property(context, global, GLOBAL_KEEP_ALIVE_NAME, &value);

    if (JSVAL_IS_OBJECT(value))
        result = JSVAL_TO_OBJECT(value);
    else
        result = NULL;

    JS_EndRequest(context);

    return result;
}
示例#11
0
JSBool
gjs_define_interface_class(JSContext       *context,
                           JSObject        *in_object,
                           GIInterfaceInfo *info,
                           JSObject       **prototype_p)
{
    Interface *priv;
    const char *constructor_name;
    JSObject *constructor;
    JSObject *prototype;
    jsval value;

    constructor_name = g_base_info_get_name((GIBaseInfo*)info);

    gjs_object_get_property(context, in_object, constructor_name, &value);
    if (!JSVAL_IS_VOID(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, "prototype property does not appear to exist or has wrong type");
            return JS_FALSE;
        } else {
            if (prototype_p)
                *prototype_p = JSVAL_TO_OBJECT(value);

            return JS_TRUE;
        }

        return JS_TRUE;
    }

    if (!gjs_init_class_dynamic(context, in_object,
                                NULL,
                                g_base_info_get_namespace((GIBaseInfo*)info),
                                constructor_name,
                                &gjs_interface_class,
                                gjs_interface_constructor, 0,
                                /* props of prototype */
                                &gjs_interface_proto_props[0],
                                /* funcs of prototype */
                                &gjs_interface_proto_funcs[0],
                                /* props of constructor, MyConstructor.myprop */
                                NULL,
                                /* funcs of constructor, MyConstructor.myfunc() */
                                NULL,
                                &prototype,
                                &constructor)) {
        gjs_fatal("Can't init class %s", constructor_name);
    }

    GJS_INC_COUNTER(interface);
    priv = g_slice_new0(Interface);
    priv->info = info;
    priv->gtype = g_registered_type_info_get_g_type(priv->info);
    g_base_info_ref((GIBaseInfo*)priv->info);
    JS_SetPrivate(context, prototype, priv);

    gjs_define_static_methods(context, constructor, priv->gtype, priv->info);

    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
    JS_DefineProperty(context, constructor, "$gtype", value,
                      NULL, NULL, JSPROP_PERMANENT);

    if (prototype_p)
        *prototype_p = prototype;

    return JS_TRUE;
}
示例#12
0
文件: importer.c 项目: KNOPOChKA2/gjs
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;
}
示例#13
0
文件: gerror.c 项目: Cobinja/cjs
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;
}
示例#14
0
文件: importer.c 项目: KNOPOChKA2/gjs
static JSBool
do_import(JSContext  *context,
          JSObject   *obj,
          Importer   *priv,
          const char *name)
{
    char *filename;
    char *native_filename;
    char *full_path;
    char *dirname = NULL;
    jsval search_path_val;
    JSObject *search_path;
    JSObject *module_obj = NULL;
    jsuint search_path_len;
    jsuint i;
    JSBool result;
    GPtrArray *directories;

    if (strcmp(name, MODULE_INIT_PROPERTY) == 0) {
        return JS_FALSE;
    }

    if (!gjs_object_require_property(context, obj, "importer", "searchPath", &search_path_val)) {
        return JS_FALSE;
    }

    if (!JSVAL_IS_OBJECT(search_path_val)) {
        gjs_throw(context, "searchPath property on importer is not an object");
        return JS_FALSE;
    }

    search_path = JSVAL_TO_OBJECT(search_path_val);

    if (!JS_IsArrayObject(context, search_path)) {
        gjs_throw(context, "searchPath property on importer is not an array");
        return JS_FALSE;
    }

    if (!JS_GetArrayLength(context, search_path, &search_path_len)) {
        gjs_throw(context, "searchPath array has no length");
        return JS_FALSE;
    }

    result = JS_FALSE;

    filename = g_strdup_printf("%s.js", name);
    native_filename = g_strdup_printf("%s."G_MODULE_SUFFIX, name);
    full_path = NULL;
    directories = NULL;

    /* First try importing an internal module like byteArray */
    if (gjs_is_registered_native_module(context, obj, name) &&
            import_native_file(context, obj, name, NULL)) {
        gjs_debug(GJS_DEBUG_IMPORTER,
                  "successfully imported module '%s'", name);
        result = JS_TRUE;
        goto out;
    }

    for (i = 0; i < search_path_len; ++i) {
        jsval elem;

        elem = JSVAL_VOID;
        if (!JS_GetElement(context, search_path, i, &elem)) {
            /* this means there was an exception, while elem == JSVAL_VOID
             * means no element found
             */
            goto out;
        }

        if (JSVAL_IS_VOID(elem))
            continue;

        if (!JSVAL_IS_STRING(elem)) {
            gjs_throw(context, "importer searchPath contains non-string");
            goto out;
        }

        g_free(dirname);
        dirname = NULL;

        if (!gjs_string_to_utf8(context, elem, &dirname))
            goto out; /* Error message already set */

        /* Ignore empty path elements */
        if (dirname[0] == '\0')
            continue;

        /* Try importing __init__.js and loading the symbol from it */
        if (full_path)
            g_free(full_path);
        full_path = g_build_filename(dirname, MODULE_INIT_FILENAME,
                                     NULL);

        module_obj = load_module_init(context, obj, full_path);
        if (module_obj != NULL) {
            jsval obj_val;

            if (gjs_object_get_property(context,
                                        module_obj,
                                        name,
                                        &obj_val)) {
                if (!JSVAL_IS_VOID(obj_val) &&
                        JS_DefineProperty(context, obj,
                                          name, obj_val,
                                          NULL, NULL,
                                          GJS_MODULE_PROP_FLAGS & ~JSPROP_PERMANENT)) {
                    result = JS_TRUE;
                    goto out;
                }
            }
        }

        /* Second try importing a directory (a sub-importer) */
        if (full_path)
            g_free(full_path);
        full_path = g_build_filename(dirname, name,
                                     NULL);

        if (g_file_test(full_path, G_FILE_TEST_IS_DIR)) {
            gjs_debug(GJS_DEBUG_IMPORTER,
                      "Adding directory '%s' to child importer '%s'",
                      full_path, name);
            if (directories == NULL) {
                directories = g_ptr_array_new();
            }
            g_ptr_array_add(directories, full_path);
            /* don't free it twice - pass ownership to ptr array */
            full_path = NULL;
        }

        /* If we just added to directories, we know we don't need to
         * check for a file.  If we added to directories on an earlier
         * iteration, we want to ignore any files later in the
         * path. So, always skip the rest of the loop block if we have
         * directories.
         */
        if (directories != NULL) {
            continue;
        }

        /* Third, if it's not a directory, try importing a file */
        g_free(full_path);
        full_path = g_build_filename(dirname, filename,
                                     NULL);

        if (g_file_test(full_path, G_FILE_TEST_EXISTS)) {
            if (import_file(context, obj, name, full_path)) {
                gjs_debug(GJS_DEBUG_IMPORTER,
                          "successfully imported module '%s'", name);
                result = JS_TRUE;
            }

            /* Don't keep searching path if we fail to load the file for
             * reasons other than it doesn't exist... i.e. broken files
             * block searching for nonbroken ones
             */
            goto out;
        }

        /* Finally see if it's a native module */
        g_free(full_path);
        full_path = g_build_filename(dirname, native_filename,
                                     NULL);

        if (g_file_test(full_path, G_FILE_TEST_EXISTS)) {
            if (import_native_file(context, obj, name, full_path)) {
                gjs_debug(GJS_DEBUG_IMPORTER,
                          "successfully imported module '%s'", name);
                result = JS_TRUE;
            }

            /* Don't keep searching path if we fail to load the file for
             * reasons other than it doesn't exist... i.e. broken files
             * block searching for nonbroken ones
             */
            goto out;
        }

        gjs_debug(GJS_DEBUG_IMPORTER,
                  "JS import '%s' not found in %s",
                  name, dirname);
    }

    if (directories != NULL) {
        /* NULL-terminate the char** */
        g_ptr_array_add(directories, NULL);

        if (import_directory(context, obj, name,
                             (const char**) directories->pdata)) {
            gjs_debug(GJS_DEBUG_IMPORTER,
                      "successfully imported directory '%s'", name);
            result = JS_TRUE;
        }
    }

out:
    if (directories != NULL) {
        char **str_array;

        /* NULL-terminate the char**
         * (maybe for a second time, but doesn't matter)
         */
        g_ptr_array_add(directories, NULL);

        str_array = (char**) directories->pdata;
        g_ptr_array_free(directories, FALSE);
        g_strfreev(str_array);
    }

    g_free(full_path);
    g_free(filename);
    g_free(native_filename);
    g_free(dirname);

    if (!result &&
            !JS_IsExceptionPending(context)) {
        /* If no exception occurred, the problem is just that we got to the
         * end of the path. Be sure an exception is set.
         */
        gjs_throw(context, "No JS module '%s' found in search path", name);
    }

    return result;
}
示例#15
0
JSObject*
gjs_init_class_dynamic(JSContext      *context,
                       JSObject       *in_object,
                       JSObject       *parent_proto,
                       const char     *ns_name,
                       const char     *class_name,
                       JSClass        *clasp,
                       JSNative        constructor,
                       uintN           nargs,
                       JSPropertySpec *ps,
                       JSFunctionSpec *fs,
                       JSPropertySpec *static_ps,
                       JSFunctionSpec *static_fs)
{
    jsval value;
    char *private_name;
    JSObject *global;
    JSObject *prototype;

    if (clasp->name != NULL) {
        g_warning("Dynamic class should not have a name in the JSClass struct");
        return NULL;
    }

    JS_BeginRequest(context);

    /* We use a special "fake" global object to store our constructors
     * in for future use. Using the actual global object of the context would
     * result in different contexts having different class definitions for
     * the same GObject class; since the proxies are shared between all
     * contexts, this would produce confusing results.
     */
    global = gjs_get_import_global(context);

    /* JS_InitClass() wants to define the constructor in the global object, so
     * we give it a private and namespaced name... passing in the namespace
     * object instead of global object seems to break JS_ConstructObject()
     * which then can't find the constructor for the class. I am probably
     * missing something.
     */
    private_name = g_strdup_printf("_private_%s_%s", ns_name, class_name);

    prototype = NULL;
    if (gjs_object_get_property(context, global,
                                private_name, &value) &&
        JSVAL_IS_OBJECT(value)) {
        jsval proto_val;

        g_free(private_name); /* don't need it anymore */

        if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(value), NULL,
                                         "prototype", &proto_val) ||
            !JSVAL_IS_OBJECT(proto_val)) {
            gjs_throw(context, "prototype was not defined or not an object?");
            goto error;
        }
        prototype = JSVAL_TO_OBJECT(proto_val);
    } else {
        DynamicJSClass *class_copy;
        RuntimeData *rd;

        rd = get_data_from_context(context);

        class_copy = g_slice_new0(DynamicJSClass);
        class_copy->base = *clasp;

        class_copy->base.name = private_name; /* Pass ownership of memory */
        class_copy->static_class = clasp;

        /* record the allocated class to be destroyed with the runtime and so
         * we can do an IS_DYNAMIC_CLASS check
         */
        g_hash_table_replace(rd->dynamic_classes,
                             class_copy, class_copy);

        gjs_debug(GJS_DEBUG_GREPO,
                  "Initializing dynamic class %s %p",
                  class_name, class_copy);

        prototype = JS_InitClass(context, global,
                                 parent_proto, &class_copy->base,
                                 constructor, nargs,
                                 ps, fs,
                                 static_ps, static_fs);
        if (prototype == NULL)
            goto error;

        /* Retrieve the property again so we can define it in
         * in_object
         */
        if (!gjs_object_require_property(context, global, NULL,
                                         class_copy->base.name, &value))
            goto error;
    }
    g_assert(!JSVAL_IS_VOID(value));
    g_assert(prototype != NULL);

    /* Now manually define our constructor with a sane name, in the
     * namespace object.
     */
    if (!JS_DefineProperty(context, in_object,
                           class_name,
                           value,
                           NULL, NULL,
                           GJS_MODULE_PROP_FLAGS))
        goto error;

    JS_EndRequest(context);
    return prototype;

 error:
    JS_EndRequest(context);
    return NULL;
}
示例#16
0
文件: jsapi-util.c 项目: sjokkis/gjs
JSObject*
gjs_init_class_dynamic(JSContext      *context,
                       JSObject       *in_object,
                       JSObject       *parent_proto,
                       const char     *ns_name,
                       const char     *class_name,
                       JSClass        *clasp,
                       JSNative        constructor,
                       uintN           nargs,
                       JSPropertySpec *ps,
                       JSFunctionSpec *fs,
                       JSPropertySpec *static_ps,
                       JSFunctionSpec *static_fs)
{
    jsval value;
    char *private_name;
    JSObject *prototype;
    JSContext *load_context;

    if (clasp->name != NULL) {
        g_warning("Dynamic class should not have a name in the JSClass struct");
        return NULL;
    }

    JS_BeginRequest(context);

    /* We replace the passed-in context and global object with our
     * runtime-global permanent load context. Otherwise, in a
     * process with multiple contexts, we'd arbitrarily define
     * the class in whatever global object initialized the
     * class first, which is not desirable.
     */
    load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
    JS_BeginRequest(load_context);

    /* JS_InitClass() wants to define the constructor in the global object, so
     * we give it a private and namespaced name... passing in the namespace
     * object instead of global object seems to break JS_ConstructObject()
     * which then can't find the constructor for the class. I am probably
     * missing something.
     */
    private_name = g_strdup_printf("_private_%s_%s", ns_name, class_name);

    prototype = NULL;
    if (gjs_object_get_property(load_context, JS_GetGlobalObject(load_context),
                                private_name, &value) &&
        JSVAL_IS_OBJECT(value)) {
        jsval proto_val;

        g_free(private_name); /* don't need it anymore */

        if (!gjs_object_require_property(load_context, JSVAL_TO_OBJECT(value), NULL,
                                         "prototype", &proto_val) ||
            !JSVAL_IS_OBJECT(proto_val)) {
            gjs_throw(load_context, "prototype was not defined or not an object?");
            goto error;
        }
        prototype = JSVAL_TO_OBJECT(proto_val);
    } else {
        DynamicJSClass *class_copy;
        RuntimeData *rd;

        rd = get_data_from_context(load_context);

        class_copy = g_slice_new0(DynamicJSClass);
        class_copy->base = *clasp;

        class_copy->base.name = private_name; /* Pass ownership of memory */
        class_copy->static_class = clasp;

        /* record the allocated class to be destroyed with the runtime and so
         * we can do an IS_DYNAMIC_CLASS check
         */
        g_hash_table_replace(rd->dynamic_classes,
                             class_copy, class_copy);

        gjs_debug(GJS_DEBUG_GREPO,
                  "Initializing dynamic class %s %p",
                  class_name, class_copy);

        prototype = JS_InitClass(load_context, JS_GetGlobalObject(load_context),
                                 parent_proto, &class_copy->base,
                                 constructor, nargs,
                                 ps, fs,
                                 static_ps, static_fs);

        /* Retrieve the property again so we can define it in
         * in_object
         */
        if (!gjs_object_require_property(load_context, JS_GetGlobalObject(load_context), NULL,
                                         class_copy->base.name, &value))
            goto error;
    }
    g_assert(value != JSVAL_VOID);
    g_assert(prototype != NULL);

    /* Now manually define our constructor with a sane name, in the
     * namespace object.
     */
    if (!JS_DefineProperty(load_context, in_object,
                           class_name,
                           value,
                           NULL, NULL,
                           GJS_MODULE_PROP_FLAGS))
        goto error;

    JS_EndRequest(load_context);
    JS_EndRequest(context);
    return prototype;

 error:
    /* Move the exception to the calling context from load context.
     */
    if (!gjs_move_exception(load_context, context)) {
        /* set an exception since none was set */
        gjs_throw(context, "No exception was set, but class initialize failed somehow");
    }

    JS_EndRequest(load_context);
    JS_EndRequest(context);
    return NULL;
}
示例#17
0
文件: param.c 项目: goizueta/gjs
JSBool
gjs_define_param_class(JSContext    *context,
                       JSObject     *in_object,
                       JSObject    **prototype_p)
{
    const char *constructor_name;
    JSObject *prototype;
    jsval value;
    JSObject *constructor;

    constructor_name = "ParamSpec";

    gjs_object_get_property(context, in_object, constructor_name, &value);
    if (!JSVAL_IS_VOID(value)) {
        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, "prototype property does not appear to exist or has wrong type");
            return JS_FALSE;
        } else {
            if (prototype_p)
                *prototype_p = JSVAL_TO_OBJECT(value);

            return JS_TRUE;
        }

        return JS_TRUE;
    }

    /* we could really just use JS_InitClass for this since we have one class instead of
     * N classes on-demand. But, this deals with namespacing and such for us.
     */
    prototype = gjs_init_class_dynamic(context, in_object,
                                          /* parent prototype JSObject* for
                                           * prototype; NULL for
                                           * Object.prototype
                                           */
                                          NULL,
                                          "GObject",
                                          constructor_name,
                                          &gjs_param_class,
                                          /* constructor for instances (NULL for
                                           * none - just name the prototype like
                                           * Math - rarely correct)
                                           */
                                          gjs_param_constructor,
                                          /* number of constructor args */
                                          0,
                                          /* props of prototype */
                                          &gjs_param_proto_props[0],
                                          /* funcs of prototype */
                                          &gjs_param_proto_funcs[0],
                                          /* props of constructor, MyConstructor.myprop */
                                          NULL,
                                          /* funcs of constructor, MyConstructor.myfunc() */
                                          gjs_param_constructor_funcs);
    if (prototype == NULL)
        gjs_fatal("Can't init class %s", constructor_name);

    constructor = NULL;
    gjs_object_get_property(context, in_object, constructor_name, &value);
    if (value != JSVAL_VOID) {
        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);

    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, G_TYPE_PARAM));
    JS_DefineProperty(context, constructor, "$gtype", value,
                      NULL, NULL, JSPROP_PERMANENT);
    
    if (prototype_p)
        *prototype_p = prototype;

    gjs_debug(GJS_DEBUG_GPARAM, "Defined class %s prototype is %p class %p in object %p",
              constructor_name, prototype, JS_GET_CLASS(context, prototype), in_object);

    return JS_TRUE;
}
示例#18
0
/*
 * See:
 * https://bugzilla.mozilla.org/show_bug.cgi?id=166436
 * https://bugzilla.mozilla.org/show_bug.cgi?id=215173
 *
 * Very surprisingly, jsapi.h lacks any way to "throw new Error()"
 *
 * So here is an awful hack inspired by
 * http://egachine.berlios.de/embedding-sm-best-practice/embedding-sm-best-practice.html#error-handling
 */
static void
gjs_throw_valist(JSContext       *context,
                 const char      *error_class,
                 const char      *format,
                 va_list          args)
{
    char *s;
    JSBool result;
    jsval v_constructor, v_message;
    JSObject *err_obj;

    s = g_strdup_vprintf(format, args);

    JS_BeginRequest(context);

    if (JS_IsExceptionPending(context)) {
        /* Often it's unclear whether a given jsapi.h function
         * will throw an exception, so we will throw ourselves
         * "just in case"; in those cases, we don't want to
         * overwrite an exception that already exists.
         * (Do log in case our second exception adds more info,
         * but don't log as topic ERROR because if the exception is
         * caught we don't want an ERROR in the logs.)
         */
        gjs_debug(GJS_DEBUG_CONTEXT,
                  "Ignoring second exception: '%s'",
                  s);
        g_free(s);
        JS_EndRequest(context);
        return;
    }

    result = JS_FALSE;

    (void)JS_EnterLocalRootScope(context);

    if (!gjs_string_from_utf8(context, s, -1, &v_message)) {
        JS_ReportError(context, "Failed to copy exception string");
        goto out;
    }

    if (!gjs_object_get_property(context, JS_GetGlobalObject(context),
                                 error_class, &v_constructor)) {
        JS_ReportError(context, "??? Missing Error constructor in global object?");
        goto out;
    }

    /* throw new Error(message) */
    err_obj = JS_New(context, JSVAL_TO_OBJECT(v_constructor), 1, &v_message);
    JS_SetPendingException(context, OBJECT_TO_JSVAL(err_obj));

    result = JS_TRUE;

 out:

    JS_LeaveLocalRootScope(context);

    if (!result) {
        /* try just reporting it to error handler? should not
         * happen though pretty much
         */
        JS_ReportError(context,
                       "Failed to throw exception '%s'",
                       s);
    }
    g_free(s);

    JS_EndRequest(context);
}
示例#19
0
文件: boxed.c 项目: Katyunechka/gjs
JSBool
gjs_define_boxed_class(JSContext    *context,
                          JSObject     *in_object,
                          GIBoxedInfo  *info,
                          JSObject    **constructor_p,
                          JSObject    **prototype_p)
{
    const char *constructor_name;
    JSObject *prototype;
    JSObject *constructor;
    jsval value;
    Boxed *priv;

    /* See the comment in gjs_define_object_class() for an
     * explanation of how this all works; Boxed is pretty much the
     * same as Object.
     */

    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, "boxed %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;
        }
    }

    if (!gjs_init_class_dynamic(context, in_object,
                                NULL, /* parent prototype */
                                g_base_info_get_namespace( (GIBaseInfo*) info),
                                constructor_name,
                                &gjs_boxed_class,
                                gjs_boxed_constructor, 1,
                                /* props of prototype */
                                &gjs_boxed_proto_props[0],
                                /* funcs of prototype */
                                &gjs_boxed_proto_funcs[0],
                                /* props of constructor, MyConstructor.myprop */
                                NULL,
                                /* funcs of constructor, MyConstructor.myfunc() */
                                NULL,
                                &prototype,
                                &constructor)) {
        gjs_log_exception(context, NULL);
        gjs_fatal("Can't init class %s", constructor_name);
    }

    GJS_INC_COUNTER(boxed);
    priv = g_slice_new0(Boxed);
    priv->info = info;
    boxed_fill_prototype_info(priv);

    g_base_info_ref( (GIBaseInfo*) priv->info);
    priv->gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) 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);

    priv->can_allocate_directly = struct_is_simple (priv->info);

    define_boxed_class_fields (context, priv, prototype);
    gjs_define_static_methods (context, constructor, priv->gtype, priv->info);

    value = OBJECT_TO_JSVAL(gjs_gtype_create_gtype_wrapper(context, priv->gtype));
    JS_DefineProperty(context, constructor, "$gtype", value,
                      NULL, NULL, JSPROP_PERMANENT);

    if (constructor_p)
        *constructor_p = constructor;

    if (prototype_p)
        *prototype_p = prototype;

    return JS_TRUE;
}