gjs r113 - in trunk: gi test/js
- From: otaylor svn gnome org
- To: svn-commits-list gnome org
- Subject: gjs r113 - in trunk: gi test/js
- Date: Wed, 19 Nov 2008 22:30:41 +0000 (UTC)
Author: otaylor
Date: Wed Nov 19 22:30:41 2008
New Revision: 113
URL: http://svn.gnome.org/viewvc/gjs?rev=113&view=rev
Log:
Allow direct allocation of "simple" boxed structures.
gi/boxed.c: Identify boxes types that are "simple" (no pointer fields)
and allow allocating them with g_slice_new rather than requiring a
constructor.
test/js/testEverythingEncapsulated.js: Add a test for simple boxed
structures.
https://bugzilla.gnome.org/show_bug.cgi?id=560808
Modified:
trunk/gi/boxed.c
trunk/test/js/testEverythingEncapsulated.js
Modified: trunk/gi/boxed.c
==============================================================================
--- trunk/gi/boxed.c (original)
+++ trunk/gi/boxed.c Wed Nov 19 22:30:41 2008
@@ -41,6 +41,8 @@
typedef struct {
GIBoxedInfo *info;
void *gboxed; /* NULL if we are the prototype and not an instance */
+ guint can_allocate_directly : 1;
+ guint allocated_directly : 1;
} Boxed;
static Boxed unthreadsafe_template_for_constructor = { NULL, NULL };
@@ -141,29 +143,31 @@
return JS_TRUE;
}
-static void*
+static JSBool
boxed_new(JSContext *context,
JSObject *obj, /* "this" for constructor */
- GIBoxedInfo *info)
+ Boxed *priv)
{
int n_methods;
int i;
/* Find a zero-args constructor and call it */
- n_methods = g_struct_info_get_n_methods(info);
+ n_methods = g_struct_info_get_n_methods(priv->info);
for (i = 0; i < n_methods; ++i) {
GIFunctionInfo *func_info;
GIFunctionInfoFlags flags;
- func_info = g_struct_info_get_method(info, i);
+ func_info = g_struct_info_get_method(priv->info, i);
flags = g_function_info_get_flags(func_info);
if ((flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0 &&
g_callable_info_get_n_args((GICallableInfo*) func_info) == 0) {
jsval rval;
+ GType gtype;
+ void *gboxed;
rval = JSVAL_NULL;
gjs_invoke_c_function(context, func_info, obj,
@@ -171,23 +175,42 @@
g_base_info_unref((GIBaseInfo*) func_info);
+ if (JSVAL_IS_NULL(rval))
+ return JS_FALSE;
+
/* We are somewhat wasteful here; invoke_c_function() above
* creates a JSObject wrapper for the boxed that we immediately
* discard.
*/
- if (JSVAL_IS_NULL(rval))
- return NULL;
- else
- return gjs_g_boxed_from_boxed(context, JSVAL_TO_OBJECT(rval));
+ gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+ gboxed = gjs_g_boxed_from_boxed(context, JSVAL_TO_OBJECT(rval));
+ priv->gboxed = g_boxed_copy (gtype, gboxed);
+
+ gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
+ "JSObject created with boxed instance %p type %s",
+ priv->gboxed, g_type_name(gtype));
+
+ return JS_TRUE;
}
g_base_info_unref((GIBaseInfo*) func_info);
}
+ if (priv->can_allocate_directly) {
+ priv->gboxed = g_slice_alloc0(g_struct_info_get_size (priv->info));
+ priv->allocated_directly = TRUE;
+
+ gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
+ "JSObject created by directly allocating %s",
+ g_base_info_get_name ((GBaseInfo *)priv->info));
+
+ return JS_TRUE;
+ }
+
gjs_throw(context, "Unable to construct boxed type %s since it has no zero-args <constructor>, can only wrap an existing one",
- g_base_info_get_name((GIBaseInfo*) info));
+ g_base_info_get_name((GIBaseInfo*) priv->info));
- return NULL;
+ return JS_FALSE;
}
/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
@@ -243,8 +266,6 @@
is_proto, obj_class->name, proto_class->name);
if (!is_proto) {
- GType gtype;
-
/* If we're the prototype, then post-construct we'll fill in priv->info.
* If we are not the prototype, though, then we'll get ->info from the
* prototype and then create a GObject if we don't have one already.
@@ -257,10 +278,9 @@
}
priv->info = proto_priv->info;
+ priv->can_allocate_directly = proto_priv->can_allocate_directly;
g_base_info_ref( (GIBaseInfo*) priv->info);
- gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
-
/* Since gobject-introspection is always creating new info
* objects, == is not meaningful on them, only comparison of
* their names. We prefer to use the info that is already ref'd
@@ -273,32 +293,14 @@
unthreadsafe_template_for_constructor.info = NULL;
if (unthreadsafe_template_for_constructor.gboxed == NULL) {
- void *gboxed;
-
- /* boxed_new happens to be implemented by calling
- * gjs_invoke_c_function(), which returns a jsval.
- * The returned "gboxed" here is owned by that jsval,
- * not by us.
- */
- gboxed = boxed_new(context, obj, priv->info);
-
- if (gboxed == NULL) {
+ if (!boxed_new(context, obj, priv))
return JS_FALSE;
- }
-
- /* Because "gboxed" is owned by a jsval and will
- * be garbage colleced, we make a copy here to be
- * owned by us.
- */
- priv->gboxed = g_boxed_copy(gtype, gboxed);
} else {
+ GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
+
priv->gboxed = g_boxed_copy(gtype, unthreadsafe_template_for_constructor.gboxed);
unthreadsafe_template_for_constructor.gboxed = NULL;
}
-
- gjs_debug_lifecycle(GJS_DEBUG_GBOXED,
- "JSObject created with boxed instance %p type %s",
- priv->gboxed, g_type_name(gtype));
}
return JS_TRUE;
@@ -317,8 +319,12 @@
return; /* wrong class? */
if (priv->gboxed) {
- g_boxed_free(g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info),
- priv->gboxed);
+ if (priv->allocated_directly)
+ g_slice_free1(g_struct_info_get_size (priv->info), priv->gboxed);
+ else
+ g_boxed_free(g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info),
+ priv->gboxed);
+
priv->gboxed = NULL;
}
@@ -606,6 +612,103 @@
return JS_GetClass(context, prototype);
}
+/* Check if the type of the boxed is "simple" - every field is a non-pointer
+ * type that we know how to assign to. If so, then we can allocate and free
+ * instances without needing a constructor.
+ */
+static void
+check_can_allocate_directly(Boxed *priv)
+{
+ GIBoxedInfo *info = priv->info;
+ int n_fields = g_struct_info_get_n_fields (info);
+ gboolean can_allocate_directly = TRUE;
+ int i;
+
+ for (i = 0; i < n_fields && can_allocate_directly; i++) {
+ GIFieldInfo *field_info = g_struct_info_get_field (info, i);
+ GITypeInfo *type_info = g_field_info_get_type (field_info);
+
+ if (g_type_info_is_pointer (type_info)) {
+ can_allocate_directly = FALSE;
+ } else {
+ switch (g_type_info_get_tag (type_info)) {
+ case GI_TYPE_TAG_BOOLEAN:
+ case GI_TYPE_TAG_INT8:
+ case GI_TYPE_TAG_UINT8:
+ case GI_TYPE_TAG_INT16:
+ case GI_TYPE_TAG_UINT16:
+ case GI_TYPE_TAG_INT32:
+ case GI_TYPE_TAG_UINT32:
+ case GI_TYPE_TAG_INT:
+ case GI_TYPE_TAG_UINT:
+ case GI_TYPE_TAG_INT64:
+ case GI_TYPE_TAG_UINT64:
+ case GI_TYPE_TAG_LONG:
+ case GI_TYPE_TAG_ULONG:
+ case GI_TYPE_TAG_SSIZE:
+ case GI_TYPE_TAG_SIZE:
+ case GI_TYPE_TAG_FLOAT:
+ case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_TIME_T:
+ break;
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_GTYPE:
+ case GI_TYPE_TAG_ERROR:
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ break;
+ case GI_TYPE_TAG_INTERFACE:
+ {
+ GIBaseInfo *interface = g_type_info_get_interface (type_info);
+ switch (g_base_info_get_type (interface)) {
+ case GI_INFO_TYPE_STRUCT:
+ case GI_INFO_TYPE_UNION:
+ case GI_INFO_TYPE_BOXED:
+ /* FIXME: Check if the nested type can be allocated directly */
+ can_allocate_directly = FALSE;
+ break;
+ case GI_INFO_TYPE_ENUM:
+ case GI_INFO_TYPE_FLAGS:
+ can_allocate_directly = FALSE;
+ /* FIXME: Needs to be implemented in g_field_info_set_field */
+ can_allocate_directly = FALSE;
+ break;
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_VFUNC:
+ case GI_INFO_TYPE_CALLBACK:
+ case GI_INFO_TYPE_INVALID:
+ case GI_INFO_TYPE_INTERFACE:
+ case GI_INFO_TYPE_FUNCTION:
+ case GI_INFO_TYPE_CONSTANT:
+ case GI_INFO_TYPE_ERROR_DOMAIN:
+ case GI_INFO_TYPE_VALUE:
+ case GI_INFO_TYPE_SIGNAL:
+ case GI_INFO_TYPE_PROPERTY:
+ case GI_INFO_TYPE_FIELD:
+ case GI_INFO_TYPE_ARG:
+ case GI_INFO_TYPE_TYPE:
+ case GI_INFO_TYPE_UNRESOLVED:
+ can_allocate_directly = FALSE;
+ break;
+ }
+
+ g_base_info_unref (interface);
+ break;
+ }
+ }
+ }
+
+ g_base_info_unref ((GIBaseInfo *)field_info);
+ g_base_info_unref ((GIBaseInfo *)type_info);
+ }
+
+ priv->can_allocate_directly = can_allocate_directly;
+}
+
JSBool
gjs_define_boxed_class(JSContext *context,
JSObject *in_object,
@@ -689,6 +792,8 @@
gjs_debug(GJS_DEBUG_GBOXED, "Defined class %s prototype is %p class %p in object %p",
constructor_name, prototype, JS_GetClass(context, prototype), in_object);
+ check_can_allocate_directly (priv);
+
define_boxed_class_fields (context, priv, prototype);
if (constructor_p) {
Modified: trunk/test/js/testEverythingEncapsulated.js
==============================================================================
--- trunk/test/js/testEverythingEncapsulated.js (original)
+++ trunk/test/js/testEverythingEncapsulated.js Wed Nov 19 22:30:41 2008
@@ -1,5 +1,15 @@
const Everything = imports.gi.Everything;
+function testSimpleBoxed() {
+ simple_boxed = new Everything.TestSimpleBoxedA();
+ simple_boxed.some_int = 42;
+ simple_boxed.some_int8 = 43;
+ simple_boxed.some_double = 42.5;
+ assertEquals(42, simple_boxed.some_int);
+ assertEquals(43, simple_boxed.some_int8);
+ assertEquals(42.5, simple_boxed.some_double);
+}
+
function testBoxed() {
boxed = new Everything.TestBoxed();
boxed.some_int8 = 42;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]