diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:42:12 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:42:16 +0900 |
commit | 7db802a3275790915ed33b470f58786a362551c6 (patch) | |
tree | de7b66f2e6ded30942469c5173eb51241422aa48 /gi/pygi-invoke.c | |
parent | fecadc1d4b1cd7bafc93313c1120a4b350e2bced (diff) | |
download | pygobject2-7db802a3275790915ed33b470f58786a362551c6.tar.gz pygobject2-7db802a3275790915ed33b470f58786a362551c6.tar.bz2 pygobject2-7db802a3275790915ed33b470f58786a362551c6.zip |
Imported Upstream version 3.13.4
Change-Id: If8453fcd54aeed1d4cec58fcabaf92a68d0efbb5
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'gi/pygi-invoke.c')
-rw-r--r-- | gi/pygi-invoke.c | 257 |
1 files changed, 105 insertions, 152 deletions
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index eebf959..a65274a 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -25,45 +25,6 @@ #include "pygi-marshal-cleanup.h" #include "pygi-error.h" -static inline gboolean -_invoke_callable (PyGIInvokeState *state, - PyGICallableCache *cache, - GICallableInfo *callable_info) -{ - GIFFIReturnValue ffi_return_value = {0}; - - Py_BEGIN_ALLOW_THREADS; - - ffi_call (&cache->invoker.cif, - state->function_ptr, - (void *)&ffi_return_value, - (void **)state->args); - - 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 (pygi_error_check (&(state->error))) { - /* even though we errored out, the call itself was successful, - so we assume the call processed all of the parameters */ - pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); - return FALSE; - } - } - - if (cache->return_cache) { - gi_type_info_extract_ffi_return_value (cache->return_cache->type_info, - &ffi_return_value, - &state->return_arg); - } - - return TRUE; -} - static gboolean _check_for_unexpected_kwargs (const gchar *function_name, GHashTable *arg_name_hash, @@ -247,15 +208,14 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, return combined_py_args; } -static inline gboolean -_invoke_state_init_from_callable_cache (GIBaseInfo *info, - PyGIInvokeState *state, - PyGICallableCache *cache, - PyObject *py_args, - PyObject *kwargs) +static gboolean +_invoke_state_init_from_cache (PyGIInvokeState *state, + PyGIFunctionCache *function_cache, + PyObject *py_args, + PyObject *kwargs) { - PyObject *combined_args = NULL; - state->implementor_gtype = 0; + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + state->n_args = _pygi_callable_cache_args_len (cache); if (cache->throws) { @@ -263,74 +223,14 @@ _invoke_state_init_from_callable_cache (GIBaseInfo *info, } /* 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. + * this has already been filled out based on the implementor's GType. */ - 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 - * around if we want to call actual gobject constructors - * in the future instead of calling g_object_new - */ - if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR) { - PyObject *constructor_class; - constructor_class = PyTuple_GetItem (py_args, 0); - - if (constructor_class == NULL) { - PyErr_Clear (); - PyErr_Format (PyExc_TypeError, - "Constructors require the class to be passed in as an argument, " - "No arguments passed to the %s constructor.", - cache->name); - - return FALSE; - } - } 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, - "need the GType of the implementor class"); - return FALSE; - } - - state->implementor_gtype = pyg_type_from_object (py_gtype); - - 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 (pygi_error_check (&error)) { - return FALSE; - } - } - - if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR || - cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { - - /* we could optimize this by using offsets instead of modifying the tuple but it makes the - * code more error prone and confusing so don't do that unless profiling shows - * significant gain - */ - combined_args = PyTuple_GetSlice (py_args, 1, PyTuple_Size (py_args)); - } else { - combined_args = py_args; - Py_INCREF (combined_args); - } + if (state->function_ptr == NULL) + state->function_ptr = function_cache->invoker.native_address; state->py_in_args = _py_args_combine_and_check_length (cache, - combined_args, + py_args, kwargs); - Py_DECREF (combined_args); if (state->py_in_args == NULL) { return FALSE; @@ -373,8 +273,8 @@ _invoke_state_init_from_callable_cache (GIBaseInfo *info, return TRUE; } -static inline void -_invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache) +static void +_invoke_state_clear (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { g_slice_free1 (state->n_args * sizeof(GIArgument *), state->args); g_slice_free1 (state->n_args * sizeof(gpointer), state->args_cleanup_data); @@ -427,7 +327,7 @@ _caller_alloc (PyGIArgCache *arg_cache, GIArgument *arg) return TRUE; } -/* _invoke_marshal_in_args: +/* pygi_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 @@ -455,9 +355,10 @@ _caller_alloc (PyGIArgCache *arg_cache, GIArgument *arg) * ]] * */ -static inline gboolean -_invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) +static gboolean +_invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { + PyGICallableCache *cache = (PyGICallableCache *) function_cache; gssize i; if (state->n_py_in_args > cache->n_py_args) { @@ -497,7 +398,7 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) */ pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } @@ -516,7 +417,7 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) state->n_py_in_args); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } @@ -550,7 +451,7 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) i, cache->name); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } } else { @@ -564,7 +465,8 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) if (py_arg == _PyGIDefaultArgPlaceholder) { *c_arg = arg_cache->default_value; - } else if (arg_cache->from_py_marshaller != NULL) { + } else if (arg_cache->from_py_marshaller != NULL && + arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) { gboolean success; gpointer cleanup_data = NULL; @@ -575,7 +477,7 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } success = arg_cache->from_py_marshaller (state, @@ -589,7 +491,7 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) if (!success) { pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } @@ -600,9 +502,10 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) return TRUE; } -static inline PyObject * -_invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) +static PyObject * +_invoke_marshal_out_args (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { + PyGICallableCache *cache = (PyGICallableCache *) function_cache; PyObject *py_out = NULL; PyObject *py_return = NULL; gssize total_out_args = cache->n_to_py_args; @@ -610,15 +513,6 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) if (cache->return_cache) { if (!cache->return_cache->is_skipped) { - if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR) { - if (state->return_arg.v_pointer == NULL) { - PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); - pygi_marshal_cleanup_args_return_fail (state, - cache); - return NULL; - } - } - py_return = cache->return_cache->to_py_marshaller ( state, cache, cache->return_cache, @@ -697,7 +591,7 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) if (py_obj == NULL) { if (has_return) py_arg_index--; - + pygi_marshal_cleanup_args_to_py_parameter_fail (state, cache, py_arg_index); @@ -713,41 +607,100 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) } PyObject * -pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, - PyObject *kwargs, PyGICallableCache *cache, - gpointer user_data) +pygi_invoke_c_callable (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) { - PyGIInvokeState state = { 0, }; + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + GIFFIReturnValue ffi_return_value = {0}; PyObject *ret = NULL; - if (!_invoke_state_init_from_callable_cache (info, &state, cache, py_args, kwargs)) - goto err; + if (!_invoke_state_init_from_cache (state, function_cache, + py_args, py_kwargs)) + goto err; + + if (!_invoke_marshal_in_args (state, function_cache)) + goto err; + + Py_BEGIN_ALLOW_THREADS; - if (cache->function_type == PYGI_FUNCTION_TYPE_CCALLBACK) - state.user_data = user_data; + ffi_call (&function_cache->invoker.cif, + state->function_ptr, + (void *) &ffi_return_value, + (void **) state->args); + + 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 (pygi_error_check (&state->error)) { + /* even though we errored out, the call itself was successful, + so we assume the call processed all of the parameters */ + pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); + goto err; + } + } - if (!_invoke_marshal_in_args (&state, cache)) - goto err; + if (cache->return_cache) { + gi_type_info_extract_ffi_return_value (cache->return_cache->type_info, + &ffi_return_value, + &state->return_arg); + } - if (!_invoke_callable (&state, cache, info)) - goto err; + ret = _invoke_marshal_out_args (state, function_cache); + pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); - ret = _invoke_marshal_out_args (&state, cache); - pygi_marshal_cleanup_args_from_py_marshal_success (&state, cache); + if (ret != NULL) + pygi_marshal_cleanup_args_to_py_marshal_success (state, cache); - if (ret) - pygi_marshal_cleanup_args_to_py_marshal_success (&state, cache); err: - _invoke_state_clear (&state, cache); + _invoke_state_clear (state, function_cache); return ret; } PyObject * +pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, + PyObject *kwargs, PyGICallableCache *cache, + gpointer user_data) +{ + return pygi_function_cache_invoke ((PyGIFunctionCache *) cache, + py_args, kwargs); +} + +PyObject * _wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args, PyObject *kwargs) { if (self->cache == NULL) { - self->cache = pygi_callable_cache_new (self->info, NULL, FALSE); + PyGIFunctionCache *function_cache; + GIInfoType type = g_base_info_get_type (self->info); + + if (type == GI_INFO_TYPE_FUNCTION) { + GIFunctionInfoFlags flags; + + flags = g_function_info_get_flags ( (GIFunctionInfo *)self->info); + + if (flags & GI_FUNCTION_IS_CONSTRUCTOR) { + function_cache = pygi_constructor_cache_new (self->info); + } else if (flags & GI_FUNCTION_IS_METHOD) { + function_cache = pygi_method_cache_new (self->info); + } else { + function_cache = pygi_function_cache_new (self->info); + } + } else if (type == GI_INFO_TYPE_VFUNC) { + function_cache = pygi_vfunc_cache_new (self->info); + } else if (type == GI_INFO_TYPE_CALLBACK) { + g_error ("Cannot invoke callback types"); + } else { + function_cache = pygi_method_cache_new (self->info); + } + + self->cache = (PyGICallableCache *)function_cache; if (self->cache == NULL) return NULL; } |