Commit 4dcaa2b9 authored by Simon Feltman's avatar Simon Feltman

cache refactoring: Move GObject arg setup and marshaling into new file

Move GObject argument cache setup and marshaling fragments into
isolated file: pygi-object.c.
Break GIInterfaceCache creation and setup into API for interface based
argument cache usage.

https://bugzilla.gnome.org/show_bug.cgi?id=709700
parent 2cddba81
......@@ -111,6 +111,8 @@ _gi_la_SOURCES = \
pygi-array.h \
pygi-error.c \
pygi-error.h \
pygi-object.c \
pygi-object.h \
pygi-hashtable.c \
pygi-hashtable.h
_gi_la_CFLAGS = \
......
......@@ -34,6 +34,7 @@
#include "pygi-marshal-from-py.h"
#include "pygi-marshal-to-py.h"
#include "pygi-basictype.h"
#include "pygi-object.h"
static gboolean
......@@ -1063,7 +1064,7 @@ array_success:
case GI_INFO_TYPE_INTERFACE:
case GI_INFO_TYPE_OBJECT:
/* An error within this call will result in a NULL arg */
_pygi_marshal_from_py_gobject_out_arg (object, &arg, transfer);
pygi_arg_gobject_out_arg_from_py (object, &arg, transfer);
break;
default:
......@@ -1436,10 +1437,10 @@ _pygi_argument_to_object (GIArgument *arg,
transfer == GI_TRANSFER_NOTHING &&
g_object_is_floating (arg->v_pointer)) {
g_object_ref (arg->v_pointer);
object = _pygi_marshal_to_py_object (arg, GI_TRANSFER_EVERYTHING);
object = pygi_arg_gobject_to_py (arg, GI_TRANSFER_EVERYTHING);
g_object_force_floating (arg->v_pointer);
} else {
object = _pygi_marshal_to_py_object (arg, transfer);
object = pygi_arg_gobject_to_py (arg, transfer);
}
break;
......
......@@ -33,15 +33,7 @@
#include "pygi-array.h"
#include "pygi-closure.h"
#include "pygi-error.h"
PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
GITypeInfo *type_info,
GIArgInfo *arg_info,
GITransfer transfer,
PyGIDirection direction,
/* will be removed */
PyGICallableCache *callable_cache);
#include "pygi-object.h"
/* _arg_info_default_value
......@@ -100,32 +92,6 @@ pygi_arg_base_setup (PyGIArgCache *arg_cache,
return TRUE;
}
gboolean
pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction,
GIInterfaceInfo *iface_info)
{
if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache,
type_info,
arg_info,
transfer,
direction)) {
return FALSE;
}
g_base_info_ref ( (GIBaseInfo *)iface_info);
iface_cache->interface_info = iface_info;
iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE;
return TRUE;
}
/* cleanup */
void
_pygi_arg_cache_free (PyGIArgCache *cache)
{
......@@ -140,6 +106,26 @@ _pygi_arg_cache_free (PyGIArgCache *cache)
g_slice_free (PyGIArgCache, cache);
}
void
_pygi_callable_cache_free (PyGICallableCache *cache)
{
if (cache == NULL)
return;
g_slist_free (cache->to_py_args);
g_slist_free (cache->arg_name_list);
g_hash_table_destroy (cache->arg_name_hash);
g_ptr_array_unref (cache->args_cache);
if (cache->return_cache != NULL)
_pygi_arg_cache_free (cache->return_cache);
g_slice_free (PyGICallableCache, cache);
}
/* PyGIInterfaceCache */
static void
_interface_cache_free_func (PyGIInterfaceCache *cache)
{
......@@ -153,50 +139,70 @@ _interface_cache_free_func (PyGIInterfaceCache *cache)
}
}
static void
_sequence_cache_free_func (PyGISequenceCache *cache)
gboolean
pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction,
GIInterfaceInfo *iface_info)
{
if (cache != NULL) {
_pygi_arg_cache_free (cache->item_cache);
g_slice_free (PyGISequenceCache, cache);
if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache,
type_info,
arg_info,
transfer,
direction)) {
return FALSE;
}
}
void
_pygi_callable_cache_free (PyGICallableCache *cache)
{
if (cache == NULL)
return;
( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
g_slist_free (cache->to_py_args);
g_slist_free (cache->arg_name_list);
g_hash_table_destroy (cache->arg_name_hash);
g_ptr_array_unref (cache->args_cache);
g_base_info_ref ( (GIBaseInfo *)iface_info);
iface_cache->interface_info = iface_info;
iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE;
iface_cache->type_name = _pygi_g_base_info_get_fullname (iface_info);
iface_cache->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
iface_cache->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
if (cache->return_cache != NULL)
_pygi_arg_cache_free (cache->return_cache);
if (iface_cache->py_type == NULL) {
return FALSE;
}
g_slice_free (PyGICallableCache, cache);
return TRUE;
}
/* cache generation */
static PyGIInterfaceCache *
_interface_cache_new (GIInterfaceInfo *iface_info)
PyGIArgCache *
pygi_arg_interface_new_from_info (GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction,
GIInterfaceInfo *iface_info)
{
PyGIInterfaceCache *ic;
ic = g_slice_new0 (PyGIInterfaceCache);
( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
if (ic->py_type == NULL)
if (!pygi_arg_interface_setup (ic,
type_info,
arg_info,
transfer,
direction,
iface_info)) {
_pygi_arg_cache_free ((PyGIArgCache *)ic);
return NULL;
}
ic->type_name = _pygi_g_base_info_get_fullname (iface_info);
return ic;
return (PyGIArgCache *)ic;
}
/* PyGISequenceCache */
static void
_sequence_cache_free_func (PyGISequenceCache *cache)
{
if (cache != NULL) {
_pygi_arg_cache_free (cache->item_cache);
g_slice_free (PyGISequenceCache, cache);
}
}
gboolean
......@@ -286,22 +292,6 @@ _arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache,
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign;
}
static void
_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object;
arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object;
}
static void
_arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter;
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object;
}
static void
_arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
......@@ -331,7 +321,7 @@ _arg_cache_to_py_interface_flags_setup (PyGIArgCache *arg_cache,
}
PyGIArgCache *
static PyGIArgCache *
_arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
GITypeInfo *type_info,
GIArgInfo *arg_info,
......@@ -354,11 +344,22 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
iface_info,
callable_cache);
}
case GI_INFO_TYPE_OBJECT:
case GI_INFO_TYPE_INTERFACE:
return pygi_arg_gobject_new_from_info (type_info,
arg_info,
transfer,
direction,
iface_info);
default:
; /* pass through to old model of setup */
}
arg_cache = (PyGIArgCache *)_interface_cache_new (iface_info);
arg_cache = pygi_arg_interface_new_from_info (type_info,
arg_info,
transfer,
direction,
iface_info);
if (arg_cache == NULL)
return NULL;
......@@ -383,15 +384,6 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
iface_info,
transfer);
break;
case GI_INFO_TYPE_OBJECT:
case GI_INFO_TYPE_INTERFACE:
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_interface_object_setup (arg_cache, transfer);
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_interface_object_setup (arg_cache, transfer);
break;
case GI_INFO_TYPE_ENUM:
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_interface_enum_setup (arg_cache, transfer);
......@@ -412,13 +404,6 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
g_assert_not_reached ();
}
pygi_arg_interface_setup ((PyGIInterfaceCache *)arg_cache,
type_info,
arg_info,
transfer,
direction,
iface_info);
return arg_cache;
}
......
......@@ -214,6 +214,13 @@ pygi_arg_sequence_setup (PyGISequenceCache *sc,
GITransfer transfer,
PyGIDirection direction);
PyGIArgCache *
pygi_arg_interface_new_from_info (GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction,
GIInterfaceInfo *iface_info);
PyGIArgCache * _arg_cache_alloc (void);
PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
GIArgInfo *arg_info,
......
......@@ -206,33 +206,6 @@ pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state,
state->failed = TRUE;
}
void
_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *py_arg,
gpointer data,
gboolean was_processed)
{
/* If we processed the parameter but fail before invoking the method,
we need to remove the ref we added */
if (was_processed && state->failed && data != NULL &&
arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_object_unref (G_OBJECT(data));
}
void
_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *dummy,
gpointer data,
gboolean was_processed)
{
/* If we error out and the object is not marshalled into a PyGObject
we must take care of removing the ref */
if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_object_unref (G_OBJECT(data));
}
void
_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
......
......@@ -55,16 +55,6 @@ void _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *stat
PyObject *dummy,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *py_arg,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
PyObject *dummy,
gpointer data,
gboolean was_processed);
G_END_DECLS
#endif /* __PYGI_MARSHAL_CLEANUP_H__ */
......@@ -298,40 +298,6 @@ _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state,
return FALSE;
}
gboolean
_pygi_marshal_from_py_interface_object (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
PyObject *py_arg,
GIArgument *arg,
gpointer *cleanup_data)
{
gboolean res = FALSE;
if (py_arg == Py_None) {
arg->v_pointer = NULL;
return TRUE;
}
if (!PyObject_IsInstance (py_arg, ( (PyGIInterfaceCache *)arg_cache)->py_type)) {
PyObject *module = PyObject_GetAttrString(py_arg, "__module__");
PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s",
arg_cache->arg_name ? arg_cache->arg_name : "self",
( (PyGIInterfaceCache *)arg_cache)->type_name,
module ? PYGLIB_PyUnicode_AsString(module) : "",
module ? "." : "",
py_arg->ob_type->tp_name);
if (module)
Py_DECREF (module);
return FALSE;
}
res = _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer);
*cleanup_data = arg->v_pointer;
return res;
}
gboolean
_pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
......@@ -345,95 +311,6 @@ _pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
return FALSE;
}
/* _pygi_marshal_from_py_gobject:
* py_arg: (in):
* arg: (out):
*/
gboolean
_pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/
GIArgument *arg, /*out*/
GITransfer transfer) {
GObject *gobj;
if (py_arg == Py_None) {
arg->v_pointer = NULL;
return TRUE;
}
if (!pygobject_check (py_arg, &PyGObject_Type)) {
PyObject *repr = PyObject_Repr (py_arg);
PyErr_Format(PyExc_TypeError, "expected GObject but got %s",
PYGLIB_PyUnicode_AsString (repr));
Py_DECREF (repr);
return FALSE;
}
gobj = pygobject_get (py_arg);
if (transfer == GI_TRANSFER_EVERYTHING) {
/* For transfer everything, add a new ref that the callee will take ownership of.
* Pythons existing ref to the GObject will be managed with the PyGObject wrapper.
*/
g_object_ref (gobj);
}
arg->v_pointer = gobj;
return TRUE;
}
/* _pygi_marshal_from_py_gobject_out_arg:
* py_arg: (in):
* arg: (out):
*
* A specialization for marshaling Python GObjects used for out/return values
* from a Python implemented vfuncs, signals, or an assignment to a GObject property.
*/
gboolean
_pygi_marshal_from_py_gobject_out_arg (PyObject *py_arg, /*in*/
GIArgument *arg, /*out*/
GITransfer transfer) {
GObject *gobj;
if (!_pygi_marshal_from_py_gobject (py_arg, arg, transfer)) {
return FALSE;
}
/* HACK: At this point the basic marshaling of the GObject was successful
* but we add some special case hacks for vfunc returns due to buggy APIs:
* https://bugzilla.gnome.org/show_bug.cgi?id=693393
*/
gobj = arg->v_pointer;
if (py_arg->ob_refcnt == 1 && gobj->ref_count == 1) {
/* If both object ref counts are only 1 at this point (the reference held
* in a return tuple), we assume the GObject will be free'd before reaching
* its target and become invalid. So instead of getting invalid object errors
* we add a new GObject ref.
*/
g_object_ref (gobj);
if (((PyGObject *)py_arg)->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) {
/*
* We want to re-float instances that were floating and the Python
* wrapper assumed ownership. With the additional caveat that there
* are not any strong references beyond the return tuple.
*/
g_object_force_floating (gobj);
} else {
PyObject *repr = PyObject_Repr (py_arg);
gchar *msg = g_strdup_printf ("Expecting to marshal a borrowed reference for %s, "
"but nothing in Python is holding a reference to this object. "
"See: https://bugzilla.gnome.org/show_bug.cgi?id=687522",
PYGLIB_PyUnicode_AsString(repr));
Py_DECREF (repr);
if (PyErr_WarnEx (PyExc_RuntimeWarning, msg, 2)) {
g_free (msg);
return FALSE;
}
g_free (msg);
}
}
return TRUE;
}
/* _pygi_marshal_from_py_gvalue:
* py_arg: (in):
......
......@@ -57,12 +57,6 @@ gboolean _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state,
PyObject *py_arg,
GIArgument *arg,
gpointer *cleanup_data);
gboolean _pygi_marshal_from_py_interface_object (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
PyObject *py_arg,
GIArgument *arg,
gpointer *cleanup_data);
gboolean _pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
......@@ -71,12 +65,6 @@ gboolean _pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
gpointer *cleanup_data);
/* Simplified marshalers shared between vfunc/closure and direct function calls. */
gboolean _pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/
GIArgument *arg, /*out*/
GITransfer transfer);
gboolean _pygi_marshal_from_py_gobject_out_arg (PyObject *py_arg, /*in*/
GIArgument *arg, /*out*/
GITransfer transfer);
gboolean _pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/
GIArgument *arg, /*out*/
......
......@@ -193,15 +193,6 @@ _pygi_marshal_to_py_interface_boxed (PyGIInvokeState *state,
return py_obj;
}
PyObject *
_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg)
{
return _pygi_marshal_to_py_object(arg, arg_cache->transfer);
}
PyObject *
_pygi_marshal_to_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
......@@ -215,28 +206,6 @@ _pygi_marshal_to_py_interface_union (PyGIInvokeState *state,
return py_obj;
}
PyObject *
_pygi_marshal_to_py_object (GIArgument *arg, GITransfer transfer) {
PyObject *pyobj;
if (arg->v_pointer == NULL) {
pyobj = Py_None;
Py_INCREF (pyobj);
} else if (G_IS_PARAM_SPEC(arg->v_pointer)) {
pyobj = pyg_param_spec_new (arg->v_pointer);
if (transfer == GI_TRANSFER_EVERYTHING)
g_param_spec_unref (arg->v_pointer);
} else {
pyobj = pygobject_new_full (arg->v_pointer,
/*steal=*/ transfer == GI_TRANSFER_EVERYTHING,
/*type=*/ NULL);
}
return pyobj;
}
PyObject *
_pygi_marshal_to_py_interface_struct (GIArgument *arg,
GIInterfaceInfo *interface_info,
......
......@@ -42,20 +42,12 @@ PyObject *_pygi_marshal_to_py_interface_boxed (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg);
PyObject *_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg);
PyObject *_pygi_marshal_to_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg);
/* Simplified marshalers shared between vfunc/closure and direct function calls. */
PyObject *_pygi_marshal_to_py_object (GIArgument *arg,
GITransfer transfer);
PyObject *_pygi_marshal_to_py_interface_struct (GIArgument *arg,
GIInterfaceInfo *interface_info,
GType g_type,
......
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
* Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
* Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include <Python.h>
#include <pyglib-python-compat.h>
#include "pygi-arg-gobject.h"
#include "pygi-private.h"
#include "pygparamspec.h"
/*
* GObject from Python