Add notes about strict aliasing rules

Add section on non-primitive types type mapping


git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@8952 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2006-03-04 23:41:02 +00:00
commit 6ccf376ab1

View file

@ -101,6 +101,7 @@
<li><a href="#java_typemaps">Java typemaps</a> <li><a href="#java_typemaps">Java typemaps</a>
<ul> <ul>
<li><a href="#default_primitive_type_mappings">Default primitive type mappings</a> <li><a href="#default_primitive_type_mappings">Default primitive type mappings</a>
<li><a href="#Java_default_non_primitive_typemaps">Default typemaps for non-primitive types</a>
<li><a href="#jvm64">Sixty four bit JVMs</a> <li><a href="#jvm64">Sixty four bit JVMs</a>
<li><a href="#what_is_typemap">What is a typemap?</a> <li><a href="#what_is_typemap">What is a typemap?</a>
<li><a href="#typemaps_c_to_java_types">Typemaps for mapping C/C++ types to Java types</a> <li><a href="#typemaps_c_to_java_types">Typemaps for mapping C/C++ types to Java types</a>
@ -316,6 +317,12 @@ additional information.
is a useful reference for compiling on different platforms. is a useful reference for compiling on different platforms.
</p> </p>
<p>
<b>Important</b> <br>
If you are going to use optimisations turned on with gcc (for example -O2), ensure you also compile with -fno-strict-aliasing. The GCC optimisations have become
more aggressive from gcc-4.0 onwards and will result in code that fails with strict aliasing optimisations turned on. See the <a href="#typemaps_c_to_java_types">C/C++ to Java typemaps</a> section for more details.
</p>
<p> <p>
The name of the shared library output file is important. The name of the shared library output file is important.
If the name of your SWIG module is "<tt>example</tt>", the name of the corresponding shared library file should be "<tt>libexample.so</tt>" (or equivalent depending on your machine, see <a href="#dynamic_linking_problems">Dynamic linking problems</a> for more information). If the name of your SWIG module is "<tt>example</tt>", the name of the corresponding shared library file should be "<tt>libexample.so</tt>" (or equivalent depending on your machine, see <a href="#dynamic_linking_problems">Dynamic linking problems</a> for more information).
@ -4154,7 +4161,23 @@ There is no perfect mapping between Java and C as Java doesn't support all the u
However, the mappings allow the full range of values for each C type from Java. However, the mappings allow the full range of values for each C type from Java.
</p> </p>
<H3><a name="jvm64"></a>20.8.2 Sixty four bit JVMs</H3>
<H3><a name="Java_default_non_primitive_typemaps"></a>20.8.2 Default typemaps for non-primitive types</H3>
<p>
The previous section covered the primitive type mappings.
Non-primitive types such as classes and structs are mapped using pointers on the C/C++ side and storing the pointer into a Java <tt>long</tt> variable which is held by
the proxy class or type wrapper class. This applies whether the type is marshalled as a pointer, by reference or by value.
It also applies for any unknown/incomplete types which use type wrapper classes.
</p>
<p>
So in summary, the C/C++ pointer to non-primitive types is cast into the 64 bit Java <tt>long</tt> type and therefore the JNI type is a <tt>jlong</tt>.
The Java type is either the proxy class or type wrapper class.
</p>
<H3><a name="jvm64"></a>20.8.3 Sixty four bit JVMs</H3>
<p> <p>
@ -4167,7 +4190,7 @@ Unfortunately it won't of course hold true for JNI code.
</p> </p>
<H3><a name="what_is_typemap"></a>20.8.3 What is a typemap?</H3> <H3><a name="what_is_typemap"></a>20.8.4 What is a typemap?</H3>
<p> <p>
@ -4290,7 +4313,7 @@ int c = example.count('e',"Hello World");
</pre> </pre>
</div> </div>
<H3><a name="typemaps_c_to_java_types"></a>20.8.4 Typemaps for mapping C/C++ types to Java types</H3> <H3><a name="typemaps_c_to_java_types"></a>20.8.5 Typemaps for mapping C/C++ types to Java types</H3>
<p> <p>
@ -4380,10 +4403,74 @@ The "freearg" typemap sometimes releases memory allocated by the "in" typemap.
The "argout" typemap sometimes sets values in function parameters which are passed by reference in Java. The "argout" typemap sometimes sets values in function parameters which are passed by reference in Java.
</p> </p>
<p>
Note that the "in" typemap marshals the JNI type held in the "jni" typemap to the real C/C++ type and for the opposite direction,
the "out" typemap marshals the real C/C++ type to the JNI type held in the "jni" typemap.
For <a href="#Java_default_non_primitive_typemaps">non-primitive types</a>
the "in" and "out" typemaps are responsible for casting between the C/C++ pointer and the 64 bit <tt>jlong</tt> type.
There is no portable way to cast a pointer into a 64 bit integer type and the approach taken by SWIG is mostly portable, but breaks C/C++ aliasing rules.
In summary, these rules state that a pointer to any type must never be dereferenced by a pointer to any other incompatible type.
The following code snippet might aid in understand aliasing rules better:
</p>
<div class="code"><pre>
short a;
short* pa = 0;
int i = 0x1234;
a = (short)i; /* okay */
a = *(short*)&amp;i; /* breaks aliasing rules */
</pre></div>
<p>
An email posting, <a href="http://mail-index.netbsd.org/tech-kern/2003/08/11/0001.html">Aliasing, pointer casts and gcc 3.3</a> elaborates further on the subject.
In SWIG, the "in" and "out" typemaps for pointers are typically
</p>
<div class="code"><pre>
%typemap(in) struct Foo * %{
$1 = *(struct Foo **)&amp;$input; /* cast jlong into C ptr */
%}
%typemap(out) struct Bar * %{
*(struct Bar **)&amp;$result = $1; /* cast C ptr into jlong */
%}
struct Bar {...};
struct Foo {...};
struct Bar * FooBar(struct Foo *f);
</pre></div>
<p>
resulting in the following code which breaks the aliasing rules:
</p>
<div class="code"><pre>
JNIEXPORT jlong JNICALL Java_exampleJNI_FooBar(JNIEnv *jenv, jclass jcls, jlong jarg1) {
jlong jresult = 0 ;
struct Foo *arg1 = (struct Foo *) 0 ;
struct Bar *result = 0 ;
(void)jenv;
(void)jcls;
arg1 = *(struct Foo **)&amp;jarg1; /* cast jlong into C ptr */
result = (struct Bar *)FooBar(arg1);
*(struct Bar **)&amp;jresult = result; /* cast C ptr into jlong */
return jresult;
}
</pre></div>
<p>
If you are using gcc as your C compiler, you might get a "dereferencing type-punned pointer will break strict-aliasing rules" warning about this.
Please see <a href="#compiling_dynamic">Compiling a dynamic module</a> to avoid runtime problems with these strict aliasing rules.
</p>
<p> <p>
The default code generated by SWIG for the Java module comes from the typemaps in the "<tt>java.swg</tt>" library file which implements the The default code generated by SWIG for the Java module comes from the typemaps in the "<tt>java.swg</tt>" library file which implements the
<a href="#default_primitive_type_mappings">Default primitive type mappings</a> <a href="#default_primitive_type_mappings">Default primitive type mappings</a> and
covered earlier. <a href="#Java_default_non_primitive_typemaps">Default typemaps for non-primitive types</a> covered earlier.
There are other type mapping typemaps in the Java library. There are other type mapping typemaps in the Java library.
These are listed below: These are listed below:
</p> </p>
@ -4480,7 +4567,7 @@ These are listed below:
</table> </table>
<H3><a name="typemap_attributes"></a>20.8.5 Java typemap attributes</H3> <H3><a name="typemap_attributes"></a>20.8.6 Java typemap attributes</H3>
<p> <p>
@ -4510,7 +4597,7 @@ the union of the exception classes is added to the throws clause ensuring there
See the <a href="#nan_exception_typemap">NaN exception example</a> for further usage. See the <a href="#nan_exception_typemap">NaN exception example</a> for further usage.
</p> </p>
<H3><a name="special_variables"></a>20.8.6 Java special variables</H3> <H3><a name="special_variables"></a>20.8.7 Java special variables</H3>
<p> <p>
@ -4650,7 +4737,7 @@ This special variable expands to the intermediary class name. Usually this is th
unless the jniclassname attribute is specified in the <a href="Java.html#java_module_directive">%module directive</a>. unless the jniclassname attribute is specified in the <a href="Java.html#java_module_directive">%module directive</a>.
</p> </p>
<H3><a name="typemaps_for_c_and_c++"></a>20.8.7 Typemaps for both C and C++ compilation</H3> <H3><a name="typemaps_for_c_and_c++"></a>20.8.8 Typemaps for both C and C++ compilation</H3>
<p> <p>
@ -4687,7 +4774,7 @@ If you do not intend your code to be targeting both C and C++ then your typemaps
</p> </p>
<H3><a name="java_code_typemaps"></a>20.8.8 Java code typemaps</H3> <H3><a name="java_code_typemaps"></a>20.8.9 Java code typemaps</H3>
<p> <p>
@ -4877,7 +4964,7 @@ For the typemap to be used in all type wrapper classes, all the different types
Again this is the same that is in "<tt>java.swg</tt>", barring the method modifier for <tt>getCPtr</tt>. Again this is the same that is in "<tt>java.swg</tt>", barring the method modifier for <tt>getCPtr</tt>.
</p> </p>
<H3><a name="java_directors_typemaps"></a>20.8.9 Director specific typemaps</H3> <H3><a name="java_directors_typemaps"></a>20.8.10 Director specific typemaps</H3>
<p> <p>
@ -5684,7 +5771,7 @@ allow the calling function to read the double * value after returning from the f
jfieldID fid = jenv-&gt;GetFieldID(clazz, "swigCPtr", "J"); jfieldID fid = jenv-&gt;GetFieldID(clazz, "swigCPtr", "J");
jlong cPtr = jenv-&gt;GetLongField($input, fid); jlong cPtr = jenv-&gt;GetLongField($input, fid);
MyDouble *pMyDouble = NULL; MyDouble *pMyDouble = NULL;
*(MyDouble **)(void *)&amp;pMyDouble = *(MyDouble **)(void *)&amp;cPtr; *(MyDouble **)&amp;pMyDouble = *(MyDouble **)&amp;cPtr;
$1 = &amp;pMyDouble-&gt;value; $1 = &amp;pMyDouble-&gt;value;
} }
@ -5849,7 +5936,7 @@ Add the following before the definition of <tt>vehicle_factory</tt>:
<div class="code"><pre> <div class="code"><pre>
%typemap(out) Vehicle * { %typemap(out) Vehicle * {
Ambulance *downcast = dynamic_cast&lt;Ambulance *&gt;($1); Ambulance *downcast = dynamic_cast&lt;Ambulance *&gt;($1);
*(Ambulance **)(void *)&amp;$result = downcast; *(Ambulance **)&amp;$result = downcast;
} }
%typemap(javaout) Vehicle * { %typemap(javaout) Vehicle * {
@ -5917,7 +6004,7 @@ Note that in this case, the Java class is constructed using JNI code rather than
jmethodID mid = jenv-&gt;GetMethodID(clazz, "&lt;init&gt;", "(JZ)V"); jmethodID mid = jenv-&gt;GetMethodID(clazz, "&lt;init&gt;", "(JZ)V");
if (mid) { if (mid) {
jlong cptr = 0; jlong cptr = 0;
*(Ambulance **)(void *)&amp;cptr = ambulance; *(Ambulance **)&amp;cptr = ambulance;
$result = jenv-&gt;NewObject(clazz, mid, cptr, false); $result = jenv-&gt;NewObject(clazz, mid, cptr, false);
} }
} }
@ -5928,7 +6015,7 @@ Note that in this case, the Java class is constructed using JNI code rather than
jmethodID mid = jenv-&gt;GetMethodID(clazz, "&lt;init&gt;", "(JZ)V"); jmethodID mid = jenv-&gt;GetMethodID(clazz, "&lt;init&gt;", "(JZ)V");
if (mid) { if (mid) {
jlong cptr = 0; jlong cptr = 0;
*(FireEngine **)(void *)&amp;cptr = fireengine; *(FireEngine **)&amp;cptr = fireengine;
$result = jenv-&gt;NewObject(clazz, mid, cptr, false); $result = jenv-&gt;NewObject(clazz, mid, cptr, false);
} }
} }
@ -6156,7 +6243,7 @@ The following interface file code should be placed before SWIG parses the above
jclass clazz = (*jenv)-&gt;FindClass(jenv, "Butler"); jclass clazz = (*jenv)-&gt;FindClass(jenv, "Butler");
jfieldID fid = (*jenv)-&gt;GetFieldID(jenv, clazz, "swigCPtr", "J"); jfieldID fid = (*jenv)-&gt;GetFieldID(jenv, clazz, "swigCPtr", "J");
jlong cPtr = 0; jlong cPtr = 0;
*(Butler **)(void *)&amp;cPtr = *$1; *(Butler **)&amp;cPtr = *$1;
(*jenv)-&gt;SetLongField(jenv, $input, fid, cPtr); (*jenv)-&gt;SetLongField(jenv, $input, fid, cPtr);
} }
%typemap(javain) Butler ** "$javainput" %typemap(javain) Butler ** "$javainput"