diff --git a/CHANGES.current b/CHANGES.current index 42c694ebe..53352513e 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -1,6 +1,12 @@ Version 1.3.36 (in progress) ============================= +05/14/2008: wsfulton + Add an optimisation for functions that return objects by value, reducing + the number of copies of the object that are made. Implemented using an + optional attribute in the "out" typemap called "optimal". Details in + Typemaps.html. + 05/11/2008: olly [PHP] Check for %feature("notabstract") when generating PHP5 class wrapper. diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html index 86908fdad..5c7a18eaf 100644 --- a/Doc/Manual/Contents.html +++ b/Doc/Manual/Contents.html @@ -379,6 +379,7 @@
+The "out" typemap supports an optional attribute flag called "optimal". This is for code optimisation and is detailed in the Optimal code generation when returning by value section. +
++The "out" typemap is the main typemap for return types. +This typemap supports an optional attribute flag called "optimal", which is for reducing +temporary variables and the amount of generated code. +It only really makes a difference when returning objects by value and it cannot always be used, +as explained later on. +
+ +
+When a function returns an object by value, SWIG generates code that instantiates the default +type on the stack then assigns the value returned by the function call to it. +A copy of this object is then made on the heap and this is what is ultimately stored and +used from the target language. +This will be clearer considering an example. +Consider running the following code through SWIG: +
+ +
+%typemap(out) SWIGTYPE %{
+ $result = new $1_ltype((const $1_ltype &)$1);
+%}
+
+%inline %{
+#include
+using namespace std;
+
+struct XX {
+ XX() { cout << "XX()" << endl; }
+ XX(int i) { cout << "XX(" << i << ")" << endl; }
+ XX(const XX &other) { cout << "XX(const XX &)" << endl; }
+ XX & operator =(const XX &other) { cout << "operator=(const XX &)" << endl; return *this; }
+ ~XX() { cout << "~XX()" << endl; }
+ static XX create() {
+ return XX(0);
+ }
+};
+%}
+
++The "out" typemap shown is the default typemap for C# when returning by objects by value. +When making a call to XX::create() from C#, the output is as follows: +
+ ++XX() +XX(0) +operator=(const XX &) +~XX() +XX(const XX &) +~XX() +~XX() ++
+Note that three objects are being created as well as an assignment. +Wouldn't it be great if the XX::create() method was the only time a constructor was called? +As the method returns by value, this is asking a lot and the code that SWIG generates by default +makes it impossible for the compiler to make this type of optimisation. +However, this is where the "optimal" attribute in the "out" typemap can help out. +If the typemap code is kept the same and just the "optimal" attribute specified like this: +
+ +
+%typemap(out, optimal="1") SWIGTYPE %{
+ $result = new $1_ltype((const $1_ltype &)$1);
+%}
+
++then when the code is run again, the output is simply: +
+ ++XX(0) +~XX() ++
+How the "optimal" attribute works is best explained using the generated code. +Without "optimal", the generated code is: +
+ +
+SWIGEXPORT void * SWIGSTDCALL CSharp_XX_create() {
+ void * jresult ;
+ XX result;
+ result = XX::create();
+ jresult = new XX((const XX &)result);
+ return jresult;
+}
+
+
++With the "optimal" attribute, the code is: +
+ +
+SWIGEXPORT void * SWIGSTDCALL CSharp_XX_create() {
+ void * jresult ;
+ jresult = new XX((const XX &)XX::create());
+ return jresult;
+}
+
++The major difference is the result temporary variable holding the value returned from XX::create() is no longer generated and instead the copy constructor call is made directly from +the value returned by XX::create(). +With modern compiler optimisations turned on, the copy is not actually done, in fact the object is never created +on the stack in XX::create() at all, it is simply created directly on the heap. +In the first instance, the $1 special variable in the typemap is expanded into result. +In the second instance, $1 is expanded into XX::create() and this is essentially +what the "optimal" attribute is telling SWIG to do. +
+ ++This kind of optimisation is not turned on by default as it has a number of restrictions. +Firstly, some code cannot be condensed into a simple call for passing into the copy constructor. +One common occurrence is when %exception is used. +Consider adding the following %exception to the example: +
+ +
+%exception XX::create() %{
+try {
+ $action
+} catch(const std::exception &e) {
+ cout << e.what() << endl;
+}
+%}
+
++SWIG can detect when the "optimal" attribute cannot be used and will ignore it and in this case will issue the following warning: +
+ +
+example.i:28: Warning(474): Method XX::create() usage of the optimal attribute in the out
+typemap at example.i:14 ignored as the following cannot be used to generate optimal code:
+try {
+ result = XX::create();
+} catch(const std::exception &e) {
+ cout << e.what() << endl;
+}
+
++It should be clear that the above code cannot be used as the argument to the copy constructor call, ie for the $1 substitution. +
+ +
+Secondly, if the typemaps uses $1 more than once, then multiple calls to the wrapped function +will be made. Obviously that is not very optimal. +In fact SWIG attempts to detect this and will issue a warning something like: +
+ ++example.i:21: Warning(475): Multiple calls to XX::create() might be generated due to +optimal attribute usage in the out typemap at example.i:7. ++
+However, it doesn't always get it right, for example when $1 is within some commented out code. +
+ +@@ -2884,7 +3076,7 @@ when crossing languages you may need to worry about issues such as row-major vs. ordering (and perform conversions if needed).
-@@ -2910,7 +3102,7 @@ language modules.
@@ -3096,7 +3288,7 @@ structures rather than creating new ones. These swig_module_info structures are chained together in a circularly linked list.
-This section covers how to use these functions from typemaps. To learn how to @@ -3190,7 +3382,7 @@ probably just look at the output of SWIG to get a better sense for how types are managed.
-@@ -3499,7 +3691,7 @@ Subsequent "in" typemaps would then perform more extensive type-checking. -
@@ -3584,7 +3776,7 @@ example: -
@@ -3665,7 +3857,7 @@ convert_float_array(PyObject *input, int size) { -
@@ -3702,7 +3894,7 @@ sure that the typemaps sharing information have exactly the same types and names
-diff --git a/Doc/Manual/Warnings.html b/Doc/Manual/Warnings.html index 6a851b3a7..39d5d3f01 100644 --- a/Doc/Manual/Warnings.html +++ b/Doc/Manual/Warnings.html @@ -482,8 +482,12 @@ example.i(4): Syntax error in input.