Python - remove duplicate proxy method definitions for global function wrappers.
Global functions previously generated two definitions, eg:
def foo():
return _example.foo()
foo = _example.foo
The first definition is replaced by the second definition and so the second definition
is the one used when the method is actually called. Now just the first definition is
generated by default and if the -fastproxy command line option is used, just the second
definition is generated. The second definition is faster as it avoids the proxy Python
method as it calls the low-level C wrapper directly. Using both -fastproxy and -olddefs
command line options will restore the previously generated code as it will generate both
method definitions.
With this change, the wrappers for global C/C++ functions and C++ class methods now work
in the same way wrt to generating just a proxy method by default and control via
-fastproxy/-olddefs options.
Closes #639.
This commit is contained in:
parent
0078c7d84d
commit
07884f10ee
3 changed files with 57 additions and 15 deletions
|
|
@ -7,6 +7,27 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.0.0 (in progress)
|
||||
===========================
|
||||
|
||||
2019-01-01: wsfulton
|
||||
[Python] #639 remove duplicate proxy method definitions for global function wrappers.
|
||||
|
||||
Global functions previously generated two definitions, eg:
|
||||
|
||||
def foo():
|
||||
return _example.foo()
|
||||
foo = _example.foo
|
||||
|
||||
The first definition is replaced by the second definition and so the second definition
|
||||
is the one used when the method is actually called. Now just the first definition is
|
||||
generated by default and if the -fastproxy command line option is used, just the second
|
||||
definition is generated. The second definition is faster as it avoids the proxy Python
|
||||
method as it calls the low-level C wrapper directly. Using both -fastproxy and -olddefs
|
||||
command line options will restore the previously generated code as it will generate both
|
||||
method definitions.
|
||||
|
||||
With this change, the wrappers for global C/C++ functions and C++ class methods now work
|
||||
in the same way wrt to generating just a proxy method by default and control via
|
||||
-fastproxy/-olddefs options.
|
||||
|
||||
2018-12-20: hasinoff,wsfulton
|
||||
[Java] #1334 Set Java thread name to native thread name when using directors.
|
||||
|
||||
|
|
|
|||
|
|
@ -3913,6 +3913,7 @@ class Go(object):
|
|||
</div>
|
||||
|
||||
<p>
|
||||
Each method in the Python class contains a Python proxy method which passes the arguments on to the underlying function in the low-level C/C++ module (_example in this case).
|
||||
The generated proxy class when using <tt>-fastproxy</tt> is:
|
||||
</p>
|
||||
|
||||
|
|
@ -3928,7 +3929,12 @@ class Go(object):
|
|||
</div>
|
||||
|
||||
<p>
|
||||
where <tt>_swig_new_instance_method</tt> adds the method to the proxy class via C API calls.
|
||||
where <tt>_swig_new_instance_method</tt> adds the method to the proxy class via C API calls for direct access to the underlying function in the low-level C/C++ module.
|
||||
Note that for some methods it is not possible to generate the direct access call and so <tt>-fastproxy</tt> is ignored.
|
||||
This happens, for example, when adding <a href="#Python_nn42">additional code</a> to Python proxy methods, such as using <tt>%pythonprepend</tt>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The overhead calling into C/C++ from Python is reduced slightly using <tt>-fastproxy</tt>.
|
||||
Below are some timings in microseconds calling the 3 functions in the example above.
|
||||
Also included in the table for comparison is using the <tt>-builtin</tt> option covered in the
|
||||
|
|
@ -3995,6 +4001,10 @@ The class defines each method in two different ways. The first definition is rep
|
|||
While this possibly provides the best of both worlds, the time to import the module will be slighly slower when the class is defined due to the additional method definitions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The command line options mentioned above also apply to wrapped C/C++ global functions, not just class methods.
|
||||
</p>
|
||||
|
||||
<H2><a name="Python_nn45">38.7 Tips and techniques</a></H2>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2144,6 +2144,9 @@ public:
|
|||
if (nn)
|
||||
n = nn;
|
||||
|
||||
Parm *parms = Getattr(n, "parms");
|
||||
bool varargs = parms ? emit_isvarargs(parms) : 0;
|
||||
|
||||
/* We prefer to explicitly list all parameters of the C function in the
|
||||
generated Python code as this makes the function more convenient to use,
|
||||
however in some cases we must replace the real parameters list with just
|
||||
|
|
@ -2153,8 +2156,9 @@ public:
|
|||
2. We were explicitly asked to use the "compact" arguments form.
|
||||
3. We were explicitly asked to use default args from C via the "python:cdefaultargs" feature.
|
||||
4. One of the default argument values can't be represented in Python.
|
||||
5. Varargs that haven't been forced to use a fixed number of arguments with %varargs.
|
||||
*/
|
||||
if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n)) {
|
||||
if (is_real_overloaded(n) || GetFlag(n, "feature:compactdefaultargs") || GetFlag(n, "feature:python:cdefaultargs") || !is_representable_as_pyargs(n) || varargs) {
|
||||
String *parms = NewString("");
|
||||
if (in_class)
|
||||
Printf(parms, "self, ");
|
||||
|
|
@ -2295,21 +2299,28 @@ public:
|
|||
void emitFunctionShadowHelper(Node *n, File *f_dest, String *name, int kw) {
|
||||
String *parms = make_pyParmList(n, false, false, kw);
|
||||
String *callParms = make_pyParmList(n, false, true, kw);
|
||||
/* Make a wrapper function to insert the code into */
|
||||
Printv(f_dest, "\ndef ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL);
|
||||
if (have_docstring(n))
|
||||
Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4), "\n", NIL);
|
||||
if (have_pythonprepend(n))
|
||||
Printv(f_dest, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL);
|
||||
if (have_pythonappend(n)) {
|
||||
Printv(f_dest, tab4 "val = ", funcCall(name, callParms), "\n", NIL);
|
||||
Printv(f_dest, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL);
|
||||
Printv(f_dest, tab4 "return val\n", NIL);
|
||||
} else {
|
||||
Printv(f_dest, tab4 "return ", funcCall(name, callParms), "\n", NIL);
|
||||
|
||||
// Callbacks need the C function in order to extract the pointer from the swig_ptr: string
|
||||
bool fast = (fastproxy && !have_addtofunc(n)) || Getattr(n, "feature:callback");
|
||||
|
||||
if (!fast || olddefs) {
|
||||
/* Make a wrapper function to insert the code into */
|
||||
Printv(f_dest, "\n", "def ", name, "(", parms, ")", returnTypeAnnotation(n), ":\n", NIL);
|
||||
if (have_docstring(n))
|
||||
Printv(f_dest, tab4, docstring(n, AUTODOC_FUNC, tab4), "\n", NIL);
|
||||
if (have_pythonprepend(n))
|
||||
Printv(f_dest, indent_pythoncode(pythonprepend(n), tab4, Getfile(n), Getline(n), "%pythonprepend or %feature(\"pythonprepend\")"), "\n", NIL);
|
||||
if (have_pythonappend(n)) {
|
||||
Printv(f_dest, tab4 "val = ", funcCall(name, callParms), "\n", NIL);
|
||||
Printv(f_dest, indent_pythoncode(pythonappend(n), tab4, Getfile(n), Getline(n), "%pythonappend or %feature(\"pythonappend\")"), "\n", NIL);
|
||||
Printv(f_dest, tab4 "return val\n", NIL);
|
||||
} else {
|
||||
Printv(f_dest, tab4 "return ", funcCall(name, callParms), "\n", NIL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_addtofunc(n)) {
|
||||
// Below may result in a 2nd definition of the method when -olddefs is used. The Python interpreter will use the second definition as it overwrites the first.
|
||||
if (fast) {
|
||||
/* If there is no addtofunc directive then just assign from the extension module (for speed up) */
|
||||
Printv(f_dest, name, " = ", module, ".", name, "\n", NIL);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue