Performance optimisation for directors for classes passed by value

The directorin typemaps in the director methods now use std::move on the
input parameter when copying the object from the stack to the heap prior
to the callback into the target language, thereby taking advantage of
move semantics if available.
This commit is contained in:
William S Fulton 2022-07-03 13:58:26 +01:00
parent e75095e6c5
commit 71cd6a38fe
24 changed files with 80 additions and 20 deletions

View File

@ -7,6 +7,12 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress)
===========================
2022-07-03: wsfulton
Performane optimisation for directors for classes passed by value. The directorin
typemaps in the director methods now use std::move on the input parameter when
copying the object from the stack to the heap prior to the callback into the target
language, thereby taking advantage of move semantics if available.
2022-07-02: wsfulton
#1722 [C#, Java, Python, Ruby] Add std::unique_ptr support. Ported from std::auto_ptr.
Use the %unique_ptr(T) macro as follows for usage std::unique_ptr<T>. For example, for

View File

@ -28,6 +28,8 @@ public class runme
break;
};
}
if (director_pass_by_value.has_cplusplus11())
Counter.check_counts(1, 0, 0, 1, 0, 1); // check move constructor called and just one destructor
// bug was the passByVal 'global' object was destroyed after the call to virtualMethod had finished.
int ret = runme.passByVal.getVal();
if (ret != 0x12345678)

View File

@ -1,14 +1,38 @@
%module(directors="1") director_pass_by_value
#if defined(SWIGD)
%rename(trace) debug;
#endif
%director DirectorPassByValueAbstractBase;
%include "cpp11_move_only_helper.i"
%ignore PassedByValue::operator=;
%ignore PassedByValue::PassedByValue(PassedByValue &&);
%inline %{
class PassedByValue {
int val;
public:
PassedByValue() { val = 0x12345678; }
#include <iostream>
using namespace std;
int debug = false;
struct PassedByValue {
PassedByValue(int v = 0x12345678) { val = v; if (debug) cout << "PassedByValue(0x" << hex << val << ")" << " " << this << endl; Counter::normal_constructor++; }
PassedByValue(const PassedByValue &other) { val = other.val; if (debug) cout << "PassedByValue(const PassedByValue &)" << " " << this << " " << &other << endl; Counter::copy_constructor++;}
PassedByValue & operator=(const PassedByValue &other) { val = other.val; if (debug) cout << "operator=(const PassedByValue &)" << " " << this << " " << &other << endl; Counter::copy_assignment++; return *this; }
#if __cplusplus >= 201103L
PassedByValue(PassedByValue &&other) noexcept { val = other.val; if (debug) cout << "PassedByValue(PassedByValue &&)" << " " << this << endl; Counter::move_constructor++; }
PassedByValue & operator=(PassedByValue &&other) noexcept { val = other.val; if (debug) cout << "operator=(PassedByValue &&)" << " " << this << endl; Counter::move_assignment++; return *this; }
~PassedByValue() { if (debug) cout << "~PassedByValue()" << " " << this << endl; Counter::destructor++; }
#endif
int getVal() { return val; }
private:
int val;
};
int doSomething(int x) {
int yy[256];
yy[0] =0x9876;
@ -18,6 +42,7 @@ int doSomething(int x) {
class DirectorPassByValueAbstractBase {
public:
virtual void virtualMethod(PassedByValue pbv) = 0;
virtual void virtualConstMethod(const PassedByValue pbv) {}
virtual ~DirectorPassByValueAbstractBase () {}
};
@ -27,4 +52,12 @@ public:
f.virtualMethod(PassedByValue());
}
};
bool has_cplusplus11() {
#if __cplusplus >= 201103L
return true;
#else
return false;
#endif
}
%}

View File

@ -32,6 +32,8 @@ public class director_pass_by_value_runme {
break;
};
}
if (director_pass_by_value.has_cplusplus11())
Counter.check_counts(1, 0, 0, 1, 0, 1); // check move constructor called and just one destructor
// bug was the passByVal 'global' object was destroyed after the call to virtualMethod had finished.
int ret = director_pass_by_value_runme.passByVal.getVal();
if (ret != 0x12345678)

View File

@ -14,10 +14,13 @@ let d =
(director_pass_by_value_Derived)
'()
let cpp11 = _has_cplusplus11 '() as bool
let _ =
let caller = new_Caller '() in
assert (caller -> call_virtualMethod (d) = C_void);
assert (Array.length !passByVal = 1);
(* TODO: only run if cpp11... let _ = _Counter_check_counts (C_list [C_int 0; C_int 0; C_int 0; C_int 1; C_int 0; C_int 1]) in*) (* check move constructor called and just one destructor *)
let a = List.hd (fnhelper (!passByVal.(0))) in
assert (a -> getVal () as int = 0x12345678);
assert (a -> "~" () = C_void);

View File

@ -14,6 +14,9 @@ class director_pass_by_value_Derived extends DirectorPassByValueAbstractBase {
# bug was the passByVal global object was destroyed after the call to virtualMethod had finished.
$caller = new Caller();
$caller->call_virtualMethod(new director_pass_by_value_Derived());
if (has_cplusplus11()) {
Counter::check_counts(1, 0, 0, 1, 0, 1); # check move constructor called and just one destructor
}
$ret = $passByVal->getVal();
if ($ret != 0x12345678) {
check::fail("Bad return value, got " . dechex($ret));

View File

@ -8,6 +8,8 @@ class director_pass_by_value_Derived(director_pass_by_value.DirectorPassByValueA
# bug was the passByVal global object was destroyed after the call to virtualMethod had finished.
director_pass_by_value.Caller().call_virtualMethod(director_pass_by_value_Derived())
if director_pass_by_value.has_cplusplus11():
director_pass_by_value.Counter.check_counts(1, 0, 0, 1, 0, 1) # check move constructor called and just one destructor
ret = passByVal.getVal();
if ret != 0x12345678:
raise RuntimeError("Bad return value, got " + hex(ret))

View File

@ -32,7 +32,7 @@
%{ $result = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1)); %}
%typemap(directorin) CONST TYPE
%{ $input = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > (new $1_ltype((const $1_ltype &)$1)); %}
%{ $input = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > (new $1_ltype(SWIG_STD_MOVE($1))); %}
%typemap(directorout) CONST TYPE
%{ if (!$input) {

View File

@ -409,7 +409,7 @@ SWIGINTERN const char * SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
#endif
%typemap(directorin) SWIGTYPE
%{ $input = (void *)new $1_ltype((const $1_ltype &)$1); %}
%{ $input = (void *)new $1_ltype(SWIG_STD_MOVE($1)); %}
%typemap(csdirectorin) SWIGTYPE "new $&csclassname($iminput, true)"
%typemap(csdirectorout) SWIGTYPE "$&csclassname.getCPtr($cscall).Handle"

View File

@ -26,7 +26,7 @@
%{ $result = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1)); %}
%typemap(directorin) CONST TYPE
%{ $input = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > (new $1_ltype((const $1_ltype &)$1)); %}
%{ $input = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > (new $1_ltype(SWIG_STD_MOVE($1))); %}
%typemap(directorout) CONST TYPE
%{ if (!$input) {

View File

@ -62,7 +62,7 @@
#endif
%typemap(directorin) SWIGTYPE
"$input = (void *)new $1_ltype((const $1_ltype &)$1);"
"$input = (void *)new $1_ltype(SWIG_STD_MOVE($1));"
%typemap(directorout) SWIGTYPE
%{ if (!$input) {
SWIG_DSetPendingException(SWIG_DIllegalArgumentException, "Unexpected null return for type $1_type");

View File

@ -625,7 +625,7 @@
%typemap(goout) SWIGTYPE ""
%typemap(directorin) SWIGTYPE
%{ $input = new $1_ltype((const $1_ltype &)$1); %}
%{ $input = new $1_ltype(SWIG_STD_MOVE($1)); %}
%typemap(godirectorin) SWIGTYPE ""

View File

@ -33,7 +33,7 @@
%typemap(directorin,descriptor="L$packagepath/$&javaclassname;") CONST TYPE
%{ $input = 0;
*((SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > **)&$input) = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > (new $1_ltype((const $1_ltype &)$1)); %}
*((SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > **)&$input) = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > (new $1_ltype(SWIG_STD_MOVE($1))); %}
%typemap(directorout) CONST TYPE
%{ if (!$input) {

View File

@ -676,7 +676,7 @@ Swig::LocalRefGuard $1_refguard(jenv, $input); }
%typemap(directorin,descriptor="L$packagepath/$&javaclassname;") SWIGTYPE
%{ $input = 0;
*(($&1_ltype*)&$input) = new $1_ltype((const $1_ltype &)$1); %}
*(($&1_ltype*)&$input) = new $1_ltype(SWIG_STD_MOVE($1)); %}
%typemap(javadirectorin) SWIGTYPE "new $&javaclassname($jniinput, true)"
%typemap(javadirectorout) SWIGTYPE "$&javaclassname.getCPtr($javacall)"

View File

@ -40,7 +40,7 @@
%typemap(javadirectorout) CTYPE *const& "$javacall.$*interfacename_GetInterfaceCPtr()"
%typemap(directorin,descriptor="L$packagepath/$&javainterfacename;") CTYPE
%{ $input = 0;
*(($&1_ltype*)&$input) = new $1_ltype((const $1_ltype &)$1); %}
*(($&1_ltype*)&$input) = new $1_ltype(SWIG_STD_MOVE($1)); %}
%typemap(directorin,descriptor="L$packagepath/$javainterfacename;") CTYPE *, CTYPE []
%{ *(($&1_ltype)&$input) = ($1_ltype) $1; %}
%typemap(directorin,descriptor="L$packagepath/$javainterfacename;") CTYPE &

View File

@ -119,7 +119,7 @@
}
%typemap(directorin) SWIGTYPE {
$&ltype temp = new $ltype((const $ltype &)$1);
$&ltype temp = new $1_ltype(SWIG_STD_MOVE($1));
swig_result = SWIG_Ocaml_ptr_to_val("create_$ltype_from_ptr", (void *)temp, $&1_descriptor);
args = caml_list_append(args, swig_result);
}

View File

@ -59,7 +59,7 @@
}
%typemap(directorin,noblock=1) CONST TYPE (SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > *smartarg = 0) %{
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1));
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(SWIG_STD_MOVE($1)));
$input = SWIG_NewPointerObj(%as_voidptr(smartarg), $descriptor(SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< TYPE > *), SWIG_POINTER_OWN | %newpointer_flags);
%}
%typemap(directorout,noblock=1) CONST TYPE (void *swig_argp, int swig_res = 0) {

View File

@ -454,7 +454,7 @@
%typemap(directorin) SWIGTYPE
%{
ZVAL_UNDEF($input);
SWIG_SetPointerZval($input, SWIG_as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&1_descriptor, 1);
SWIG_SetPointerZval($input, SWIG_as_voidptr(new $1_ltype(SWIG_STD_MOVE($1))), $&1_descriptor, 1);
%}
%typemap(out, phptype="void") void "";

View File

@ -63,7 +63,7 @@
}
%typemap(directorin,noblock=1) CONST TYPE (SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > *smartarg = 0) %{
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1));
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(SWIG_STD_MOVE($1)));
$input = SWIG_NewPointerObj(%as_voidptr(smartarg), $descriptor(SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< TYPE > *), SWIG_POINTER_OWN | %newpointer_flags);
%}
%typemap(directorout,noblock=1) CONST TYPE (void *swig_argp, int swig_res = 0) {

View File

@ -59,7 +59,7 @@
}
%typemap(directorin,noblock=1) CONST TYPE (SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > *smartarg = 0) %{
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1));
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(SWIG_STD_MOVE($1)));
$input = SWIG_NewPointerObj(%as_voidptr(smartarg), $descriptor(SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< TYPE > *), SWIG_POINTER_OWN | %newpointer_flags);
%}
%typemap(directorout,noblock=1) CONST TYPE (void *swig_argp, int swig_res = 0) {

View File

@ -59,7 +59,7 @@
}
%typemap(directorin,noblock=1) CONST TYPE (SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > *smartarg = 0) %{
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1));
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(SWIG_STD_MOVE($1)));
$input = SWIG_NewPointerObj(%as_voidptr(smartarg), $descriptor(SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< TYPE > *), SWIG_POINTER_OWN | %newpointer_flags);
%}
%typemap(directorout,noblock=1) CONST TYPE (void *swig_argp, int swig_res = 0) {

View File

@ -59,7 +59,7 @@
}
%typemap(directorin,noblock=1) CONST TYPE (SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE > *smartarg = 0) %{
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(($1_ltype &)$1));
smartarg = new SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< CONST TYPE >(new $1_ltype(SWIG_STD_MOVE($1)));
$input = SWIG_NewPointerObj(%as_voidptr(smartarg), $descriptor(SWIG_SHARED_PTR_QNAMESPACE::shared_ptr< TYPE > *), SWIG_POINTER_OWN | %newpointer_flags);
%}
%typemap(directorout,noblock=1) CONST TYPE (void *swig_argp, int swig_res = 0) {

View File

@ -703,6 +703,15 @@ public:
template <typename T> T SwigValueInit() {
return T();
}
%}
%insert("runtime") %{
#if __cplusplus >=201103L
# define SWIG_STD_MOVE(OBJ) std::move(OBJ)
#else
# define SWIG_STD_MOVE(OBJ) OBJ
#endif
#endif
%}
#endif

View File

@ -417,7 +417,7 @@
/* directorin */
%typemap(directorin,noblock=1) SWIGTYPE {
$input = SWIG_NewPointerObj(%as_voidptr(new $1_ltype((const $1_ltype &)$1)), $&descriptor, SWIG_POINTER_OWN | %newpointer_flags);
$input = SWIG_NewPointerObj(%as_voidptr(new $1_ltype(SWIG_STD_MOVE($1))), $&descriptor, SWIG_POINTER_OWN | %newpointer_flags);
}
%typemap(directorin,noblock=1) SWIGTYPE * {