Index: test/js/testEverythingBasic.js
===================================================================
--- test/js/testEverythingBasic.js	(revision 105)
+++ test/js/testEverythingBasic.js	(working copy)
@@ -80,12 +80,48 @@
     }
 }
 
-function testStrv() {
-    assertTrue(Everything.test_strv_in(['1', '2', '3']));
+function testArrayString() {
+    assertTrue(Everything.test_array_string_in(['1', '2', '3']));
     // Second two are deliberately not strings
-    assertRaises(function() { Everything.test_strv_in(['1', 2, 3]); });
+    assertRaises(function() { Everything.test_array_string_in(['1', 2, 3]); });
 }
 
+function testArrayInt() {
+    assertEquals(42, Everything.test_array_int_in(1, [42]));
+    var sum = 0, i, ints = new Array();
+    for (i = 0; i < 10; i++) {
+      ints.push(i);
+      sum += i;
+    }
+    log(ints);
+    assertEquals(sum, Everything.test_array_int_in(10, ints));
+    assertEquals(1180, Everything.test_array_int_in(2, [42, 1138]));
+    assertRaises(function() { Everything.test_array_int_in([1, 2, '3']); });
+}
+
+function testArrayFloat() {
+    var sum = 0, i, floats = new Array();
+    for (i = 1; i < 10; i++) {
+      floats.push(i*0.1);
+    }
+    log(floats);
+    sum = Everything.test_array_float_in(floats.length, floats);
+    assert(sum > 4.4 && sum < 4.6);
+    assertRaises(function() { Everything.test_array_float_in([1.0, 2, '3']); });
+}
+
+function testArrayDouble() {
+    assertEquals(42, Everything.test_array_double_in(1, [42]));
+    var sum = 0, i, doubles = new Array();
+    for (i = 1; i < 10; i++) {
+      doubles.push(i*0.1);
+    }
+    log(doubles);
+    sum = Everything.test_array_double_in(doubles.length, doubles);
+    assert(sum > 4.4 && sum < 4.6);
+    assertRaises(function() { Everything.test_array_double_in([1.0, 2, '3']); });
+}
+
 function testFilenameReturn() {
     var filenames = Everything.test_filename_return();
     assertEquals(2, filenames.length);
Index: gi/arg.c
===================================================================
--- gi/arg.c	(revision 105)
+++ gi/arg.c	(working copy)
@@ -29,11 +29,13 @@
 #include "union.h"
 #include "value.h"
 #include <gjs/gjs.h>
+#include <girffi.h>
 
 #include <util/log.h>
 
 static JSBool gjs_value_to_g_arg_with_type_info(JSContext  *context,
                                                 jsval       value,
+                                                GITypeTag   type_tag,
                                                 GITypeInfo *type_info,
                                                 const char *arg_name,
                                                 gboolean    is_return_value,
@@ -138,6 +140,7 @@
          */
         if (!gjs_value_to_g_arg_with_type_info(context,
                                                elem,
+                                               param_tag,
                                                param_info,
                                                "list element",
                                                FALSE,
@@ -165,83 +168,94 @@
 }
 
 JSBool
-gjs_array_to_strv(JSContext   *context,
-                  jsval        array_value,
-                  unsigned int length,
-                  void       **arr_p)
+gjs_array_to_array(JSContext    *context,
+                   jsval         array_value,
+                   unsigned int  length,
+                   GITypeTag     param_type_tag,
+                   GITypeInfo   *param_info,
+                   gboolean      zero_terminated,
+                   void        **arguments_p)
 {
-    char **result;
-    guint32 i;
+    guint32 alloc_size, i, j;
+    jsval elem;
+    void *tmp;
+    gboolean failed = FALSE;
+    JSObject *array;
+    ffi_type *ftype;
+    
+    ftype = g_ir_ffi_get_ffi_type(param_type_tag);
+    array = JSVAL_TO_OBJECT(array_value);
 
-    result = g_new0(char *, length+1);
+    alloc_size = length;
+    if (zero_terminated)
+        alloc_size += 1;
 
+    tmp = g_malloc0(alloc_size * ftype->size);
+    
     for (i = 0; i < length; ++i) {
-        jsval elem;
-
         elem = JSVAL_VOID;
-        if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
-                           i, &elem)) {
-            g_free(result);
-            gjs_throw(context,
-                      "Missing array element %u",
-                      i);
-            return JS_FALSE;
+        if (!JS_GetElement(context, array, i, &elem)) {
+            gjs_throw(context, "Missing array element %u", i);
+            failed = TRUE;
+            break;
         }
 
-        if (!JSVAL_IS_STRING(elem)) {
-            gjs_throw(context,
-                      "Invalid element in string array");
-            g_strfreev(result);
-            return JS_FALSE;
+        if (!gjs_value_to_g_arg_with_type_info(context, elem, param_type_tag,
+                                               param_info,
+                                               "element argument", FALSE,
+                                               TRUE,
+                                               (void*)((guchar*)tmp + i * ftype->size))) {
+            /* exception already set */
+            failed = TRUE;
+            break;
         }
-        if (!gjs_string_to_utf8(context, elem, (char **)&(result[i]))) {
-            g_strfreev(result);
-            return JS_FALSE;
-        }
     }
 
-    *arr_p = result;
+    if (failed) {
+        for (j = 0; j < i; ++j) {
+            gjs_g_arg_release(context,
+                              0, /* FIXME, JS_GetElement */
+                              GI_TRANSFER_EVERYTHING,
+                              param_info,
+                              (void*)((guchar*)tmp + i * ftype->size));
+        }
+        g_free(tmp);
+        return JS_FALSE;
+    } 
 
+    *arguments_p = tmp;
+    
     return JS_TRUE;
 }
 
+/**
+ * gjs_value_to_g_arg_with_type_info:
+ *
+ * @context: the context we are executed in
+ * @value: value to convert
+ * @type_tag: the type of argument
+ * @type_info: type info for the argument, can be NULL for basic types
+ * @arg_name: what kind of argument we send, used in exception messages
+ * @is_return_value: is the argument a return value?
+ * @may_be_null: is null allowed?
+ * @arg: where the argument should be stored, should be initialized before
+ *       calling this function.
+ */
 static JSBool
-gjs_array_to_array(JSContext   *context,
-                   jsval        array_value,
-                   unsigned int length,
-                   GITypeInfo  *param_info,
-                   void       **arr_p)
-{
-    GITypeTag element_type;
-
-    element_type = g_type_info_get_tag(param_info);
-
-    if (element_type == GI_TYPE_TAG_UTF8) {
-        return gjs_array_to_strv (context, array_value, length, arr_p);
-    } else {
-        gjs_throw(context,
-                  "Unhandled array element type %d", element_type);
-        return JS_FALSE;
-    }
-}
-
-static JSBool
 gjs_value_to_g_arg_with_type_info(JSContext  *context,
                                   jsval       value,
+                                  GITypeTag   type_tag,
                                   GITypeInfo *type_info,
                                   const char *arg_name,
                                   gboolean    is_return_value,
                                   gboolean    may_be_null,
                                   GArgument  *arg)
 {
-    GITypeTag type_tag;
     gboolean wrong;
     gboolean out_of_range;
     gboolean report_type_mismatch;
     gboolean nullable_type;
 
-    type_tag = g_type_info_get_tag( (GITypeInfo*) type_info);
-
     gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
                       "Converting jsval to GArgument %s",
                       g_type_tag_to_string(type_tag));
@@ -400,6 +414,7 @@
             GIBaseInfo* symbol_info;
             GType gtype;
 
+            g_assert(type_info != NULL);
             symbol_info = g_type_info_get_interface(type_info);
             g_assert(symbol_info != NULL);
 
@@ -528,6 +543,7 @@
                 GSList *slist;
                 GITypeInfo *param_info;
 
+                g_assert(type_info != NULL);
                 param_info = g_type_info_get_param_type(type_info, 0);
                 g_assert(param_info != NULL);
 
@@ -574,11 +590,17 @@
                 wrong = TRUE;
             } else {
                 GITypeInfo *param_info;
-
+                GITypeTag param_type;
+                gboolean zero_terminated;
+                
+                g_assert(type_info != NULL);
                 param_info = g_type_info_get_param_type(type_info, 0);
                 g_assert(param_info != NULL);
-
-                if (!gjs_array_to_array (context, value, length, param_info, &arg->v_pointer))
+                param_type = g_type_info_get_tag( (GITypeInfo*) param_info);
+                zero_terminated = g_type_info_is_zero_terminated(type_info);
+                if (!gjs_array_to_array (context, value, length, param_type,
+                                         param_info, zero_terminated,
+                                         (void**)&arg->v_pointer))
                     wrong = TRUE;
 
                 g_base_info_unref((GIBaseInfo*) param_info);
@@ -642,6 +664,7 @@
 
     result =
         gjs_value_to_g_arg_with_type_info(context, value,
+                                          g_type_info_get_tag( (GITypeInfo*) type_info),
                                           type_info,
                                           g_base_info_get_name( (GIBaseInfo*) arg_info),
                                           g_arg_info_is_return_value(arg_info),
@@ -932,6 +955,7 @@
 
 static JSBool
 gjs_g_arg_release_internal(JSContext  *context,
+                           jsval       value,
                            GITransfer  transfer,
                            GITypeInfo *type_info,
                            GITypeTag   type_tag,
@@ -970,7 +994,6 @@
             if (arg->v_pointer == NULL) {
                 /* nothing to do */
             } else {
-                jsval value;
                 GIBaseInfo* symbol_info;
                 GType gtype;
 
@@ -982,16 +1005,14 @@
                 gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
                                   "gtype of SYMBOL is %s", g_type_name(gtype));
 
-                value = JSVAL_NULL;
-
                 if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) {
                     g_object_unref(G_OBJECT(arg->v_pointer));
                 } else if (g_type_is_a(gtype, G_TYPE_BOXED)) {
                     g_boxed_free(gtype, arg->v_pointer);
                 } else if (g_type_is_a(gtype, G_TYPE_VALUE)) {
-                    GValue *value = arg->v_pointer;
-                    g_value_unset(value);
-                    g_slice_free(GValue, value);
+                    GValue *gvalue = arg->v_pointer;
+                    g_value_unset(gvalue);
+                    g_slice_free(GValue, gvalue);
                 } else if (g_type_is_a(gtype, G_TYPE_ENUM) || g_type_is_a(gtype, G_TYPE_FLAGS)) {
                     /* nothing to do */
                 } else {
@@ -1019,6 +1040,7 @@
                 elem.v_pointer = list->data;
 
                 if (!gjs_g_arg_release(context,
+                                       value, /* FIXME, JS_GetElement */
                                        GI_TRANSFER_EVERYTHING,
                                        param_info,
                                        &elem)) {
@@ -1040,16 +1062,52 @@
             /* OK */
         } else {
             GITypeInfo *param_info;
-
+            void *arguments = arg->v_pointer;
+            GITypeTag param_type_tag;
+            ffi_type *ftype;
+            jsval length_value;
+            guint32 length;
+            unsigned int i;
+            gboolean zero_terminated;
+            
             param_info = g_type_info_get_param_type(type_info, 0);
-
             if (g_type_info_get_tag (param_info) == GI_TYPE_TAG_UTF8 ||
                 g_type_info_get_tag (param_info) == GI_TYPE_TAG_FILENAME)
-                g_strfreev (arg->v_pointer);
-            else
-                g_assert_not_reached ();
+                gjs_debug_marshal(GJS_DEBUG_MEMORY,
+                                  "Releasing memory for string arrays is not properly "
+                                  "implemented. Leaking.");
+            
+            param_type_tag = g_type_info_get_tag( (GITypeInfo*) param_info);
+            ftype = g_ir_ffi_get_ffi_type(param_type_tag);
+            
+            if (!gjs_object_require_property(context,
+                                             JSVAL_TO_OBJECT(value),
+                                             "length",
+                                             &length_value) ||
+                !JS_ValueToECMAUint32(context, length_value, &length)) {
+                g_error("Failed to release list element");
+                break;
+            }
 
+            zero_terminated = g_type_info_is_zero_terminated(type_info);
+            if (zero_terminated)
+                length += 1;
+            
+            for (i = 0; i < length; ++i) {
+                if (!gjs_g_arg_release(context, 
+                                       0, /* FIXME, JS_GetElement */
+                                       GI_TRANSFER_EVERYTHING,
+                                       param_info,
+                                       (void*)(((guchar*)arguments) + i * ftype->size))) {
+                    /* no way to recover here, and errors should
+                     * not be possible.
+                     */
+                    g_error("Failed to release list element");
+                    break;
+                }
+            }
             g_base_info_unref((GIBaseInfo*) param_info);
+            g_free(arguments);
         }
         break;
 
@@ -1068,6 +1126,7 @@
                 elem.v_pointer = slist->data;
 
                 if (!gjs_g_arg_release(context,
+                                       value, /* FIXME, JS_GetElement */
                                        GI_TRANSFER_EVERYTHING,
                                        param_info,
                                        &elem)) {
@@ -1096,6 +1155,7 @@
 
 JSBool
 gjs_g_arg_release(JSContext  *context,
+                  jsval       value,
                   GITransfer  transfer,
                   GITypeInfo *type_info,
                   GArgument  *arg)
@@ -1111,11 +1171,12 @@
                       "Releasing GArgument %s out param or return value",
                       g_type_tag_to_string(type_tag));
 
-    return gjs_g_arg_release_internal(context, transfer, type_info, type_tag, arg);
+    return gjs_g_arg_release_internal(context, value, transfer, type_info, type_tag, arg);
 }
 
 JSBool
 gjs_g_arg_release_in_arg(JSContext  *context,
+                         jsval       value,
                          GITransfer  transfer,
                          GITypeInfo *type_info,
                          GArgument  *arg)
@@ -1139,7 +1200,7 @@
     case GI_TYPE_TAG_UTF8:
     case GI_TYPE_TAG_FILENAME:
     case GI_TYPE_TAG_ARRAY:
-        return gjs_g_arg_release_internal(context, GI_TRANSFER_EVERYTHING,
+        return gjs_g_arg_release_internal(context, value, GI_TRANSFER_EVERYTHING,
                                           type_info, type_tag, arg);
     default:
         return JS_TRUE;
Index: gi/value.c
===================================================================
--- gi/value.c	(revision 105)
+++ gi/value.c	(working copy)
@@ -302,10 +302,13 @@
                 return JS_FALSE;
             } else {
                 char **strv;
-
-                if (!gjs_array_to_strv (context,
-                                        value,
-                                        length, (void**)&strv))
+                if (!gjs_array_to_array (context,
+                                         value,
+                                         length,
+                                         GI_TYPE_TAG_UTF8,
+                                         NULL,
+                                         TRUE,
+                                         (void**)&strv))
                     return JS_FALSE;
                 g_value_take_boxed (gvalue, strv);
             }
Index: gi/arg.h
===================================================================
--- gi/arg.h	(revision 105)
+++ gi/arg.h	(working copy)
@@ -41,10 +41,12 @@
                              GITypeInfo *type_info,
                              GArgument  *arg);
 JSBool gjs_g_arg_release    (JSContext  *context,
+                             jsval       value,
                              GITransfer  transfer,
                              GITypeInfo *type_info,
                              GArgument  *arg);
 JSBool gjs_g_arg_release_in_arg (JSContext  *context,
+                                 jsval       value,
                                  GITransfer  transfer,
                                  GITypeInfo *type_info,
                                  GArgument  *arg);
@@ -53,12 +55,14 @@
                                   GFlagsClass *klass,
                                   guint        value);
 
+JSBool gjs_array_to_array (JSContext    *context,
+                           jsval         array_value,
+                           unsigned int  length,
+                           GITypeTag     param_type,
+                           GITypeInfo   *param_info,
+                           gboolean      zero_terminated,
+                           void        **arguments);
 
-JSBool gjs_array_to_strv (JSContext   *context,
-                          jsval        array_value,
-                          unsigned int length,
-                          void       **arr_p);
-
 G_END_DECLS
 
 #endif  /* __GJS_ARG_H__ */
Index: gi/function.c
===================================================================
--- gi/function.c	(revision 105)
+++ gi/function.c	(working copy)
@@ -279,9 +279,10 @@
             /* Free GArgument, the jsval should have ref'd or copied it */
             if (invoke_ok &&
                 !gjs_g_arg_release(context,
-                                      g_callable_info_get_caller_owns((GICallableInfo*) info),
-                                      return_info,
-                                      &return_arg))
+                                   return_values[next_rval],
+                                   g_callable_info_get_caller_owns((GICallableInfo*) info),
+                                   return_info,
+                                   &return_arg))
                 failed = TRUE;
 
             ++next_rval;
@@ -308,6 +309,7 @@
             g_assert(in_args_pos < expected_in_argc);
 
             if (!gjs_g_arg_release_in_arg(context,
+                                          argv[i],
                                           g_arg_info_get_ownership_transfer(arg_info),
                                           arg_type_info,
                                           &in_args[in_args_pos]))
@@ -332,6 +334,7 @@
             /* Free GArgument, the jsval should have ref'd or copied it */
             if (invoke_ok &&
                 !gjs_g_arg_release(context,
+                                   argv[i],
                                    g_arg_info_get_ownership_transfer(arg_info),
                                    arg_type_info,
                                    out_args[out_args_pos].v_pointer))
