gjs r115 - in trunk: gi test/js
- From: otaylor svn gnome org
- To: svn-commits-list gnome org
- Subject: gjs r115 - in trunk: gi test/js
- Date: Wed, 19 Nov 2008 22:30:54 +0000 (UTC)
Author: otaylor
Date: Wed Nov 19 22:30:54 2008
New Revision: 115
URL: http://svn.gnome.org/viewvc/gjs?rev=115&view=rev
Log:
Allow access to nested structures
gi/boxed.c: Allow boxed objects that have no memory of their own
but point into the memory of a parent object. Use that to implementing
reading a field that is a nested simple boxed structure. (The
restriction to boxed structures and simple structures is artificial
and could be lifted.)
test/js/testEverythingEncapsulated.js: Test access to nested 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:54 2008
@@ -43,9 +43,18 @@
void *gboxed; /* NULL if we are the prototype and not an instance */
guint can_allocate_directly : 1;
guint allocated_directly : 1;
+ guint has_parent : 1; /* If set, this boxed doesn't have an independent allocation */
} Boxed;
-static Boxed unthreadsafe_template_for_constructor = { NULL, NULL };
+typedef struct {
+ GIBoxedInfo *info;
+ void *gboxed;
+ jsval parent_jsval;
+} BoxedConstructInfo;
+
+static gboolean struct_is_simple(GIStructInfo *info);
+
+static BoxedConstructInfo unthreadsafe_template_for_constructor = { NULL, NULL, JSVAL_NULL };
static struct JSClass gjs_boxed_class;
@@ -295,6 +304,20 @@
if (unthreadsafe_template_for_constructor.gboxed == NULL) {
if (!boxed_new(context, obj, priv))
return JS_FALSE;
+ } else if (!JSVAL_IS_NULL(unthreadsafe_template_for_constructor.parent_jsval)) {
+ /* A structure nested inside a parent object; doens't have an independent allocation */
+
+ priv->gboxed = unthreadsafe_template_for_constructor.gboxed;
+ priv->has_parent = TRUE;
+
+ /* We never actually read the reserved slot, but we put the parent object
+ * into it to hold onto the parent object.
+ */
+ JS_SetReservedSlot(context, obj, 0,
+ unthreadsafe_template_for_constructor.parent_jsval);
+
+ unthreadsafe_template_for_constructor.parent_jsval = JSVAL_NULL;
+ unthreadsafe_template_for_constructor.gboxed = NULL;
} else {
GType gtype = g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*) priv->info);
@@ -361,6 +384,59 @@
}
static JSBool
+get_nested_interface_object (JSContext *context,
+ JSObject *parent_obj,
+ Boxed *parent_priv,
+ GIFieldInfo *field_info,
+ GITypeInfo *type_info,
+ jsval *value)
+{
+ JSObject *obj;
+ JSObject *proto;
+ GIBaseInfo *info;
+ int offset;
+ gboolean success = FALSE;
+
+ info = g_type_info_get_interface (type_info);
+ if (!(g_base_info_get_type (info) == GI_INFO_TYPE_STRUCT || g_base_info_get_type (info) == GI_INFO_TYPE_BOXED) ||
+ g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*)info) == G_TYPE_NONE ||
+ !struct_is_simple ((GIStructInfo *)info)) {
+ gjs_throw(context, "Reading field %s.%s is not supported",
+ g_base_info_get_name ((GIBaseInfo *)parent_priv->info),
+ g_base_info_get_name ((GIBaseInfo *)field_info));
+
+ goto out;
+ }
+
+ proto = gjs_lookup_boxed_prototype(context, (GIBoxedInfo*) info);
+
+ offset = g_field_info_get_offset (field_info);
+ unthreadsafe_template_for_constructor.info = (GIBoxedInfo*) info;
+ unthreadsafe_template_for_constructor.gboxed = ((char *)parent_priv->gboxed) + offset;
+
+ /* Rooting the object here is a little paranoid; the JSObject has to be kept
+ * alive anyways by our caller; so this would matter only if there was an
+ * aggressive GC that moved rooted objects */
+ JS_AddRoot(context, &unthreadsafe_template_for_constructor.parent_jsval);
+ unthreadsafe_template_for_constructor.parent_jsval = OBJECT_TO_JSVAL(parent_obj);
+
+ obj = gjs_construct_object_dynamic(context, proto,
+ 0, NULL);
+
+ JS_RemoveRoot(context, &unthreadsafe_template_for_constructor.parent_jsval);
+
+ if (obj != NULL) {
+ success = TRUE;
+ *value = OBJECT_TO_JSVAL(obj);
+ }
+
+out:
+ g_base_info_unref( (GIBaseInfo*) info);
+
+ return success;
+}
+
+static JSBool
boxed_field_getter (JSContext *context,
JSObject *obj,
jsval id,
@@ -389,17 +465,26 @@
goto out;
}
- if (!g_field_info_get_field (field_info, priv->gboxed, &arg)) {
- gjs_throw(context, "Reading field %s.%s is not supported",
- g_base_info_get_name ((GIBaseInfo *)priv->info),
- g_base_info_get_name ((GIBaseInfo *)field_info));
- goto out;
- }
+ if (!g_type_info_is_pointer (type_info) &&
+ g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) {
- if (!gjs_value_from_g_argument (context, value,
- type_info,
- &arg))
- goto out;
+ if (!get_nested_interface_object (context, obj, priv, field_info, type_info, value))
+ goto out;
+
+ } else {
+ if (!g_field_info_get_field (field_info, priv->gboxed, &arg)) {
+ gjs_throw(context, "Reading field %s.%s is not supported",
+ g_base_info_get_name ((GIBaseInfo *)priv->info),
+ g_base_info_get_name ((GIBaseInfo *)field_info));
+ goto out;
+ }
+
+ if (!gjs_value_from_g_argument (context, value,
+ type_info,
+ &arg))
+ goto out;
+
+ }
success = TRUE;
@@ -533,13 +618,19 @@
* tell, it would only be used if no constructor were provided to
* JS_InitClass. The constructor from JS_InitClass is not applied to
* the prototype unless JSCLASS_CONSTRUCT_PROTOTYPE is in flags.
+ *
+ * We allocate 1 reserved slot; this is typically unused, but if the
+ * boxed is for a nested structure inside a parent structure, the
+ * reserved slot is used to hold onto the parent Javascript object and
+ * make sure it doesn't get freed.
*/
static struct JSClass gjs_boxed_class = {
NULL, /* dynamic class, no name here */
JSCLASS_HAS_PRIVATE |
JSCLASS_NEW_RESOLVE |
JSCLASS_NEW_RESOLVE_GETS_START |
- JSCLASS_CONSTRUCT_PROTOTYPE,
+ JSCLASS_CONSTRUCT_PROTOTYPE |
+ JSCLASS_HAS_RESERVED_SLOTS(1),
JS_PropertyStub,
JS_PropertyStub,
JS_PropertyStub,
@@ -616,20 +707,19 @@
* 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)
+static gboolean
+struct_is_simple(GIStructInfo *info)
{
- GIBoxedInfo *info = priv->info;
int n_fields = g_struct_info_get_n_fields (info);
- gboolean can_allocate_directly = TRUE;
+ gboolean is_simple = TRUE;
int i;
- for (i = 0; i < n_fields && can_allocate_directly; i++) {
+ for (i = 0; i < n_fields && is_simple; 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;
+ is_simple = FALSE;
} else {
switch (g_type_info_get_tag (type_info)) {
case GI_TYPE_TAG_BOOLEAN:
@@ -665,17 +755,21 @@
{
GIBaseInfo *interface = g_type_info_get_interface (type_info);
switch (g_base_info_get_type (interface)) {
+ case GI_INFO_TYPE_BOXED:
case GI_INFO_TYPE_STRUCT:
+ if (g_registered_type_info_get_g_type( (GIRegisteredTypeInfo*)info) == G_TYPE_NONE ||
+ !struct_is_simple ((GIStructInfo *)interface))
+ is_simple = FALSE;
+ break;
case GI_INFO_TYPE_UNION:
- case GI_INFO_TYPE_BOXED:
- /* FIXME: Check if the nested type can be allocated directly */
- can_allocate_directly = FALSE;
+ /* FIXME: Need to implement */
+ is_simple = FALSE;
break;
case GI_INFO_TYPE_ENUM:
case GI_INFO_TYPE_FLAGS:
- can_allocate_directly = FALSE;
+ is_simple = FALSE;
/* FIXME: Needs to be implemented in g_field_info_set_field */
- can_allocate_directly = FALSE;
+ is_simple = FALSE;
break;
case GI_INFO_TYPE_OBJECT:
case GI_INFO_TYPE_VFUNC:
@@ -692,7 +786,7 @@
case GI_INFO_TYPE_ARG:
case GI_INFO_TYPE_TYPE:
case GI_INFO_TYPE_UNRESOLVED:
- can_allocate_directly = FALSE;
+ is_simple = FALSE;
break;
}
@@ -706,7 +800,7 @@
g_base_info_unref ((GIBaseInfo *)type_info);
}
- priv->can_allocate_directly = can_allocate_directly;
+ return is_simple;
}
JSBool
@@ -792,7 +886,7 @@
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);
+ priv->can_allocate_directly = struct_is_simple (priv->info);
define_boxed_class_fields (context, priv, prototype);
@@ -856,6 +950,7 @@
/* can't come up with a better approach... */
unthreadsafe_template_for_constructor.info = (GIBoxedInfo*) info;
unthreadsafe_template_for_constructor.gboxed = gboxed;
+ unthreadsafe_template_for_constructor.parent_jsval = JSVAL_NULL;
obj = gjs_construct_object_dynamic(context, proto,
0, NULL);
Modified: trunk/test/js/testEverythingEncapsulated.js
==============================================================================
--- trunk/test/js/testEverythingEncapsulated.js (original)
+++ trunk/test/js/testEverythingEncapsulated.js Wed Nov 19 22:30:54 2008
@@ -10,6 +10,14 @@
assertEquals(42.5, simple_boxed.some_double);
}
+function testNestedSimpleBoxed() {
+ let simple_boxed = new Everything.TestSimpleBoxedB();
+ simple_boxed.some_int8 = 42
+ simple_boxed.nested_a.some_int = 43;
+ assertEquals(42, simple_boxed.some_int8);
+ assertEquals(43, simple_boxed.nested_a.some_int);
+}
+
function testBoxed() {
let boxed = new Everything.TestBoxed();
boxed.some_int8 = 42;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]