Imported Upstream version 3.11.91 upstream/3.11.91
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 30 Oct 2018 01:27:05 +0000 (10:27 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 30 Oct 2018 01:27:05 +0000 (10:27 +0900)
25 files changed:
ChangeLog
Makefile.am
Makefile.in
NEWS
PKG-INFO
configure
configure.ac
gi/gimodule.c
gi/gobjectmodule.c
gi/pygi-array.c
gi/pygi-basictype.c
gi/pygi-cache.c
gi/pygi-cache.h
gi/pygi-ccallback.c
gi/pygi-closure.c
gi/pygi-enum-marshal.c
gi/pygi-invoke-state-struct.h
gi/pygi-invoke.c
gi/pygi-invoke.h
gi/pygi-marshal-cleanup.c
gi/pygi-property.c
gi/pygtype.c
tests/test_generictreemodel.py
tests/test_overrides_gtk.py
tests/test_properties.py

index 0b234c2..f8382f8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,190 @@
+commit 1a63a04eaf2a77c1752b90e80ab571677f27ac3d
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Mar 3 06:49:09 2014 -0800
+
+    build: Update release-news to use srcdir
+
+    Use $(top_srcdir)/NEWS for pulling in news items to ensure
+    "make release-news" works in a vpath build environment.
+
+ Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit 5798f94b6a727b930b07fe840b0aef264f98a80e
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Fri Feb 7 20:16:21 2014 -0800
+
+    Use ffi_call directly instead of g_callable_info_invoke
+
+    Cleanup internal callable cache and state tracking by removing
+    multiple
+    counting schemes for differently sized "in" and "out" argument arrays.
+    Use a single count based on the total number of arguments passed to C
+    (inclusive of instance argument and GError exception where
+    applicable).
+    Size all state tracking arrays to the same size and ensure argument
+    cache
+    indices always line up with these arrays. This cleans up logic
+    which was
+    required by g_callable_info_invoke for splitting "in" and "out"
+    arguments
+    up.
+
+    Cleanup array marshaling which can now rely on the new scheme
+    which ensures
+    the "arg_values" array always points to the correct location for
+    length
+    argument values.
+
+    Cache the ffi_cif struct in PyGICallableCache via GIFunctionInvoker
+    and
+    related GI methods. Overall, these changes can give a performance
+    boost of
+    almost 2x for simple function calls (see ticket for micro benchmarks).
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=723642
+
+ gi/pygi-array.c               |  26 ++---
+ gi/pygi-cache.c               |  61 +++++++++--
+ gi/pygi-cache.h               |  10 +-
+ gi/pygi-ccallback.c           |   3 +-
+ gi/pygi-closure.c             |   6 +-
+ gi/pygi-invoke-state-struct.h |  42 +++++---
+ gi/pygi-invoke.c              | 241
+ +++++++++++++++++++++++-------------------
+ gi/pygi-invoke.h              |   2 +-
+ gi/pygi-marshal-cleanup.c     |   4 +-
+ 9 files changed, 230 insertions(+), 165 deletions(-)
+
+commit ad680ae9c37a0091628a7d66010fbf70aa1a2e43
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Mar 3 04:51:09 2014 -0800
+
+    tests: Move class definition depending on GTK+ within function
+    evaluation
+
+    Move the definition of WindowWithSizeAllocOverride inside of the test
+    function call to so it is lazily defined. This avoids problems
+    running tests
+    on systems without GTK+ installed.
+
+ tests/test_overrides_gtk.py | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+commit 45d45e7c2704d68a3008f739e501fa332d326b8b
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Mar 3 04:45:59 2014 -0800
+
+    tests: Conditionalize usage of GTK+ in tests_generictreemodel
+
+    This allows running make check without GTK+ installed.
+
+ tests/test_generictreemodel.py | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+commit 038563ed620e0d966e385a1779455d9b0e148c41
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Mar 3 04:39:35 2014 -0800
+
+    tests: Conditionalize usage of regress typelib in test_properties
+
+    Unconditional usage of regress breaks tests when PyGObject is
+    built without
+    cairo.
+
+ tests/test_properties.py | 27 +++++++++++++++++----------
+ 1 file changed, 17 insertions(+), 10 deletions(-)
+
+commit 1fa93ddc51b2d223d772aee7930fc96c0ced0e00
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Mar 3 02:44:12 2014 -0800
+
+    configure.ac: Use -std=c90 and error on declaration-after-statement
+
+    Replace gcc option of -std=c9x with c90 and add
+    -Werror=declaration-after-statement
+    This ensures we keep compatibility with msvc builds.
+
+ configure.ac | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+commit cee414ab5725c51d79a2c6aa1e8760e9fd754545
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Mar 3 02:38:30 2014 -0800
+
+    Use g_snprintf instead of snprintf
+
+    Use g_snprintf for consistency with the rest of gobjectmodule.c
+
+ gi/gobjectmodule.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit b016ae6793839b2a6a00a69d00de30937bc611be
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Thu Feb 27 04:27:41 2014 -0800
+
+    Use C style comments
+
+    Update various locations which use C99 single line comments to
+    conform to
+    C90 style comments. Found with: make CFLAGS="-std=C90"
+
+ gi/gimodule.c      | 2 +-
+ gi/pygi-array.c    | 3 ++-
+ gi/pygi-property.c | 2 +-
+ gi/pygtype.c       | 2 +-
+ 4 files changed, 5 insertions(+), 4 deletions(-)
+
+commit df7cba1495c167f1019dec7f4398dc5de62a5937
+Author: Chun-wei Fan <fanchunwei@src.gnome.org>
+Date:   Tue Feb 25 14:38:41 2014 +0800
+
+    Fix Build on Visual Studio
+
+    Some items from pygi-enum-marshal.c were moved to pygi-basictype.c,
+    which
+    included the use of the NAN and INFINITY macros/constants, so the
+    definitions for those need to be moved to pygi-basictype.c as well.
+    Also
+    avoid defining a variable in the middle of the block.
+
+    https://bugzilla.gnome.org/show_bug.cgi?id=725122
+
+ gi/pygi-basictype.c    | 16 ++++++++++++++++
+ gi/pygi-cache.c        |  3 ++-
+ gi/pygi-enum-marshal.c | 16 ----------------
+ 3 files changed, 18 insertions(+), 17 deletions(-)
+
+commit bb5550bc85ac0ff60ea39912416e347f27853fb4
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Feb 17 17:22:40 2014 -0800
+
+    Update release steps to be more explicit in regards to NEWS
+
+    Add an explicit step to commit the NEWS changes and push prior
+    tagging.
+
+ HACKING | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+commit c6ac95286bce858f1925a9d6173a91866d7e9f88
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Feb 17 17:18:10 2014 -0800
+
+    configure.ac: post release version bump to 3.11.91
+
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+commit f87e341c5528d066371d4ec493956db28dd0bafa
+Author: Simon Feltman <sfeltman@src.gnome.org>
+Date:   Mon Feb 17 17:08:13 2014 -0800
+
+    release 3.11.90
+
+ NEWS | 4 ++++
+ 1 file changed, 4 insertions(+)
+
 commit 9b345b153e86ca6c9b7290cf2ad3b38f6ad9d0e5
 Author: Simon Feltman <sfeltman@src.gnome.org>
 Date:   Wed Feb 12 10:28:35 2014 -0800
index ea0b4ba..208ed13 100644 (file)
@@ -130,7 +130,7 @@ release-news:
 
        @echo -e "\n\n\nFor blogging, you can copy&paste this HTML formatted news:"
        @echo "-------------- 8< -------------"
-       @last=`head -n1 NEWS | cut -f1 -d' '`; \
+       @last=`head -n1 $(top_srcdir)/NEWS | cut -f1 -d' '`; \
         echo "<ul>"; \
        for commit in `git rev-list $$last..`; do \
           data=`git log --format="format:%s%n%an%n%b" $$commit^..$$commit`; \
index 7ba43dd..4cf5c4e 100644 (file)
@@ -1094,7 +1094,7 @@ release-news:
 
        @echo -e "\n\n\nFor blogging, you can copy&paste this HTML formatted news:"
        @echo "-------------- 8< -------------"
-       @last=`head -n1 NEWS | cut -f1 -d' '`; \
+       @last=`head -n1 $(top_srcdir)/NEWS | cut -f1 -d' '`; \
         echo "<ul>"; \
        for commit in `git rev-list $$last..`; do \
           data=`git log --format="format:%s%n%an%n%b" $$commit^..$$commit`; \
diff --git a/NEWS b/NEWS
index 45cbb0c..df04403 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+3.11.91 03-Mar-2014
+        - Use ffi_call directly instead of g_callable_info_invoke
+          (Simon Feltman) (#723642)
+        - configure.ac: Use -std=c90 and error on declaration-after-statement
+          (Simon Feltman)
+        - Fix Build on Visual Studio (Chun-wei Fan) (#725122)
+
 3.11.90 17-Feb-2014
         - Use GObject type checking for instance arguments (Simon Feltman) (#724009)
         - configure.ac: post release version bump to 3.11.90 (Simon Feltman)
index 1899a6a..ae9e0b7 100644 (file)
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: PyGObject
-Version: 3.11.90
+Version: 3.11.91
 Summary: Python bindings for GObject
 Home-page: http://www.pygtk.org/
 Author: James Henstridge
@@ -8,7 +8,7 @@ Author-email: james@daa.com.au
 Maintainer: Johan Dahlin
 Maintainer-email: johan@gnome.org
 License: GNU LGPL
-Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.11/pygobject-3.11.90.tar.gz
+Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.11/pygobject-3.11.91.tar.gz
 Description: Python bindings for GLib and GObject
 Platform: POSIX, Windows
 Classifier: Development Status :: 5 - Production/Stable
index ee6b1df..f4ba831 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for pygobject 3.11.90.
+# Generated by GNU Autoconf 2.69 for pygobject 3.11.91.
 #
 # Report bugs to <http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject>.
 #
@@ -591,8 +591,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='pygobject'
 PACKAGE_TARNAME='pygobject'
-PACKAGE_VERSION='3.11.90'
-PACKAGE_STRING='pygobject 3.11.90'
+PACKAGE_VERSION='3.11.91'
+PACKAGE_STRING='pygobject 3.11.91'
 PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject'
 PACKAGE_URL='https://live.gnome.org/PyGObject/'
 
@@ -1398,7 +1398,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures pygobject 3.11.90 to adapt to many kinds of systems.
+\`configure' configures pygobject 3.11.91 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1468,7 +1468,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of pygobject 3.11.90:";;
+     short | recursive ) echo "Configuration of pygobject 3.11.91:";;
    esac
   cat <<\_ACEOF
 
@@ -1605,7 +1605,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-pygobject configure 3.11.90
+pygobject configure 3.11.91
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1883,7 +1883,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by pygobject $as_me 3.11.90, which was
+It was created by pygobject $as_me 3.11.91, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2247,9 +2247,9 @@ $as_echo "#define PYGOBJECT_MINOR_VERSION 11" >>confdefs.h
 PYGOBJECT_MINOR_VERSION=11
 
 
-$as_echo "#define PYGOBJECT_MICRO_VERSION 90" >>confdefs.h
+$as_echo "#define PYGOBJECT_MICRO_VERSION 91" >>confdefs.h
 
-PYGOBJECT_MICRO_VERSION=90
+PYGOBJECT_MICRO_VERSION=91
 
 
 ac_config_headers="$ac_config_headers config.h"
@@ -2760,7 +2760,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='pygobject'
- VERSION='3.11.90'
+ VERSION='3.11.91'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -14694,19 +14694,52 @@ $as_echo "$jh_has_option" >&6; }
   ;;
 esac
 
+case " $CFLAGS " in
+*[\    \ ]-Werror=declaration-after-statement[\        \ ]*)
+  ;;
+*)
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -Werror=declaration-after-statement"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -Werror=declaration-after-statement" >&5
+$as_echo_n "checking whether $CC understands -Werror=declaration-after-statement... " >&6; }
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  jh_has_option=yes
+else
+  jh_has_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $jh_has_option" >&5
+$as_echo "$jh_has_option" >&6; }
+  if test $jh_has_option = no; then
+    CFLAGS="$save_CFLAGS"
+  fi
+  ;;
+esac
+
   case $host_os in
   solaris*)
     ;;
   *)
 
 case " $CFLAGS " in
-*[\    \ ]-std=c9x[\   \ ]*)
+*[\    \ ]-std=c90[\   \ ]*)
   ;;
 *)
   save_CFLAGS="$CFLAGS"
-  CFLAGS="$CFLAGS -std=c9x"
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -std=c9x" >&5
-$as_echo_n "checking whether $CC understands -std=c9x... " >&6; }
+  CFLAGS="$CFLAGS -std=c90"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -std=c90" >&5
+$as_echo_n "checking whether $CC understands -std=c90... " >&6; }
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -15291,7 +15324,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by pygobject $as_me 3.11.90, which was
+This file was extended by pygobject $as_me 3.11.91, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -15358,7 +15391,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-pygobject config.status 3.11.90
+pygobject config.status 3.11.91
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index a4d4683..f700bbe 100644 (file)
@@ -18,7 +18,7 @@ m4_define(python3_min_ver, 3.1)
 dnl the pygobject version number
 m4_define(pygobject_major_version, 3)
 m4_define(pygobject_minor_version, 11)
-m4_define(pygobject_micro_version, 90)
+m4_define(pygobject_micro_version, 91)
 m4_define(pygobject_version, pygobject_major_version.pygobject_minor_version.pygobject_micro_version)
 
 dnl versions of packages we require ...
@@ -254,12 +254,13 @@ if test "x$GCC" = "xyes"; then
   JH_ADD_CFLAG([-Wall])
   JH_ADD_CFLAG([-Werror=unused-variable])
   JH_ADD_CFLAG([-fno-strict-aliasing])
+  JH_ADD_CFLAG([-Werror=declaration-after-statement])
 
   case $host_os in
   solaris*)
     ;;
   *)
-    JH_ADD_CFLAG([-std=c9x])
+    JH_ADD_CFLAG([-std=c90])
     ;;
   esac
 
index ef3e205..25fc3d6 100644 (file)
@@ -274,7 +274,7 @@ _wrap_pyg_flags_register_new_gtype_and_add (PyObject *self,
 static void
 initialize_interface (GTypeInterface *iface, PyTypeObject *pytype)
 {
-    // pygobject prints a warning if interface_init is NULL
+    /* pygobject prints a warning if interface_init is NULL */
 }
 
 static PyObject *
index 82d52a1..b156190 100644 (file)
@@ -934,7 +934,7 @@ get_type_name_for_class(PyTypeObject *class)
     while (name_serial < 1000)
     {
        g_free(type_name);
-       snprintf(name_serial_str, 16, "-v%i", name_serial);
+       g_snprintf(name_serial_str, 16, "-v%i", name_serial);
        module = PyObject_GetAttrString((PyObject *)class, "__module__");
        if (module && PYGLIB_PyUnicode_Check(module)) {
            type_name = g_strconcat(PYGLIB_PyUnicode_AsString(module), ".",
index 937c6b3..c17ace0 100644 (file)
@@ -370,24 +370,10 @@ array_success:
         PyGIArgCache *child_cache =
             _pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index);
 
-        if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) {
-            gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer;
-            /* if we are not setup yet just set the in arg */
-            if (len_arg == NULL) {
-                if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
-                                                  length,
-                                                  child_cache->type_tag)) {
-                    goto err;
-                }
-            } else {
-                *len_arg = length;
-            }
-        } else {
-            if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index],
-                                              length,
-                                              child_cache->type_tag)) {
-                goto err;
-            }
+        if (!gi_argument_from_py_ssize_t (&state->arg_values[child_cache->c_arg_index],
+                                          length,
+                                          child_cache->type_tag)) {
+            goto err;
         }
     }
 
@@ -528,7 +514,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
                 len = g_strv_length ((gchar **)arg->v_pointer);
             }
         } else {
-            GIArgument *len_arg = state->args[array_cache->len_arg_index];
+            GIArgument *len_arg = &state->arg_values[array_cache->len_arg_index];
             PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache,
                                                                     array_cache->len_arg_index);
 
@@ -600,7 +586,8 @@ _pygi_marshal_to_py_array (PyGIInvokeState   *state,
                 } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
                     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache;
 
-                    // FIXME: This probably doesn't work with boxed types or gvalues. See fx. _pygi_marshal_from_py_array()
+                    /* FIXME: This probably doesn't work with boxed types or gvalues.
+                     * See fx. _pygi_marshal_from_py_array() */
                     switch (g_base_info_get_type (iface_cache->interface_info)) {
                         case GI_INFO_TYPE_STRUCT:
                             if (arg_cache->transfer == GI_TRANSFER_EVERYTHING &&
@@ -683,7 +670,7 @@ _wrap_c_array (PyGIInvokeState   *state,
     } else if (array_cache->is_zero_terminated) {
         len = g_strv_length ((gchar **)data);
     } else if (array_cache->len_arg_index >= 0) {
-        GIArgument *len_arg = state->args[array_cache->len_arg_index];
+        GIArgument *len_arg = &state->arg_values[array_cache->len_arg_index];
         len = len_arg->v_long;
     }
 
index 6fbe929..c9606a9 100644 (file)
 #include "pygi-argument.h"
 #include "pygi-private.h"
 
+#ifdef G_OS_WIN32
+#ifdef _MSC_VER
+#include <math.h>
+
+#ifndef NAN
+static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
+#define NAN (*(const float *) __nan)
+#endif
+
+#ifndef INFINITY
+#define INFINITY HUGE_VAL
+#endif
+
+#endif
+#endif
+
 
 /*
  * From Python Marshaling
index 8055c15..c29733f 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <girepository.h>
 
+#include "pyglib.h"
 #include "pygi-info.h"
 #include "pygi-cache.h"
 #include "pygi-marshal-cleanup.h"
@@ -132,6 +133,7 @@ pygi_callable_cache_free (PyGICallableCache *cache)
     if (cache->return_cache != NULL)
         pygi_arg_cache_free (cache->return_cache);
 
+    g_function_invoker_destroy (&cache->invoker);
     g_slice_free (PyGICallableCache, cache);
 }
 
@@ -475,6 +477,7 @@ _args_cache_generate (GICallableInfo *callable_info,
     GITransfer return_transfer;
     PyGIArgCache *return_cache;
     PyGIDirection return_direction;
+       gssize last_explicit_arg_index;
 
     /* Return arguments are always considered out */
     return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT);
@@ -529,7 +532,6 @@ _args_cache_generate (GICallableInfo *callable_info,
         _pygi_callable_cache_set_arg (callable_cache, arg_index, instance_cache);
 
         arg_index++;
-        callable_cache->n_from_py_args++;
         callable_cache->n_py_args++;
     }
 
@@ -551,8 +553,6 @@ _args_cache_generate (GICallableInfo *callable_info,
             arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE;
             arg_cache->c_arg_index = i;
 
-            callable_cache->n_from_py_args++;
-
         } else {
             GITypeInfo *type_info;
 
@@ -566,16 +566,15 @@ _args_cache_generate (GICallableInfo *callable_info,
              */
             arg_cache = _pygi_callable_cache_get_arg (callable_cache, arg_index);
             if (arg_cache != NULL) {
+                /* ensure c_arg_index always aligns with callable_cache->args_cache
+                 * and all of the various PyGIInvokeState arrays. */
+                arg_cache->c_arg_index = arg_index;
+
                 if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) {
                     arg_cache->py_arg_index = callable_cache->n_py_args;
                     callable_cache->n_py_args++;
                 }
 
-                if (direction & PYGI_DIRECTION_FROM_PYTHON) {
-                    arg_cache->c_arg_index = callable_cache->n_from_py_args;
-                    callable_cache->n_from_py_args++;
-                }
-
                 if (direction & PYGI_DIRECTION_TO_PYTHON) {
                     callable_cache->n_to_py_args++;
                 }
@@ -589,7 +588,6 @@ _args_cache_generate (GICallableInfo *callable_info,
 
                 if (direction & PYGI_DIRECTION_FROM_PYTHON) {
                     py_arg_index = callable_cache->n_py_args;
-                    callable_cache->n_from_py_args++;
                     callable_cache->n_py_args++;
                 }
 
@@ -637,7 +635,7 @@ _args_cache_generate (GICallableInfo *callable_info,
     callable_cache->n_py_required_args = 0;
     callable_cache->user_data_varargs_index = -1;
 
-    gssize last_explicit_arg_index = -1;
+    last_explicit_arg_index = -1;
 
     /* Reverse loop through all the arguments to setup arg_name_list/hash
      * and find the number of required arguments */
@@ -685,8 +683,47 @@ _args_cache_generate (GICallableInfo *callable_info,
     return TRUE;
 }
 
+static gboolean
+_setup_invoker (GICallableInfo *callable_info,
+                GIInfoType info_type,
+                GIFunctionInvoker *invoker,
+                GCallback function_ptr)
+{
+    GError *error = NULL;
+
+    if (info_type == GI_INFO_TYPE_FUNCTION) {
+        if (g_function_info_prep_invoker ((GIFunctionInfo *)callable_info,
+                                          invoker,
+                                          &error)) {
+            return TRUE;
+        }
+        if (!pyglib_error_check (&error)) {
+            PyErr_Format (PyExc_RuntimeError,
+                          "unknown error creating invoker for %s",
+                          g_base_info_get_name ((GIBaseInfo *)callable_info));
+        }
+        return FALSE;
+
+    } else {
+        if (!g_function_invoker_new_for_address (function_ptr,
+                                                 (GIFunctionInfo *)callable_info,
+                                                 invoker,
+                                                 &error)) {
+            if (!pyglib_error_check (&error)) {
+                PyErr_Format (PyExc_RuntimeError,
+                              "unknown error creating invoker for %s",
+                              g_base_info_get_name ((GIBaseInfo *)callable_info));
+            }
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
 PyGICallableCache *
-pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback)
+pygi_callable_cache_new (GICallableInfo *callable_info,
+                         GCallback function_ptr,
+                         gboolean is_ccallback)
 {
     gint n_args;
     PyGICallableCache *cache;
@@ -698,6 +735,7 @@ pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback)
         return NULL;
 
     cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info);
+    cache->throws = g_callable_info_can_throw_gerror ((GIBaseInfo *)callable_info);
 
     if (g_base_info_is_deprecated (callable_info)) {
         const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated");
@@ -748,6 +786,10 @@ pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback)
     if (!_args_cache_generate (callable_info, cache))
         goto err;
 
+    if (!_setup_invoker (callable_info, type, &cache->invoker, function_ptr)) {
+        goto err;
+    }
+
     return cache;
 err:
     pygi_callable_cache_free (cache);
index 5521605..407e38c 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <Python.h>
 #include <girepository.h>
+#include <girffi.h>
 
 #include "pygi-invoke-state-struct.h"
 
@@ -167,14 +168,11 @@ struct _PyGICallableCache
     GSList *to_py_args;
     GSList *arg_name_list; /* for keyword arg matching */
     GHashTable *arg_name_hash;
+    gboolean throws;
 
     /* Index of user_data arg that can eat variable args passed to a callable. */
     gssize user_data_varargs_index;
 
-    /* Number of in args passed to g_function_info_invoke.
-     * This is used for the length of PyGIInvokeState.in_args */
-    gssize n_from_py_args;
-
     /* Number of out args passed to g_function_info_invoke.
      * This is used for the length of PyGIInvokeState.out_values */
     gssize n_to_py_args;
@@ -191,6 +189,9 @@ struct _PyGICallableCache
     /* Minimum number of args required to call the callable from Python.
      * This count does not include args with defaults. */
     gssize n_py_required_args;
+
+    /* An invoker with ffi_cif already setup */
+    GIFunctionInvoker invoker;
 };
 
 gboolean
@@ -243,6 +244,7 @@ pygi_callable_cache_free (PyGICallableCache *cache);
 
 PyGICallableCache *
 pygi_callable_cache_new  (GICallableInfo *callable_info,
+                          GCallback function_ptr,
                           gboolean is_ccallback);
 
 #define _pygi_callable_cache_args_len(cache) ((cache)->args_cache)->len
index 01e109b..2a6c520 100644 (file)
@@ -34,7 +34,7 @@ _ccallback_call(PyGICCallback *self, PyObject *args, PyObject *kwargs)
     PyObject *result;
 
     if (self->cache == NULL) {
-        self->cache = pygi_callable_cache_new (self->info, TRUE);
+        self->cache = pygi_callable_cache_new (self->info, self->callback, TRUE);
         if (self->cache == NULL)
             return NULL;
     }
@@ -43,7 +43,6 @@ _ccallback_call(PyGICCallback *self, PyObject *args, PyObject *kwargs)
                                          args,
                                          kwargs,
                                          self->cache,
-                                         self->callback,
                                          self->user_data);
     return result;
 }
index a30363f..b803541 100644 (file)
@@ -800,7 +800,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
      * The return trip to python will marshal this back and pull the python user data out.
      */
     if (user_data_cache != NULL) {
-        state->in_args[user_data_cache->c_arg_index].v_pointer = closure;
+        state->arg_values[user_data_cache->c_arg_index].v_pointer = closure;
     }
 
     /* Setup a GDestroyNotify callback if this method supports it along with
@@ -817,7 +817,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
     if (destroy_cache) {
         if (user_data_cache != NULL) {
             PyGICClosure *destroy_notify = _pygi_destroy_notify_create ();
-            state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
+            state->arg_values[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure;
         } else {
             gchar *msg = g_strdup_printf("Callables passed to %s will leak references because "
                                          "the method does not support a user_data argument. "
@@ -829,7 +829,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
                 return FALSE;
             }
             g_free(msg);
-            state->in_args[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy;
+            state->arg_values[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy;
         }
     }
 
index dec5924..32ca9dc 100644 (file)
 #include "pygi-enum-marshal.h"
 #include "pygi-private.h"
 
-#ifdef _WIN32
-#ifdef _MSC_VER
-#include <math.h>
-
-#ifndef NAN
-static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
-#define NAN (*(const float *) __nan)
-#endif
-
-#ifndef INFINITY
-#define INFINITY HUGE_VAL
-#endif
-
-#endif
-#endif
-
 static gboolean
 gi_argument_from_c_long (GIArgument *arg_out,
                          long        c_long_in,
index 139b878..174f473 100644 (file)
@@ -11,39 +11,49 @@ typedef struct _PyGIInvokeState
 {
     PyObject *py_in_args;
     gssize n_py_in_args;
-    gssize current_arg;
 
     GType implementor_gtype;
 
+    /* Number of arguments the ffi wrapped C function takes. Used as the exact
+     * count for argument related arrays held in this struct.
+     */
+    gssize n_args;
+
+    /* List of arguments passed to ffi. Elements can point directly to values held in
+     * arg_values for "in/from Python" or indirectly via arg_pointers for
+     * "out/inout/to Python". In the latter case, the arg_pointers[x]->v_pointer
+     * member points to memory for the value storage.
+     */
     GIArgument **args;
-    GIArgument *in_args;
+
+    /* Holds memory for the C value of arguments marshaled "to" or "from" Python. */
+    GIArgument *arg_values;
+
+    /* Holds pointers to values in arg_values or a caller allocated chunk of
+     * memory via arg_pointers[x].v_pointer.
+     */
+    GIArgument *arg_pointers;
 
     /* Array of pointers allocated to the same length as args which holds from_py
      * marshaler cleanup data.
      */
     gpointer *args_cleanup_data;
 
-    /* Out args and out values
-     * In order to pass a parameter and get something back out in C
-     * we need to pass a pointer to the value, e.g.
-     *    int *out_integer;
-     *
-     * so while out_args == out_integer, out_value == *out_integer
-     * or in other words out_args = &out_values
-     *
-     * We do all of our processing on out_values but we pass out_args to 
-     * the actual function.
-     */
-    GIArgument *out_args;
-    GIArgument *out_values;
-
+    /* Memory to receive the result of the C ffi function call. */
     GIArgument return_arg;
 
+    /* A GError exception which is indirectly bound into the last position of
+     * the "args" array if the callable caches "throws" member is set.
+     */
     GError *error;
 
     gboolean failed;
 
     gpointer user_data;
+
+    /* Function pointer to call with ffi. */
+    gpointer function_ptr;
+
 } PyGIInvokeState;
 
 G_END_DECLS
index 1d89912..3bb4dc6 100644 (file)
 static inline gboolean
 _invoke_callable (PyGIInvokeState *state,
                   PyGICallableCache *cache,
-                  GICallableInfo *callable_info,
-                  GCallback function_ptr)
+                  GICallableInfo *callable_info)
 {
-    GError *error;
-    gint retval;
-
-    error = NULL;
+    GIFFIReturnValue ffi_return_value = {0};
 
     Py_BEGIN_ALLOW_THREADS;
 
-    /* FIXME: use this for now but we can streamline the calls */
-    if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC)
-        retval = g_vfunc_info_invoke ( callable_info,
-                                       state->implementor_gtype,
-                                       state->in_args,
-                                       cache->n_from_py_args,
-                                       state->out_args,
-                                       cache->n_to_py_args,
-                                      &state->return_arg,
-                                      &error);
-    else if (g_base_info_get_type (callable_info) == GI_INFO_TYPE_CALLBACK)
-        retval = g_callable_info_invoke (callable_info,
-                                         function_ptr,
-                                         state->in_args,
-                                         cache->n_from_py_args,
-                                         state->out_args,
-                                         cache->n_to_py_args,
-                                         &state->return_arg,
-                                         FALSE,
-                                         FALSE,
-                                         &error);
-    else
-        retval = g_function_info_invoke ( callable_info,
-                                          state->in_args,
-                                          cache->n_from_py_args,
-                                          state->out_args,
-                                          cache->n_to_py_args,
-                                         &state->return_arg,
-                                         &error);
-    Py_END_ALLOW_THREADS;
-
-    if (!retval) {
-        g_assert (error != NULL);
-        pyglib_error_check (&error);
-
-        /* It is unclear if the error occured before or after the C
-         * function was invoked so for now assume success
-         * We eventually should marshal directly to FFI so we no longer
-         * have to use the reference implementation
-         */
-        pygi_marshal_cleanup_args_from_py_marshal_success (state, cache);
+        ffi_call (&cache->invoker.cif,
+                  state->function_ptr,
+                  (void *)&ffi_return_value,
+                  (void **)state->args);
 
-        return FALSE;
-    }
+    Py_END_ALLOW_THREADS;
 
+    /* If the callable throws, the address of state->error will be bound into
+     * the state->args as the last value. When the callee sets an error using
+     * the state->args passed, it will have the side effect of setting
+     * state->error allowing for easy checking here.
+     */
     if (state->error != NULL) {
         if (pyglib_error_check (&(state->error))) {
             /* even though we errored out, the call itself was successful,
@@ -93,6 +56,12 @@ _invoke_callable (PyGIInvokeState *state,
         }
     }
 
+    if (cache->return_cache) {
+        gi_type_info_extract_ffi_return_value (cache->return_cache->type_info,
+                                               &ffi_return_value,
+                                               &state->return_arg);
+    }
+
     return TRUE;
 }
 
@@ -280,13 +249,24 @@ _py_args_combine_and_check_length (PyGICallableCache *cache,
 }
 
 static inline gboolean
-_invoke_state_init_from_callable_cache (PyGIInvokeState *state,
+_invoke_state_init_from_callable_cache (GIBaseInfo *info,
+                                        PyGIInvokeState *state,
                                         PyGICallableCache *cache,
                                         PyObject *py_args,
                                         PyObject *kwargs)
 {
     PyObject *combined_args = NULL;
     state->implementor_gtype = 0;
+    state->n_args = _pygi_callable_cache_args_len (cache);
+
+    if (cache->throws) {
+        state->n_args++;
+    }
+
+    /* Copy the function pointer to the state for the normal case. For vfuncs,
+     * this will be filled out based on the implementor_gtype calculated below.
+     */
+    state->function_ptr = cache->invoker.native_address;
 
     /* TODO: We don't use the class parameter sent in by  the structure
      * so we remove it from the py_args tuple but we can keep it 
@@ -308,6 +288,8 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state,
         }
     } else if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) {
         PyObject *py_gtype;
+        GError *error = NULL;
+
         py_gtype = PyTuple_GetItem (py_args, 0);
         if (py_gtype == NULL) {
             PyErr_SetString (PyExc_TypeError,
@@ -319,6 +301,18 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state,
 
         if (state->implementor_gtype == 0)
             return FALSE;
+
+        /* vfunc addresses are pulled into the state at call time and cannot be
+         * cached because the call site can specify a different portion of the
+         * class hierarchy. e.g. Object.do_func vs. SubObject.do_func might
+         * retrieve a different vfunc address but GI gives us the same vfunc info.
+         */
+        state->function_ptr = g_vfunc_info_get_address ((GIVFuncInfo *)info,
+                                                        state->implementor_gtype,
+                                                        &error);
+        if (pyglib_error_check (&error)) {
+            return FALSE;
+        }
     }
 
     if  (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR ||
@@ -344,68 +338,65 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state,
     }
     state->n_py_in_args = PyTuple_Size (state->py_in_args);
 
-    state->args = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (GIArgument *));
-    if (state->args == NULL && _pygi_callable_cache_args_len (cache) != 0) {
+    state->args = g_slice_alloc0 (state->n_args * sizeof (GIArgument *));
+    if (state->args == NULL && state->n_args != 0) {
         PyErr_NoMemory();
         return FALSE;
     }
 
-    state->args_cleanup_data = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (gpointer));
-    if (state->args_cleanup_data == NULL && _pygi_callable_cache_args_len (cache) != 0) {
+    state->args_cleanup_data = g_slice_alloc0 (state->n_args * sizeof (gpointer));
+    if (state->args_cleanup_data == NULL && state->n_args != 0) {
         PyErr_NoMemory();
         return FALSE;
     }
 
-    state->in_args = g_slice_alloc0 (cache->n_from_py_args * sizeof(GIArgument));
-    if (state->in_args == NULL && cache->n_from_py_args != 0) {
+    state->arg_values = g_slice_alloc0 (state->n_args * sizeof(GIArgument));
+    if (state->arg_values == NULL && state->n_args != 0) {
         PyErr_NoMemory ();
         return FALSE;
     }
 
-    state->out_values = g_slice_alloc0 (cache->n_to_py_args * sizeof(GIArgument));
-    if (state->out_values == NULL && cache->n_to_py_args != 0) {
-        PyErr_NoMemory ();
-        return FALSE;
-    }
-
-    state->out_args = g_slice_alloc0 (cache->n_to_py_args * sizeof(GIArgument));
-    if (state->out_args == NULL && cache->n_to_py_args != 0) {
+    state->arg_pointers = g_slice_alloc0 (state->n_args * sizeof(GIArgument));
+    if (state->arg_pointers == NULL && state->n_args != 0) {
         PyErr_NoMemory ();
         return FALSE;
     }
 
     state->error = NULL;
 
+    if (cache->throws) {
+        gssize error_index = state->n_args - 1;
+        /* The ffi argument for GError needs to be a triple pointer. */
+        state->arg_pointers[error_index].v_pointer = &state->error;
+        state->args[error_index] = &(state->arg_pointers[error_index]);
+    }
+
     return TRUE;
 }
 
 static inline void
 _invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache)
 {
-    g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(GIArgument *), state->args);
-    g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(gpointer), state->args_cleanup_data);
-    g_slice_free1 (cache->n_from_py_args * sizeof(GIArgument), state->in_args);
-    g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_args);
-    g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_values);
+    g_slice_free1 (state->n_args * sizeof(GIArgument *), state->args);
+    g_slice_free1 (state->n_args * sizeof(gpointer), state->args_cleanup_data);
+    g_slice_free1 (state->n_args * sizeof(GIArgument), state->arg_values);
+    g_slice_free1 (state->n_args * sizeof(GIArgument), state->arg_pointers);
 
     Py_XDECREF (state->py_in_args);
 }
 
-static gboolean _caller_alloc (PyGIInvokeState *state,
-                               PyGIArgCache *arg_cache,
-                               gssize arg_count,
-                               gssize out_count)
+static gboolean
+_caller_alloc (PyGIArgCache *arg_cache, GIArgument *arg)
 {
     if (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) {
         PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
 
-        state->out_args[out_count].v_pointer = NULL;
-        state->args[arg_count] = &state->out_args[out_count];
+        arg->v_pointer = NULL;
         if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
-            state->args[arg_count]->v_pointer =
+            arg->v_pointer =
                 _pygi_boxed_alloc (iface_cache->interface_info, NULL);
         } else if (iface_cache->g_type == G_TYPE_VALUE) {
-            state->args[arg_count]->v_pointer = g_slice_new0 (GValue);
+            arg->v_pointer = g_slice_new0 (GValue);
         } else if (iface_cache->is_foreign) {
             PyObject *foreign_struct =
                 pygi_struct_foreign_convert_from_g_argument (
@@ -415,34 +406,59 @@ static gboolean _caller_alloc (PyGIInvokeState *state,
                 pygi_struct_foreign_convert_to_g_argument (foreign_struct,
                                                            iface_cache->interface_info,
                                                            GI_TRANSFER_EVERYTHING,
-                                                           state->args[arg_count]);
+                                                           arg);
         } else {
                 gssize size = g_struct_info_get_size(
                     (GIStructInfo *)iface_cache->interface_info);
-                state->args[arg_count]->v_pointer = g_malloc0 (size);
+                arg->v_pointer = g_malloc0 (size);
         }
     } else if (arg_cache->type_tag == GI_TYPE_TAG_ARRAY) {
         PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
 
-        state->out_args[out_count].v_pointer = g_array_new (TRUE, TRUE, array_cache->item_size);
-        state->args[arg_count] = &state->out_args[out_count];
+        arg->v_pointer = g_array_new (TRUE, TRUE, array_cache->item_size);
     } else {
         return FALSE;
     }
 
-    if (state->args[arg_count]->v_pointer == NULL)
+    if (arg->v_pointer == NULL)
         return FALSE;
 
 
     return TRUE;
 }
 
+/* _invoke_marshal_in_args:
+ *
+ * Fills out the state struct argument lists. arg_values will always hold
+ * actual values marshaled either to or from Python and C. arg_pointers will
+ * hold pointers (via v_pointer) to auxilary value storage. This will normally
+ * point to values stored in arg_values. In the case of caller allocated
+ * out args, arg_pointers[x].v_pointer will point to newly allocated memory.
+ * arg_pointers inserts a level of pointer indirection between arg_values
+ * and the argument list ffi receives when dealing with non-caller allocated
+ * out arguments.
+ *
+ * For example:
+ * [[
+ *  void callee (int *i, int j) { *i = 50 - j; }
+ *  void caller () {
+ *    int i = 0;
+ *    callee (&i, 8);
+ *  }
+ *
+ *  args[0] == &arg_pointers[0];
+ *  arg_pointers[0].v_pointer == &arg_values[0];
+ *  arg_values[0].v_int == 42;
+ *
+ *  args[1] == &arg_values[1];
+ *  arg_values[1].v_int == 8;
+ * ]]
+ *
+ */
 static inline gboolean
 _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
 {
-    gssize i, in_count, out_count;
-    in_count = 0;
-    out_count = 0;
+    gssize i;
 
     if (state->n_py_in_args > cache->n_py_args) {
         PyErr_Format (PyExc_TypeError,
@@ -454,14 +470,14 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
     }
 
     for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
-        GIArgument *c_arg;
+        GIArgument *c_arg = &state->arg_values[i];
         PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i);
         PyObject *py_arg = NULL;
 
         switch (arg_cache->direction) {
             case PYGI_DIRECTION_FROM_PYTHON:
-                state->args[i] = &(state->in_args[in_count]);
-                in_count++;
+                /* The ffi argument points directly at memory in arg_values. */
+                state->args[i] = c_arg;
 
                 if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CLOSURE) {
                     state->args[i]->v_pointer = state->user_data;
@@ -491,13 +507,6 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
 
                 break;
             case PYGI_DIRECTION_BIDIRECTIONAL:
-                /* this will be filled in if it is an child value */
-                if (state->in_args[in_count].v_pointer != NULL)
-                    state->out_values[out_count] = state->in_args[in_count];
-
-                state->in_args[in_count].v_pointer = &state->out_values[out_count];
-                in_count++;
-
                 if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) {
                     if (arg_cache->py_arg_index >= state->n_py_in_args) {
                         PyErr_Format (PyExc_TypeError,
@@ -515,9 +524,27 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
                         PyTuple_GET_ITEM (state->py_in_args,
                                           arg_cache->py_arg_index);
                 }
+                /* Fall through */
+
             case PYGI_DIRECTION_TO_PYTHON:
+                /* arg_pointers always stores a pointer to the data to be marshaled "to python"
+                 * even in cases where arg_pointers is not being used as indirection between
+                 * ffi and arg_values. This gives a guarantee that out argument marshaling
+                 * (_invoke_marshal_out_args) can always rely on arg_pointers pointing to
+                 * the correct chunk of memory to marshal.
+                 */
+                state->arg_pointers[i].v_pointer = c_arg;
+
                 if (arg_cache->is_caller_allocates) {
-                    if (!_caller_alloc (state, arg_cache, i, out_count)) {
+                    /* In the case of caller allocated out args, we don't use
+                     * an extra level of indirection and state->args will point
+                     * directly at the data to be marshaled. However, as noted
+                     * above, arg_pointers will also point to this caller allocated
+                     * chunk of memory used by out argument marshaling.
+                     */
+                    state->args[i] = c_arg;
+
+                    if (!_caller_alloc (arg_cache, c_arg)) {
                         PyErr_Format (PyExc_TypeError,
                                       "Could not caller allocate argument %zd of callable %s",
                                       i, cache->name);
@@ -527,14 +554,14 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
                         return FALSE;
                     }
                 } else {
-                    state->out_args[out_count].v_pointer = &state->out_values[out_count];
-                    state->args[i] = &state->out_values[out_count];
+                    /* Non-caller allocated out args will use arg_pointers as an
+                     * extra level of indirection */
+                    state->args[i] = &state->arg_pointers[i];
                 }
-                out_count++;
+
                 break;
         }
 
-        c_arg = state->args[i];
         if (py_arg == _PyGIDefaultArgPlaceholder) {
             *c_arg = arg_cache->default_value;
         } else if (arg_cache->from_py_marshaller != NULL) {
@@ -642,7 +669,7 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
         py_out = arg_cache->to_py_marshaller (state,
                                               cache,
                                               arg_cache,
-                                              state->args[arg_cache->c_arg_index]);
+                                              state->arg_pointers[arg_cache->c_arg_index].v_pointer);
         if (py_out == NULL) {
             pygi_marshal_cleanup_args_to_py_parameter_fail (state,
                                                             cache,
@@ -665,7 +692,7 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
             PyObject *py_obj = arg_cache->to_py_marshaller (state,
                                                             cache,
                                                             arg_cache,
-                                                            state->args[arg_cache->c_arg_index]);
+                                                            state->arg_pointers[arg_cache->c_arg_index].v_pointer);
 
             if (py_obj == NULL) {
                 if (has_return)
@@ -688,12 +715,12 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
 PyObject *
 pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args,
                            PyObject *kwargs, PyGICallableCache *cache,
-                           GCallback function_ptr, gpointer user_data)
+                           gpointer user_data)
 {
     PyGIInvokeState state = { 0, };
     PyObject *ret = NULL;
 
-    if (!_invoke_state_init_from_callable_cache (&state, cache, py_args, kwargs))
+    if (!_invoke_state_init_from_callable_cache (info, &state, cache, py_args, kwargs))
         goto err;
 
     if (cache->function_type == PYGI_FUNCTION_TYPE_CCALLBACK)
@@ -702,7 +729,7 @@ pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args,
     if (!_invoke_marshal_in_args (&state, cache))
         goto err;
 
-    if (!_invoke_callable (&state, cache, info, function_ptr))
+    if (!_invoke_callable (&state, cache, info))
         goto err;
 
     ret = _invoke_marshal_out_args (&state, cache);
@@ -720,10 +747,10 @@ _wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
                               PyObject *kwargs)
 {
     if (self->cache == NULL) {
-        self->cache = pygi_callable_cache_new (self->info, FALSE);
+        self->cache = pygi_callable_cache_new (self->info, NULL, FALSE);
         if (self->cache == NULL)
             return NULL;
     }
 
-    return pygi_callable_info_invoke (self->info, py_args, kwargs, self->cache, NULL, NULL);
+    return pygi_callable_info_invoke (self->info, py_args, kwargs, self->cache, NULL);
 }
index 051bc8d..a481be3 100644 (file)
@@ -32,7 +32,7 @@ G_BEGIN_DECLS
 
 PyObject *pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args,
                                      PyObject *kwargs, PyGICallableCache *cache,
-                                     GCallback function_ptr, gpointer user_data);
+                                     gpointer user_data);
 PyObject *_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
                                         PyObject *kwargs);
 
index 3d82601..169e149 100644 (file)
@@ -136,7 +136,7 @@ pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState   *state,
     while (cache_item) {
         PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
         PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup;
-        gpointer data = state->args[arg_cache->c_arg_index]->v_pointer;
+        gpointer data = state->arg_values[arg_cache->c_arg_index].v_pointer;
 
         if (cleanup_func != NULL && data != NULL)
             cleanup_func (state,
@@ -168,7 +168,7 @@ pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState   *state,
     for (i = 0; i < _pygi_callable_cache_args_len (cache)  && i <= failed_arg_index; i++) {
         PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
         PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
-        gpointer data = state->args[i]->v_pointer;
+        gpointer data = state->arg_values[i].v_pointer;
         PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
                                              arg_cache->py_arg_index);
 
index 3f6d038..6f80506 100644 (file)
@@ -302,7 +302,7 @@ pygi_set_property_value_real (PyGObject *instance,
 
     g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
-    // FIXME: Lots of types still unhandled
+    /* FIXME: Lots of types still unhandled */
     type_tag = g_type_info_get_tag (type_info);
     switch (type_tag) {
         case GI_TYPE_TAG_INTERFACE:
index e1fb4e6..fb21282 100644 (file)
@@ -946,7 +946,7 @@ gclosure_from_pyfunc(PyGObject *object, PyObject *func)
             PyGClosure *pyclosure = l->data;
             int res = PyObject_RichCompareBool(pyclosure->callback, func, Py_EQ);
             if (res == -1) {
-                PyErr_Clear(); // Is there anything else to do?
+                PyErr_Clear(); /* Is there anything else to do? */
             } else if (res) {
                 return (GClosure*)pyclosure;
             }
index 9fa89ff..6ba71bc 100644 (file)
@@ -28,9 +28,15 @@ import unittest
 
 # pygobject
 from gi.repository import GObject
-from gi.repository import Gtk
-from pygtkcompat.generictreemodel import GenericTreeModel
-from pygtkcompat.generictreemodel import _get_user_data_as_pyobject
+
+try:
+    from gi.repository import Gtk
+    from pygtkcompat.generictreemodel import GenericTreeModel
+    from pygtkcompat.generictreemodel import _get_user_data_as_pyobject
+    has_gtk = True
+except ImportError:
+    GenericTreeModel = object
+    has_gtk = False
 
 
 class Node(object):
@@ -127,6 +133,7 @@ class TesterModel(GenericTreeModel):
             return child.parent()
 
 
+@unittest.skipUnless(has_gtk, 'Gtk not available')
 class TestReferences(unittest.TestCase):
     def setUp(self):
         pass
@@ -279,6 +286,7 @@ class TestReferences(unittest.TestCase):
             self.assertEqual(ref(), None)
 
 
+@unittest.skipUnless(has_gtk, 'Gtk not available')
 class TestIteration(unittest.TestCase):
     def test_iter_next_root(self):
         model = TesterModel()
@@ -306,6 +314,7 @@ class ErrorModel(GenericTreeModel):
     pass
 
 
+@unittest.skipUnless(has_gtk, 'Gtk not available')
 class ExceptHook(object):
     """
     Temporarily installs an exception hook in a context which
@@ -337,6 +346,7 @@ class ExceptHook(object):
             assert issubclass(got, expected), error_message
 
 
+@unittest.skipUnless(has_gtk, 'Gtk not available')
 class TestReturnsAfterError(unittest.TestCase):
     def setUp(self):
         self.model = ErrorModel()
index 210cf45..2a0fd90 100644 (file)
@@ -633,26 +633,26 @@ class TestGtk(unittest.TestCase):
 
 @unittest.skipUnless(Gtk, 'Gtk not available')
 class TestSignals(unittest.TestCase):
-    class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
-        __gsignals__ = {'size-allocate': 'override'}
+    def test_class_closure_override_with_aliased_type(self):
+        class WindowWithSizeAllocOverride(Gtk.ScrolledWindow):
+            __gsignals__ = {'size-allocate': 'override'}
 
-        def __init__(self):
-            Gtk.ScrolledWindow.__init__(self)
-            self._alloc_called = False
-            self._alloc_value = None
-            self._alloc_error = None
+            def __init__(self):
+                Gtk.ScrolledWindow.__init__(self)
+                self._alloc_called = False
+                self._alloc_value = None
+                self._alloc_error = None
 
-        def do_size_allocate(self, alloc):
-            self._alloc_called = True
-            self._alloc_value = alloc
+            def do_size_allocate(self, alloc):
+                self._alloc_called = True
+                self._alloc_value = alloc
 
-            try:
-                Gtk.ScrolledWindow.do_size_allocate(self, alloc)
-            except Exception as e:
-                self._alloc_error = e
+                try:
+                    Gtk.ScrolledWindow.do_size_allocate(self, alloc)
+                except Exception as e:
+                    self._alloc_error = e
 
-    def test_class_closure_override_with_aliased_type(self):
-        win = self.WindowWithSizeAllocOverride()
+        win = WindowWithSizeAllocOverride()
         rect = Gdk.Rectangle()
         rect.width = 100
         rect.height = 100
index d7ceb89..c0579f7 100644 (file)
@@ -21,10 +21,15 @@ from gi.repository.GObject import \
 
 from gi.repository import Gio
 from gi.repository import GLib
-from gi.repository import Regress
 from gi.repository import GIMarshallingTests
 from gi import _propertyhelper as propertyhelper
 
+try:
+    from gi.repository import Regress
+    has_regress = True
+except ImportError:
+    has_regress = False
+
 if sys.version_info < (3, 0):
     TEST_UTF8 = "\xe2\x99\xa5"
     UNICODE_UTF8 = unicode(TEST_UTF8, 'UTF-8')
@@ -73,19 +78,20 @@ class PropertyObject(GObject.GObject):
         type=Gio.File, flags=PARAM_READWRITE | PARAM_CONSTRUCT)
 
 
-class PropertyInheritanceObject(Regress.TestObj):
-    # override property from the base class, with a different type
-    string = GObject.Property(type=int)
-
-    # a property entirely defined at the Python level
-    python_prop = GObject.Property(type=str)
+if has_regress:
+    class PropertyInheritanceObject(Regress.TestObj):
+        # override property from the base class, with a different type
+        string = GObject.Property(type=int)
 
+        # a property entirely defined at the Python level
+        python_prop = GObject.Property(type=str)
 
-class PropertySubClassObject(PropertyInheritanceObject):
-    # override property from the base class, with a different type
-    python_prop = GObject.Property(type=int)
+    class PropertySubClassObject(PropertyInheritanceObject):
+        # override property from the base class, with a different type
+        python_prop = GObject.Property(type=int)
 
 
+@unittest.skipUnless(has_regress, 'Missing Regress typelib')
 class TestPropertyInheritanceObject(unittest.TestCase):
     def test_override_gi_property(self):
         self.assertNotEqual(Regress.TestObj.props.string.value_type,
@@ -728,6 +734,7 @@ class TestProperty(unittest.TestCase):
         b.prop1 = 20
         self.assertEqual(b.prop1, 20)
 
+    @unittest.skipUnless(has_regress, 'Missing regress typelib')
     def test_property_subclass_c(self):
         class A(Regress.TestSubObj):
             prop1 = GObject.Property(type=int)