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:
parent
9669b8d5b2
commit
6ccf376ab1
1 changed files with 102 additions and 15 deletions
|
|
@ -101,6 +101,7 @@
|
|||
<li><a href="#java_typemaps">Java typemaps</a>
|
||||
<ul>
|
||||
<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="#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>
|
||||
|
|
@ -316,6 +317,12 @@ additional information.
|
|||
is a useful reference for compiling on different platforms.
|
||||
</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>
|
||||
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).
|
||||
|
|
@ -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.
|
||||
</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>
|
||||
|
|
@ -4167,7 +4190,7 @@ Unfortunately it won't of course hold true for JNI code.
|
|||
</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>
|
||||
|
|
@ -4290,7 +4313,7 @@ int c = example.count('e',"Hello World");
|
|||
</pre>
|
||||
</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>
|
||||
|
|
@ -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.
|
||||
</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*)&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 **)&$input; /* cast jlong into C ptr */
|
||||
%}
|
||||
%typemap(out) struct Bar * %{
|
||||
*(struct Bar **)&$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 **)&jarg1; /* cast jlong into C ptr */
|
||||
|
||||
result = (struct Bar *)FooBar(arg1);
|
||||
|
||||
*(struct Bar **)&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>
|
||||
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>
|
||||
covered earlier.
|
||||
<a href="#default_primitive_type_mappings">Default primitive type mappings</a> and
|
||||
<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.
|
||||
These are listed below:
|
||||
</p>
|
||||
|
|
@ -4480,7 +4567,7 @@ These are listed below:
|
|||
|
||||
</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>
|
||||
|
|
@ -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.
|
||||
</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>
|
||||
|
|
@ -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>.
|
||||
</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>
|
||||
|
|
@ -4687,7 +4774,7 @@ If you do not intend your code to be targeting both C and C++ then your typemaps
|
|||
</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>
|
||||
|
|
@ -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>.
|
||||
</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>
|
||||
|
|
@ -5684,7 +5771,7 @@ allow the calling function to read the double * value after returning from the f
|
|||
jfieldID fid = jenv->GetFieldID(clazz, "swigCPtr", "J");
|
||||
jlong cPtr = jenv->GetLongField($input, fid);
|
||||
MyDouble *pMyDouble = NULL;
|
||||
*(MyDouble **)(void *)&pMyDouble = *(MyDouble **)(void *)&cPtr;
|
||||
*(MyDouble **)&pMyDouble = *(MyDouble **)&cPtr;
|
||||
$1 = &pMyDouble->value;
|
||||
}
|
||||
|
||||
|
|
@ -5849,7 +5936,7 @@ Add the following before the definition of <tt>vehicle_factory</tt>:
|
|||
<div class="code"><pre>
|
||||
%typemap(out) Vehicle * {
|
||||
Ambulance *downcast = dynamic_cast<Ambulance *>($1);
|
||||
*(Ambulance **)(void *)&$result = downcast;
|
||||
*(Ambulance **)&$result = downcast;
|
||||
}
|
||||
|
||||
%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->GetMethodID(clazz, "<init>", "(JZ)V");
|
||||
if (mid) {
|
||||
jlong cptr = 0;
|
||||
*(Ambulance **)(void *)&cptr = ambulance;
|
||||
*(Ambulance **)&cptr = ambulance;
|
||||
$result = jenv->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->GetMethodID(clazz, "<init>", "(JZ)V");
|
||||
if (mid) {
|
||||
jlong cptr = 0;
|
||||
*(FireEngine **)(void *)&cptr = fireengine;
|
||||
*(FireEngine **)&cptr = fireengine;
|
||||
$result = jenv->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)->FindClass(jenv, "Butler");
|
||||
jfieldID fid = (*jenv)->GetFieldID(jenv, clazz, "swigCPtr", "J");
|
||||
jlong cPtr = 0;
|
||||
*(Butler **)(void *)&cPtr = *$1;
|
||||
*(Butler **)&cPtr = *$1;
|
||||
(*jenv)->SetLongField(jenv, $input, fid, cPtr);
|
||||
}
|
||||
%typemap(javain) Butler ** "$javainput"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue