[gjs] object: split class definition from prototype lookup
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] object: split class definition from prototype lookup
- Date: Mon, 13 May 2013 19:51:30 +0000 (UTC)
commit fe339117a6f337618fcd2ef3ae01df40c9474a76
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Thu Apr 25 01:26:11 2013 +0200
object: split class definition from prototype lookup
prototype lookup is a very hot path (it's involved in creating
JS objects from GObjects), while class definition is mostly
called when we know the property is not there, so we can avoid
the lookup.
Also, this is a general code cleanup.
https://bugzilla.gnome.org/show_bug.cgi?id=699818
gi/object.c | 187 ++++++++++++++++++++++++++---------------------------------
gi/object.h | 8 +--
gi/repo.c | 3 +-
3 files changed, 86 insertions(+), 112 deletions(-)
---
diff --git a/gi/object.c b/gi/object.c
index 17c981f..a49dae7 100644
--- a/gi/object.c
+++ b/gi/object.c
@@ -1410,14 +1410,66 @@ object_instance_finalize(JSFreeOp *fop,
g_slice_free(ObjectInstance, priv);
}
-JSObject*
-gjs_lookup_object_prototype(JSContext *context,
- GType gtype)
+static JSObject *
+gjs_lookup_object_prototype_from_info(JSContext *context,
+ GIObjectInfo *info,
+ GType gtype)
{
- JSObject *proto;
+ JSObject *in_object;
+ JSObject *constructor;
+ const char *constructor_name;
+ jsval value;
+
+ if (info) {
+ in_object = gjs_lookup_namespace_object(context, (GIBaseInfo*) info);
+ constructor_name = g_base_info_get_name((GIBaseInfo*) info);
+ } else {
+ in_object = gjs_lookup_private_namespace(context);
+ constructor_name = g_type_name(gtype);
+ }
+
+ if (G_UNLIKELY (!in_object))
+ return NULL;
+
+ if (!JS_GetProperty(context, in_object, constructor_name, &value))
+ return NULL;
+
+ if (JSVAL_IS_VOID(value)) {
+ /* In case we're looking for a private type, and we don't find it,
+ we need to define it first.
+ */
+ gjs_define_object_class(context, in_object, NULL, gtype, &constructor);
+ } else {
+ if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+ return NULL;
+
+ constructor = JSVAL_TO_OBJECT(value);
+ }
- if (!gjs_define_object_class(context, NULL, gtype, NULL, &proto))
+ g_assert(constructor != NULL);
+
+ if (!gjs_object_get_property_const(context, constructor,
+ GJS_STRING_PROTOTYPE, &value))
+ return NULL;
+
+ if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
return NULL;
+
+ return JSVAL_TO_OBJECT(value);
+}
+
+static JSObject *
+gjs_lookup_object_prototype(JSContext *context,
+ GType gtype)
+{
+ GIObjectInfo *info;
+ JSObject *proto;
+
+ info = (GIObjectInfo*)g_irepository_find_by_gtype(g_irepository_get_default(), gtype);
+ proto = gjs_lookup_object_prototype_from_info(context, info, gtype);
+ if (info)
+ g_base_info_unref((GIBaseInfo*)info);
+
return proto;
}
@@ -1828,12 +1880,12 @@ gjs_define_static_methods(JSContext *context,
return JS_TRUE;
}
-JSBool
-gjs_define_object_class(JSContext *context,
- JSObject *in_object,
- GType gtype,
- JSObject **constructor_p,
- JSObject **prototype_p)
+void
+gjs_define_object_class(JSContext *context,
+ JSObject *in_object,
+ GIObjectInfo *info,
+ GType gtype,
+ JSObject **constructor_p)
{
const char *constructor_name;
JSObject *prototype;
@@ -1841,25 +1893,12 @@ gjs_define_object_class(JSContext *context,
JSObject *parent_proto;
jsval value;
ObjectInstance *priv;
- GIObjectInfo *info = NULL;
const char *ns;
+ GType parent_type;
+ g_assert(in_object != NULL);
g_assert(gtype != G_TYPE_INVALID);
- info = (GIObjectInfo*)g_irepository_find_by_gtype(g_irepository_get_default(), gtype);
-
- if (!in_object) {
- if (info)
- in_object = gjs_lookup_namespace_object(context, (GIBaseInfo*) info);
- else
- in_object = gjs_lookup_private_namespace(context);
-
- if (!in_object) {
- if (info)
- g_base_info_unref((GIBaseInfo*)info);
- return FALSE;
- }
- }
/* http://egachine.berlios.de/embedding-sm-best-practice/apa.html
* http://www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/
* http://www.cs.rit.edu/~atk/JavaScript/manuals/jsobj/
@@ -1900,77 +1939,22 @@ gjs_define_object_class(JSContext *context,
* JavaScript is SO AWESOME
*/
- /* 'gtype' is the GType of a concrete class (if any) which may or may not
- * be defined in the GIRepository. 'info' corresponds to the first known
- * ancestor of 'gtype' (or the gtype itself.)
- *
- * For example:
- * gtype=GtkWindow info=Gtk.Window (defined)
- * gtype=GLocalFile info=GLib.Object (not defined)
- * gtype=GHalMount info=GLib.Object (not defined)
- *
- * Each GType needs to have distinct JS class, otherwise the JS class for
- * first common parent in GIRepository gets used with conflicting gtypes
- * when resolving GTypeInterface methods.
- *
- * In case 'gtype' is not defined in GIRepository use the type name as
- * constructor assuming it is unique enough instead of sharing
- * 'Object' (or whatever the first known ancestor is)
- *
- */
- if (!info) {
- constructor_name = g_type_name(gtype);
- } else {
- constructor_name = g_base_info_get_name((GIBaseInfo*) info);
- }
-
- if (!JS_GetProperty(context, in_object, constructor_name, &value)) {
- if (info)
- g_base_info_unref(info);
- return JS_FALSE;
- }
- if (!JSVAL_IS_VOID(value)) {
- if (!JSVAL_IS_OBJECT(value)) {
- gjs_throw(context, "Existing property '%s' does not look like a constructor",
- constructor_name);
- g_base_info_unref((GIBaseInfo*)info);
- return FALSE;
- }
-
- constructor = JSVAL_TO_OBJECT(value);
-
- gjs_object_get_property_const(context, constructor, GJS_STRING_PROTOTYPE, &value);
- if (!JSVAL_IS_OBJECT(value)) {
- gjs_throw(context, "prototype property does not appear to exist or has wrong type");
- g_base_info_unref((GIBaseInfo*)info);
- return FALSE;
- } else {
- if (prototype_p)
- *prototype_p = JSVAL_TO_OBJECT(value);
- if (constructor_p)
- *constructor_p = constructor;
-
- if (info)
- g_base_info_unref((GIBaseInfo*)info);
- return TRUE;
- }
- }
-
parent_proto = NULL;
- if (g_type_parent(gtype) != G_TYPE_INVALID) {
- GType parent_gtype;
+ parent_type = g_type_parent(gtype);
+ if (parent_type != G_TYPE_INVALID)
+ parent_proto = gjs_lookup_object_prototype(context, parent_type);
- parent_gtype = g_type_parent(gtype);
- parent_proto = gjs_lookup_object_prototype(context, parent_gtype);
- }
-
- /* This is only used to disambiguate classes in the import global.
+ /* ns is only used to set the JSClass->name field (exposed by Object.prototype.toString).
* We can safely set "unknown" if there is no info, as in that case
* the name is globally unique (it's a GType name). */
- if (info)
+ if (info) {
ns = g_base_info_get_namespace((GIBaseInfo*) info);
- else
+ constructor_name = g_base_info_get_name((GIBaseInfo*) info);
+ } else {
ns = "unknown";
+ constructor_name = g_type_name(gtype);
+ }
+
if (!gjs_init_class_dynamic(context, in_object,
parent_proto,
ns, constructor_name,
@@ -1993,7 +1977,7 @@ gjs_define_object_class(JSContext *context,
priv = g_slice_new0(ObjectInstance);
priv->info = info;
if (info)
- g_base_info_ref( (GIBaseInfo*) priv->info);
+ g_base_info_ref((GIBaseInfo*) info);
priv->gtype = gtype;
priv->klass = g_type_class_ref (gtype);
JS_SetPrivate(prototype, priv);
@@ -2008,15 +1992,8 @@ gjs_define_object_class(JSContext *context,
JS_DefineProperty(context, constructor, "$gtype", value,
NULL, NULL, JSPROP_PERMANENT);
- if (prototype_p)
- *prototype_p = prototype;
-
if (constructor_p)
*constructor_p = constructor;
-
- if (info)
- g_base_info_unref((GIBaseInfo*)info);
- return TRUE;
}
static JSObject*
@@ -2046,14 +2023,14 @@ gjs_object_from_g_object(JSContext *context,
if (obj == NULL) {
/* We have to create a wrapper */
JSObject *proto;
+ GType gtype;
gjs_debug_marshal(GJS_DEBUG_GOBJECT,
"Wrapping %s with JSObject",
g_type_name_from_instance((GTypeInstance*) gobj));
-
- if (!gjs_define_object_class(context, NULL, G_TYPE_FROM_INSTANCE(gobj), NULL, &proto))
- return NULL;
+ gtype = G_TYPE_FROM_INSTANCE(gobj);
+ proto = gjs_lookup_object_prototype(context, gtype);
JS_BeginRequest(context);
@@ -2457,7 +2434,7 @@ gjs_register_type(JSContext *cx,
{
jsval *argv = JS_ARGV(cx, vp);
gchar *name;
- JSObject *parent, *constructor, *interfaces;
+ JSObject *parent, *constructor, *interfaces, *module;
GType instance_type, parent_type;
GTypeQuery query;
GTypeModule *type_module;
@@ -2560,8 +2537,8 @@ gjs_register_type(JSContext *cx,
gjs_add_interface(instance_type, iface_types[i]);
/* create a custom JSClass */
- if (!gjs_define_object_class(cx, NULL, instance_type, &constructor, NULL))
- goto out;
+ module = gjs_lookup_private_namespace(cx);
+ gjs_define_object_class(cx, module, NULL, instance_type, &constructor);
JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(constructor));
diff --git a/gi/object.h b/gi/object.h
index 145139c..b1a8a1f 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -30,13 +30,11 @@
G_BEGIN_DECLS
-JSBool gjs_define_object_class (JSContext *context,
+void gjs_define_object_class (JSContext *context,
JSObject *in_object,
+ GIObjectInfo *info,
GType gtype,
- JSObject **constructor_p,
- JSObject **prototype_p);
-JSObject* gjs_lookup_object_prototype (JSContext *context,
- GType gtype);
+ JSObject **constructor_p);
JSObject* gjs_object_from_g_object (JSContext *context,
GObject *gobj);
GObject* gjs_g_object_from_object (JSContext *context,
diff --git a/gi/repo.c b/gi/repo.c
index 24d10ae..1f94c3a 100644
--- a/gi/repo.c
+++ b/gi/repo.c
@@ -473,8 +473,7 @@ gjs_define_info(JSContext *context,
if (!gjs_define_param_class(context, in_object, NULL))
return JS_FALSE;
} else if (g_type_is_a (gtype, G_TYPE_OBJECT)) {
- if (!gjs_define_object_class(context, in_object, gtype, NULL, NULL))
- return JS_FALSE;
+ gjs_define_object_class(context, in_object, (GIObjectInfo*) info, gtype, NULL);
} else {
gjs_throw (context,
"Unsupported type %s, deriving from fundamental %s",
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]