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; }
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; }
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; }
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; }