Beispiel #1
0
JSObject*
gjs_construct_object_dynamic(JSContext      *context,
                             JSObject       *proto,
                             uintN           argc,
                             jsval          *argv)
{
    RuntimeData *rd;
    JSClass *proto_class;
    JSContext *load_context;
    JSObject *result;

    JS_BeginRequest(context);

    /* We replace the passed-in context and global object with our
     * runtime-global permanent load context. Otherwise, JS_ConstructObject
     * can't find the constructor in whatever random global object is set
     * on the passed-in context.
     */
    load_context = gjs_runtime_get_load_context(JS_GetRuntime(context));
    JS_BeginRequest(load_context);

    proto_class = JS_GET_CLASS(load_context, proto);

    rd = get_data_from_context(load_context);

    /* Check that it's safe to cast to DynamicJSClass */
    if (g_hash_table_lookup(rd->dynamic_classes, proto_class) == NULL) {
        gjs_throw(load_context, "Prototype is not for a dynamically-registered class");
        goto error;
    }

    gjs_debug_lifecycle(GJS_DEBUG_GREPO,
                        "Constructing instance of dynamic class %s %p from proto %p",
                        proto_class->name, proto_class, proto);

    if (argc > 0)
        result = JS_ConstructObjectWithArguments(load_context, proto_class, proto, NULL, argc, argv);
    else
        result = JS_ConstructObject(load_context, proto_class, proto, NULL);

    if (!result)
        goto error;

    JS_EndRequest(load_context);
    JS_EndRequest(context);
    return result;

 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 object construction failed somehow");
    }

    JS_EndRequest(load_context);
    JS_EndRequest(context);
    return NULL;
}
Beispiel #2
0
void*
gjs_get_instance_private_dynamic(JSContext      *context,
                                 JSObject       *obj,
                                 JSClass        *static_clasp,
                                 jsval          *argv)
{
    RuntimeData *rd;
    JSClass *obj_class;
    void *instance;

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

    JS_BeginRequest(context);

    obj_class = JS_GET_CLASS(context, obj);
    g_assert(obj_class != NULL);

    rd = get_data_from_context(context);
    g_assert(rd != NULL);

    /* Check that it's safe to cast to DynamicJSClass */
    if (g_hash_table_lookup(rd->dynamic_classes, obj_class) == NULL) {
        gjs_throw(context,
                  "Object %p proto %p doesn't have a dynamically-registered class, it has %s",
                  obj, JS_GetPrototype(context, obj), obj_class->name);
        JS_EndRequest(context);
        return NULL;
    }

    if (static_clasp != ((DynamicJSClass*) obj_class)->static_class) {
        gjs_throw(context, "Object is not a dynamically-registered class based on expected static class pointer");
        JS_EndRequest(context);
        return NULL;
    }

    instance = JS_GetInstancePrivate(context, obj, obj_class, argv);
    JS_EndRequest(context);

    return instance;
}
Beispiel #3
0
void*
gjs_get_instance_private_dynamic_with_typecheck(JSContext      *context,
                                                JSObject       *obj,
                                                JSClass        *static_clasp,
                                                jsval          *argv)
{
    RuntimeData *rd;
    JSClass *obj_class;
    void *instance;

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

    JS_BeginRequest(context);

    obj_class = JS_GET_CLASS(context, obj);
    g_assert(obj_class != NULL);

    rd = get_data_from_context(context);
    g_assert(rd != NULL);

    /* Check that it's safe to cast to DynamicJSClass */
    if (g_hash_table_lookup(rd->dynamic_classes, obj_class) == NULL) {
        JS_EndRequest(context);
        return NULL;
    }

    if (static_clasp != ((DynamicJSClass*) obj_class)->static_class) {
        JS_EndRequest(context);
        return NULL;
    }

    instance = JS_GetInstancePrivate(context, obj, obj_class, argv);
    JS_EndRequest(context);
    return instance;
}
Beispiel #4
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 *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;
}
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;
}