aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--doc/GlueGen_Mapping.html302
-rw-r--r--doc/GlueGen_Mapping.md227
-rw-r--r--src/java/com/jogamp/gluegen/CCodeUnit.java15
-rw-r--r--src/java/com/jogamp/gluegen/CMethodBindingEmitter.java355
-rw-r--r--src/java/com/jogamp/gluegen/FunctionEmitter.java57
-rw-r--r--src/java/com/jogamp/gluegen/JavaCallbackEmitter.java666
-rw-r--r--src/java/com/jogamp/gluegen/JavaConfiguration.java87
-rw-r--r--src/java/com/jogamp/gluegen/JavaEmitter.java36
-rw-r--r--src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java437
-rw-r--r--src/java/com/jogamp/gluegen/JavaType.java109
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java13
-rw-r--r--src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java9
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java431
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.c82
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg17
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/test2.h14
-rw-r--r--www/index.html2
18 files changed, 1999 insertions, 862 deletions
diff --git a/README.md b/README.md
index 089ca01..e9741f5 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@ GlueGen can produce native foreign function bindings to Java™ as well as
[map native data structures](doc/GlueGen_Mapping.md#struct-mapping) to be fully accessible from Java™ including
potential calls to [embedded function pointer](doc/GlueGen_Mapping.md#struct-function-pointer-support).
-GlueGen supports [registering Java™ callback methods](doc/GlueGen_Mapping.md#java-callback-from-native-c-api-support)
+GlueGen supports [registering Java™ callback methods](doc/GlueGen_Mapping.md#java-callback)
to receive asynchronous and off-thread native toolkit events,
where a generated native callback function dispatches the events to Java™.
diff --git a/doc/GlueGen_Mapping.html b/doc/GlueGen_Mapping.html
index 706eda4..d1b5b04 100644
--- a/doc/GlueGen_Mapping.html
+++ b/doc/GlueGen_Mapping.html
@@ -449,19 +449,28 @@
<li><a href="#struct-function-pointer-support">Struct Function-Pointer
Support</a></li>
</ul></li>
- <li><a href="#java-callback-from-native-c-api-support">Java Callback
- from Native C-API Support</a>
+ <li><a href="#java-callback">Java Callback</a>
<ul>
- <li><a href="#required-libraryonload">Required
- <em>LibraryOnLoad</em></a></li>
+ <li><a href="#implementation-details">Implementation Details</a></li>
+ <li><a href="#javacallback-userparam-mapping"><em>JavaCallback</em>
+ <em>UserParam</em> Mapping</a></li>
<li><a href="#javacallback-configuration"><em>JavaCallback</em>
Configuration</a></li>
+ <li><a
+ href="#javacallback-generated-interfaces-classes-and-methods"><em>JavaCallback</em>
+ Generated Interfaces, Classes and Methods</a></li>
<li><a href="#javacallback-notes"><em>JavaCallback</em> Notes</a></li>
<li><a href="#javacallback-example-1">JavaCallback Example 1</a></li>
<li><a href="#javacallback-example-2a-default-keyclass">JavaCallback
Example 2a (Default <em>KeyClass</em>)</a></li>
<li><a href="#javacallback-example-2b-custom-keyclass">JavaCallback
Example 2b (Custom <em>KeyClass</em>)</a></li>
+ <li><a
+ href="#javacallback-example-11a-homogeneous-struct-type">JavaCallback
+ Example 11a (<em>Homogeneous Struct Type</em>)</a></li>
+ <li><a
+ href="#javacallback-example-11b-heterogeneous-pointerstruct-type">JavaCallback
+ Example 11b (<em>Heterogeneous Pointer/Struct Type</em>)</a></li>
</ul></li>
<li><a href="#misc-configurations">Misc Configurations</a>
<ul>
@@ -531,11 +540,10 @@ as <a href="#struct-mapping">map native data structures</a> to be fully
accessible from Java™ including potential calls to <a
href="#struct-function-pointer-support">embedded function
pointer</a>.</p>
-<p>GlueGen supports <a
-href="#java-callback-from-native-c-api-support">registering Java™
-callback methods</a> to receive asynchronous and off-thread native
-toolkit events, where a generated native callback function dispatches
-the events to Java™.</p>
+<p>GlueGen supports <a href="#java-callback">registering Java™ callback
+methods</a> to receive asynchronous and off-thread native toolkit
+events, where a generated native callback function dispatches the events
+to Java™.</p>
<p>GlueGen also supports <a
href="#oo-style-api-interface-mapping">producing an OO-Style API
mapping</a> like <a href="../../jogl/doc/uml/html/index.html">JOGL's
@@ -1076,7 +1084,7 @@ variable</li>
function pointer, see <a href="#struct-function-pointer-support">Struct
Function-Pointer Support</a> below.</li>
<li><em>Java Callback from Native Code</em>, see <a
-href="#java-callback-from-native-c-api-support">section below</a></li>
+href="#java-callback">section below</a></li>
</ul>
<p>A field may be a direct aggregation, i.e. instance, within the struct
including an array or a reference to a single element or array via a
@@ -1947,24 +1955,79 @@ StructPackage T2_InitializeOptions com.jogamp.gluegen.test.junit.generation</cod
/** Interface to C language function: &lt;br&gt; &lt;code&gt;int32_t CustomFuncB1(T2_UserData * pUserData)&lt;/code&gt;&lt;br&gt; */
public final int CustomFuncB1(T2_UserData pUserData) { .. } </code></pre>
-<h2 id="java-callback-from-native-c-api-support">Java Callback from
-Native C-API Support</h2>
+<h2 id="java-callback">Java Callback</h2>
<p>GlueGen supports registering Java callback methods to receive
asynchronous and off-thread native toolkit events, where a generated
native callback function dispatches the events to Java.</p>
-<h3 id="required-libraryonload">Required <em>LibraryOnLoad</em></h3>
-<p>Note that <a
-href="#libraryonload-librarybasename-for-jni_onload-"><code>LibraryOnLoad Bindingtest2</code></a>
-must be specified in exactly one native code-unit. It provides code to
-allow the generated native callback-function to attach the current
-thread to the <code>JavaVM*</code> generating a new
-<code>JNIEnv*</code>in daemon mode - or just to retrieve the thread's
-<code>JNIEnv*</code>, if already attached to the
-<code>JavaVM*</code>.</p>
+<h3 id="implementation-details">Implementation Details</h3>
+<p>Implementation generates a static Java callback dispatcher for each
+defined <code>SetCallbackFunction</code>, which gets invoked by the
+generated native static counterpart with all arguments required.</p>
+<p>The <em>static callback</em> utilizes its own synchronization for
+thread-safety and fetches the required data set stored at
+<code>SetCallbackFunction</code> to dispatch the call to the users'
+<code>CallbackFunction</code>.<br />
+In case the callback has been removed already, the <em>static
+callback</em> simply bails out quietly.</p>
+<p>The native code does not create, release or manage heap memory and
+therefore is considered safe.</p>
+<h3 id="javacallback-userparam-mapping"><em>JavaCallback</em>
+<em>UserParam</em> Mapping</h3>
+<p>Usually the same <code>UserParam</code> type is used in both items
+(or hooks), <code>SetCallbackFunctionName</code> and
+<code>CallbackFunctionType</code>, which we call a homogeneous
+<code>UserParam</code> mapping.</p>
+<p>Even in a homogeneous <code>UserParam</code> mapping, handling of the
+<code>UserParam</code> value might differ in the native binding
+code.</p>
+<p>To specify a non homogeneous <code>UserParam</code> mapping, i.e.
+heterogeneous <code>UserParam</code> mapping, the <code>UserParam</code>
+index of the <code>SetCallbackFunction</code> must be <a
+href="#javacallback-configuration">set in the configuration</a>.</p>
+<p>The following mappings are supported.</p>
+<h4 id="pure-java-object-user-type-default">Pure Java Object User Type
+(default)</h4>
+<p>A pure Java <em>Object type</em> is used for both,
+<code>SetCallbackFunctionName</code> and
+<code>CallbackFunctionType</code>.</p>
+<p>It's a homogeneous <code>UserParam</code> mapping, where the native
+side receives a simple unique ID and shall not dereference the
+<em>pointer</em>.</p>
+<p>The static Java callback dispatcher fetches the Java
+<code>UserParam</code> <em>Object</em> from the key-mapped data
+value.</p>
+<h4 id="struct-type-user-param-homogeneous">Struct Type User Param
+(Homogeneous)</h4>
+<p>A <a href="#struct-mapping">GlueGen generated <em>Struct
+type</em></a> is used for both, <code>SetCallbackFunctionName</code> and
+<code>CallbackFunctionType</code>.</p>
+<p>It's a homogeneous <code>UserParam</code> mapping, where the native
+side receives the actual native struct address.</p>
+<p>The static Java callback dispatcher dereferences the received native
+struct address (<em>long</em>), i.e. rebuilding the <em>struct
+Object</em> to be passed to the users'
+<code>CallbackFunction</code>.</p>
+<h4 id="struct-type-user-param-heterogeneous">Struct Type User Param
+(Heterogeneous)</h4>
+<p>An anonymous pointer (<em>long</em>) for
+<code>SetCallbackFunctionName</code> and a <a
+href="#struct-mapping">GlueGen generated <em>struct type</em></a> for
+<code>CallbackFunctionType</code> is being used.</p>
+<p>It's a heterogeneous <code>UserParam</code> mapping, where the
+toolkit is expected to place the given anonymous pointer inside the
+defined <em>struct type</em> passed to the
+<code>CallbackFunction</code>.</p>
+<p>The <code>SetCallback-UserParamIndex</code> for the different
+parameter-type is <a href="#javacallback-configuration">set in the
+configuration</a>.</p>
+<p>The static Java callback dispatcher dereferences the received native
+struct address (<em>long</em>), i.e. rebuilding the <em>struct
+Object</em> to be passed to the users'
+<code>CallbackFunction</code>.</p>
<h3 id="javacallback-configuration"><em>JavaCallback</em>
Configuration</h3>
<p>Configuration directives are as follows:</p>
-<pre><code>JavaCallbackDef &lt;SetCallbackFunctionName&gt; &lt;CallbackFunctionType&gt; &lt;CallbackFunction-UserParamIndex&gt; [&lt;SetCallback-KeyClassName&gt;]
+<pre><code>JavaCallbackDef &lt;SetCallbackFunctionName&gt; [&lt;SetCallback-UserParamIndex&gt;] &lt;CallbackFunctionType&gt; &lt;CallbackFunction-UserParamIndex&gt; [&lt;SetCallback-KeyClassName&gt;]
JavaCallbackKey &lt;SetCallbackFunctionName&gt; (SetCallback-ParamIdx)*</code></pre>
<p><code>JavaCallbackDef</code> and <code>JavaCallbackKey</code> use the
name of the <code>SetCallbackFunction</code> as its first attribute, as
@@ -1973,6 +2036,11 @@ it is core to the semantic mapping of all resources.</p>
<ul>
<li><code>SetCallbackFunction</code>: <code>SetCallbackFunction</code>
name of the native toolkit API responsible to set the callback</li>
+<li><code>SetCallback-UserParamIndex</code>: Optional
+<code>UserParam</code> parameter-index of the
+<code>SetCallbackFunction</code>, allowing to <a
+href="#struct-type-user-param-heterogeneous">indicate a heterogeneous
+<code>UserParam</code></a></li>
<li><code>CallbackFunctionType</code>: The native toolkit API
typedef-name of the function-pointer-type, aka the callback type
name</li>
@@ -2012,9 +2080,35 @@ callback scope, i.e. the callback and all resources will be mapped to
this key. The optional <code>SetCallback-KeyClass</code> may override
this semantic.</li>
</ul>
-<h4
+<h4 id="custom-setcallback-keyclass">Custom
+<code>SetCallback-KeyClass</code></h4>
+<p>The <code>SetCallback-KeyClass</code> is the optional user-written
+hash-map-key definition and shall handle all key parameter of the
+<code>SetCallbackFunction</code> as defined via
+<code>JavaCallbackKey</code>, see above.</p>
+<p><code>SetCallback-KeyClass</code> may be used to add external
+key-components, e.g. current-thread or a toolkit dependent context.</p>
+<p>The <code>SetCallback-KeyClass</code> shall implement the following
+hash-map-key standard methods</p>
+<ul>
+<li><code>boolean equals(Object)</code></li>
+<li><code>int hashCode()</code></li>
+<li><code>SetCallback-KeyClassName(...)</code> constructor receiving all
+key parameter of <code>SetCallbackFunction</code> as defined via
+<code>JavaCallbackKey</code>, see above.</li>
+</ul>
+<h4 id="required-libraryonload">Required <em>LibraryOnLoad</em></h4>
+<p>Note that <a
+href="#libraryonload-librarybasename-for-jni_onload-"><code>LibraryOnLoad Bindingtest2</code></a>
+must be specified in exactly one native code-unit. It provides code to
+allow the generated native callback-function to attach the current
+thread to the <code>JavaVM*</code> generating a new
+<code>JNIEnv*</code>in daemon mode - or just to retrieve the thread's
+<code>JNIEnv*</code>, if already attached to the
+<code>JavaVM*</code>.</p>
+<h3
id="javacallback-generated-interfaces-classes-and-methods"><em>JavaCallback</em>
-Generated Interfaces, Classes and Methods</h4>
+Generated Interfaces, Classes and Methods</h3>
<p>The public <code>CallbackFunction</code> interface is generated.</p>
<p>The default public <code>SetCallback-KeyClass</code> is generated if
keys are used and no custom class is specified, see above.</p>
@@ -2068,23 +2162,6 @@ and <em>releaseAll<code>SetCallbackFunctionName</code>()</em> methods
are not the <em>proper toolkit API way</em> to remove the callback, try
to use original <code>SetCallbackFunctionName</code> API method instead
using a <code>null</code> <code>CallbackFunction</code> reference.</p>
-<h4 id="custom-setcallback-keyclass">Custom
-<code>SetCallback-KeyClass</code></h4>
-<p>The <code>SetCallback-KeyClass</code> is the optional user-written
-hash-map-key definition and shall handle all key parameter of the
-<code>SetCallbackFunction</code> as defined via
-<code>JavaCallbackKey</code>, see above.</p>
-<p><code>SetCallback-KeyClass</code> may be used to add external
-key-components, e.g. current-thread or a toolkit dependent context.</p>
-<p>The <code>SetCallback-KeyClass</code> shall implement the following
-hash-map-key standard methods</p>
-<ul>
-<li><code>boolean equals(Object)</code></li>
-<li><code>int hashCode()</code></li>
-<li><code>SetCallback-KeyClassName(...)</code> constructor receiving all
-key parameter of <code>SetCallbackFunction</code> as defined via
-<code>JavaCallbackKey</code>, see above.</li>
-</ul>
<h3 id="javacallback-notes"><em>JavaCallback</em> Notes</h3>
<p>Please consider the following <em>currently enabled</em> constraints
using JavaCallback</p>
@@ -2118,7 +2195,11 @@ and the native callback dispatcher <strong>are thread-safe</strong></li>
<li>...</li>
</ul>
<h3 id="javacallback-example-1">JavaCallback Example 1</h3>
-<p>This is a generic example.</p>
+<p>This examples demonstrates a <a
+href="#pure-java-object-user-type-default">homogeneous <em>Java
+Object</em> <code>UserParam</code> mapping</a> with a <a
+href="#javacallback-key-definition">globally scoped</a>
+<code>CallbackFunction</code> and <code>UserParam</code>.</p>
<p>The callback <code>T2_CallbackFunc01</code> has global scope, i.e. is
not mapped to any key and can be only set globally.</p>
<p>C-API header snippet:</p>
@@ -2187,6 +2268,11 @@ thread to the <code>JavaVM*</code> generating a new
public void InjectMessageCallback01(long id, String msg);</code></pre>
<h3 id="javacallback-example-2a-default-keyclass">JavaCallback Example
2a (Default <em>KeyClass</em>)</h3>
+<p>This examples demonstrates a <a
+href="#pure-java-object-user-type-default">homogeneous <em>Java
+Object</em> <code>UserParam</code> mapping</a> with a <a
+href="#javacallback-key-definition">key-mapped</a>
+<code>CallbackFunction</code> and <code>UserParam</code>.</p>
<p>This examples is derived from OpenAL's
<code>AL_SOFT_callback_buffer</code> extension.</p>
<p>The callback <code>ALBUFFERCALLBACKTYPESOFT</code> is mapped to
@@ -2278,6 +2364,11 @@ buffer.</p>
public void alEventCallbackInject(int eventType, int object, int param, String msg); </code></pre>
<h3 id="javacallback-example-2b-custom-keyclass">JavaCallback Example 2b
(Custom <em>KeyClass</em>)</h3>
+<p>This examples demonstrates a <a
+href="#pure-java-object-user-type-default">homogeneous <em>Java
+Object</em> <code>UserParam</code> mapping</a> with a <a
+href="#custom-setcallback-keyclass">custom <em>KeyClass</em></a> to map
+<code>CallbackFunction</code> and <code>UserParam</code>.</p>
<p>Same as example 2a, but implementing a custom
<code>SetCallback-KeyClass</code>.</p>
<p>Instead of <code>Callback0</code>, the unit <code>test2.*</code> uses
@@ -2316,6 +2407,133 @@ which uses one key, i.e. <code>buffer</code>.</p>
return &quot;CustomALKey[this &quot;+toHexString(System.identityHashCode(this))+&quot;, buffer &quot;+buffer+&quot;]&quot;;
}
}</code></pre>
+<h3 id="javacallback-example-11a-homogeneous-struct-type">JavaCallback
+Example 11a (<em>Homogeneous Struct Type</em>)</h3>
+<p>This examples demonstrates a <a
+href="#struct-type-user-param-homogeneous">homogeneous <em>Struct</em>
+<code>UserParam</code> mapping</a> with a <a
+href="#javacallback-key-definition">key-mapped</a>
+<code>CallbackFunction</code> and <code>UserParam</code>.</p>
+<p>The callback <code>T2_CallbackFunc11</code> is passed by the toolkit
+to the <code>CallbackFunction</code> and by the user to the registration
+method <code>MessageCallback11b(..)</code>.</p>
+<p>C-API Header snipped</p>
+<pre><code> typedef struct {
+ int32_t ApiVersion;
+ void* Data;
+ long i;
+ long r;
+ size_t id;
+ } T2_Callback11UserType;
+
+ typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam, long val);
+
+ void MessageCallback11a(size_t id /* key */, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam);
+ void MessageCallback11aInject(size_t id, long val); </code></pre>
+<p>and the following GlueGen configuration</p>
+<pre><code> JavaCallbackDef MessageCallback11a T2_CallbackFunc11 1
+ JavaCallbackKey MessageCallback11a 0</code></pre>
+<p>leading to the following interface</p>
+<pre><code> /** JavaCallback interface: T2_CallbackFunc11 -&gt; void (*T2_CallbackFunc11)(size_t id, const T2_Callback11UserType * usrParam, long val) */
+ public static interface T2_CallbackFunc11 {
+ /** Interface to C language function: &lt;br&gt; &lt;code&gt;void callback(size_t id, const T2_Callback11UserType * usrParam, long val)&lt;/code&gt;&lt;br&gt;Alias for: &lt;code&gt;T2_CallbackFunc11&lt;/code&gt; */
+ public void callback(long id, T2_Callback11UserType usrParam, long val);
+ }
+
+ ...
+
+ public static class MessageCallback11aKey { ... }
+
+ ...
+
+ /** Returns set of Key { long id } for &lt;br&gt; &lt;code&gt; void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)&lt;/code&gt; */
+ public Set&lt;MessageCallback11aKey&gt; getMessageCallback11aKeys();
+
+ /** Returns whether callback Key { long id } is mapped for &lt;br&gt; &lt;code&gt; void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)&lt;/code&gt; */
+ public boolean isMessageCallback11aMapped(MessageCallback11aKey key);
+
+ /** Returns T2_CallbackFunc11 callback mapped to Key { long id } for &lt;br&gt; &lt;code&gt; void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)&lt;/code&gt; */
+ public T2_CallbackFunc11 getMessageCallback11a(MessageCallback11aKey key);
+
+ /** Returns user-param mapped to Key { long id } for &lt;br&gt; &lt;code&gt; void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)&lt;/code&gt; */
+ public Object getMessageCallback11aUserParam(MessageCallback11aKey key);
+
+ /** Releases all callback data mapped via Key { long id } skipping toolkit API. Favor passing `null` callback ref to &lt;br&gt; &lt;code&gt; void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)&lt;/code&gt; */
+ public int releaseAllMessageCallback11a();
+
+ /** Releases callback data mapped to Key { long id } skipping toolkit API. Favor passing `null` callback ref to &lt;br&gt; &lt;code&gt; void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)&lt;/code&gt; */
+ public void releaseMessageCallback11a(MessageCallback11aKey key);
+
+ /** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void MessageCallback11a(size_t id, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType * usrParam)&lt;/code&gt;&lt;br&gt; */
+ public void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam);
+
+ /** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void MessageCallback11aInject(size_t id, long val)&lt;/code&gt;&lt;br&gt; */
+ public void MessageCallback11aInject(long id, long val); </code></pre>
+<h3
+id="javacallback-example-11b-heterogeneous-pointerstruct-type">JavaCallback
+Example 11b (<em>Heterogeneous Pointer/Struct Type</em>)</h3>
+<p>This examples demonstrates a <a
+href="#struct-type-user-param-heterogeneous">heterogeneous
+<em>Struct</em> <code>UserParam</code> mapping</a> with a <a
+href="#javacallback-key-definition">key-mapped</a>
+<code>CallbackFunction</code> and <code>UserParam</code>.</p>
+<p>The callback <code>T2_CallbackFunc11</code> is managed by the toolkit
+and passed to the callback function, while user passes a <em>void</em>
+with the registration method <code>MessageCallback11b(..)</code>. The
+toolkit associates the users' <code>void*</code> pointer with the
+<code>T2_CallbackFunc11</code>.</p>
+<p>C-API Header snipped</p>
+<pre><code> typedef struct {
+ int32_t ApiVersion;
+ void* Data;
+ long i;
+ long r;
+ size_t id;
+ } T2_Callback11UserType;
+
+ typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam, long val);
+
+ void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data);
+ void MessageCallback11bInject(size_t id, long val);</code></pre>
+<p>and the following GlueGen configuration</p>
+<pre><code> JavaCallbackDef MessageCallback11b 2 T2_CallbackFunc11 1
+ JavaCallbackKey MessageCallback11b 0</code></pre>
+<p>leading to the following interface</p>
+<pre><code> /** JavaCallback interface: T2_CallbackFunc11 -&gt; void (*T2_CallbackFunc11)(size_t id, const T2_Callback11UserType * usrParam, long val) */
+ public static interface T2_CallbackFunc11 {
+ /** Interface to C language function: &lt;br&gt; &lt;code&gt;void callback(size_t id, const T2_Callback11UserType * usrParam, long val)&lt;/code&gt;&lt;br&gt;Alias for: &lt;code&gt;T2_CallbackFunc11&lt;/code&gt; */
+ public void callback(long id, T2_Callback11UserType usrParam, long val);
+ }
+
+ ...
+
+ public static class MessageCallback11bKey { ... }
+
+ ...
+
+ /** Returns set of Key { long id } for &lt;br&gt; &lt;code&gt; void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)&lt;/code&gt; */
+ public Set&lt;MessageCallback11bKey&gt; getMessageCallback11bKeys();
+
+ /** Returns whether callback Key { long id } is mapped for &lt;br&gt; &lt;code&gt; void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)&lt;/code&gt; */
+ public boolean isMessageCallback11bMapped(MessageCallback11bKey key);
+
+ /** Returns T2_CallbackFunc11 callback mapped to Key { long id } for &lt;br&gt; &lt;code&gt; void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)&lt;/code&gt; */
+ public T2_CallbackFunc11 getMessageCallback11b(MessageCallback11bKey key);
+
+ /** Returns user-param mapped to Key { long id } for &lt;br&gt; &lt;code&gt; void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)&lt;/code&gt; */
+ public Object getMessageCallback11bUserParam(MessageCallback11bKey key);
+
+ /** Releases all callback data mapped via Key { long id } skipping toolkit API. Favor passing `null` callback ref to &lt;br&gt; &lt;code&gt; void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)&lt;/code&gt; */
+ public int releaseAllMessageCallback11b();
+
+ /** Releases callback data mapped to Key { long id } skipping toolkit API. Favor passing `null` callback ref to &lt;br&gt; &lt;code&gt; void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)&lt;/code&gt; */
+ public void releaseMessageCallback11b(MessageCallback11bKey key);
+
+ /** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void MessageCallback11b(size_t id, T2_CallbackFunc11 cbFunc, void * Data)&lt;/code&gt;&lt;br&gt; */
+ public void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data);
+
+ /** Entry point (through function pointer) to C language function: &lt;br&gt; &lt;code&gt;void MessageCallback11bInject(size_t id, long val)&lt;/code&gt;&lt;br&gt; */
+ public void MessageCallback11bInject(long id, long val); </code></pre>
<p><em>TODO: Enhance documentation</em></p>
<h2 id="misc-configurations">Misc Configurations</h2>
<h3
diff --git a/doc/GlueGen_Mapping.md b/doc/GlueGen_Mapping.md
index 1ab79b2..6453e64 100644
--- a/doc/GlueGen_Mapping.md
+++ b/doc/GlueGen_Mapping.md
@@ -40,7 +40,7 @@ GlueGen can produce native foreign function bindings to Java™ as well as
[map native data structures](#struct-mapping) to be fully accessible from Java™ including
potential calls to [embedded function pointer](#struct-function-pointer-support).
-GlueGen supports [registering Java™ callback methods](#java-callback-from-native-c-api-support)
+GlueGen supports [registering Java™ callback methods](#java-callback)
to receive asynchronous and off-thread native toolkit events,
where a generated native callback function dispatches the events to Java™.
@@ -299,7 +299,7 @@ A *Struct* may utilize the following data types for its fields
* See [*String Mapping*](#string-mapping) above.
* *Struct*, i.e. an aggregated or referenced compound variable
* *Function Pointer*, a *typedef*'ed and set callable function pointer, see [Struct Function-Pointer Support](#struct-function-pointer-support) below.
-* *Java Callback from Native Code*, see [section below](#java-callback-from-native-c-api-support)
+* *Java Callback from Native Code*, see [section below](#java-callback)
A field may be a direct aggregation, i.e. instance, within the struct including an array
or a reference to a single element or array via a pointer.
@@ -765,21 +765,58 @@ and similar to `T2_CustomFuncB customFuncB1`
public final int CustomFuncB1(T2_UserData pUserData) { .. }
```
-## Java Callback from Native C-API Support
+## Java Callback
GlueGen supports registering Java callback methods
to receive asynchronous and off-thread native toolkit events,
where a generated native callback function dispatches the events to Java.
-### Required *LibraryOnLoad*
-Note that [`LibraryOnLoad Bindingtest2`](#libraryonload-librarybasename-for-jni_onload-) must be specified in exactly one native code-unit.
-It provides code to allow the generated native callback-function to attach the current thread to the `JavaVM*` generating a new `JNIEnv*`in daemon mode -
-or just to retrieve the thread's `JNIEnv*`, if already attached to the `JavaVM*`.
+### Implementation Details
+Implementation generates a static Java callback dispatcher for each defined `SetCallbackFunction`, which gets invoked by the generated native static counterpart with all arguments required.
+
+The *static callback* utilizes its own synchronization for thread-safety and fetches the required data set stored at `SetCallbackFunction` to dispatch the call to the users' `CallbackFunction`.
+In case the callback has been removed already, the *static callback* simply bails out quietly.
+
+The native code does not create, release or manage heap memory and therefore is considered safe.
+
+### *JavaCallback* *UserParam* Mapping
+Usually the same `UserParam` type is used in both items (or hooks), `SetCallbackFunctionName` and `CallbackFunctionType`,
+which we call a homogeneous `UserParam` mapping.
+
+Even in a homogeneous `UserParam` mapping, handling of the `UserParam` value might differ in the native binding code.
+
+To specify a non homogeneous `UserParam` mapping, i.e. heterogeneous `UserParam` mapping,
+the `UserParam` index of the `SetCallbackFunction` must be [set in the configuration](#javacallback-configuration).
+
+The following mappings are supported.
+
+#### Pure Java Object User Type (default)
+A pure Java *Object type* is used for both, `SetCallbackFunctionName` and `CallbackFunctionType`.
+
+It's a homogeneous `UserParam` mapping, where the native side receives a simple unique ID and shall not dereference the *pointer*.
+
+The static Java callback dispatcher fetches the Java `UserParam` *Object* from the key-mapped data value.
+
+#### Struct Type User Param (Homogeneous)
+A [GlueGen generated *Struct type*](#struct-mapping) is used for both, `SetCallbackFunctionName` and `CallbackFunctionType`.
+
+It's a homogeneous `UserParam` mapping, where the native side receives the actual native struct address.
+
+The static Java callback dispatcher dereferences the received native struct address (*long*), i.e. rebuilding the *struct Object* to be passed to the users' `CallbackFunction`.
+
+#### Struct Type User Param (Heterogeneous)
+An anonymous pointer (*long*) for `SetCallbackFunctionName` and a [GlueGen generated *struct type*](#struct-mapping) for `CallbackFunctionType` is being used.
+
+It's a heterogeneous `UserParam` mapping, where the toolkit is expected to place the given anonymous pointer inside the defined *struct type* passed to the `CallbackFunction`.
+
+The `SetCallback-UserParamIndex` for the different parameter-type is [set in the configuration](#javacallback-configuration).
+
+The static Java callback dispatcher dereferences the received native struct address (*long*), i.e. rebuilding the *struct Object* to be passed to the users' `CallbackFunction`.
### *JavaCallback* Configuration
Configuration directives are as follows:
- JavaCallbackDef <SetCallbackFunctionName> <CallbackFunctionType> <CallbackFunction-UserParamIndex> [<SetCallback-KeyClassName>]
+ JavaCallbackDef <SetCallbackFunctionName> [<SetCallback-UserParamIndex>] <CallbackFunctionType> <CallbackFunction-UserParamIndex> [<SetCallback-KeyClassName>]
JavaCallbackKey <SetCallbackFunctionName> (SetCallback-ParamIdx)*
`JavaCallbackDef` and `JavaCallbackKey` use the name of the `SetCallbackFunction` as its first attribute,
@@ -787,6 +824,7 @@ as it is core to the semantic mapping of all resources.
`JavaCallbackDef` attributes:
- `SetCallbackFunction`: `SetCallbackFunction` name of the native toolkit API responsible to set the callback
+- `SetCallback-UserParamIndex`: Optional `UserParam` parameter-index of the `SetCallbackFunction`, allowing to [indicate a heterogeneous `UserParam`](#struct-type-user-param-heterogeneous)
- `CallbackFunctionType`: The native toolkit API typedef-name of the function-pointer-type, aka the callback type name
- `CallbackFunction-UserParamIndex`: The `userParam` parameter-index of the `CallbackFunctionType`
- `SetCallback-KeyClassName`: Name of an optional user-implemented `SetCallback-KeyClass`, providing the hash-map-key - see below
@@ -811,7 +849,24 @@ Key arguments must match in `SetCallbackFunction` to remove a previously set `Ca
- `SetCallbackFunction`: `SetCallbackFunction` name of the native toolkit API responsible to set the callback
- `SetCallback-ParamIdx`: List of parameter indices of the `SetCallbackFunction`, denoting the key(s) limiting the callback scope, i.e. the callback and all resources will be mapped to this key. The optional `SetCallback-KeyClass` may override this semantic.
-#### *JavaCallback* Generated Interfaces, Classes and Methods
+#### Custom `SetCallback-KeyClass`
+
+The `SetCallback-KeyClass` is the optional user-written hash-map-key definition
+and shall handle all key parameter of the `SetCallbackFunction` as defined via `JavaCallbackKey`, see above.
+
+`SetCallback-KeyClass` may be used to add external key-components, e.g. current-thread or a toolkit dependent context.
+
+The `SetCallback-KeyClass` shall implement the following hash-map-key standard methods
+- `boolean equals(Object)`
+- `int hashCode()`
+- `SetCallback-KeyClassName(...)` constructor receiving all key parameter of `SetCallbackFunction` as defined via `JavaCallbackKey`, see above.
+
+#### Required *LibraryOnLoad*
+Note that [`LibraryOnLoad Bindingtest2`](#libraryonload-librarybasename-for-jni_onload-) must be specified in exactly one native code-unit.
+It provides code to allow the generated native callback-function to attach the current thread to the `JavaVM*` generating a new `JNIEnv*`in daemon mode -
+or just to retrieve the thread's `JNIEnv*`, if already attached to the `JavaVM*`.
+
+### *JavaCallback* Generated Interfaces, Classes and Methods
The public `CallbackFunction` interface is generated.
@@ -838,19 +893,6 @@ If no `SetCallback-KeyClass` is used, the additional *maintenance* methods are:
Note that the *release`SetCallbackFunctionName`(\*)* and *releaseAll`SetCallbackFunctionName`()* methods are not the *proper toolkit API way* to remove the callback,
try to use original `SetCallbackFunctionName` API method instead using a `null` `CallbackFunction` reference.
-#### Custom `SetCallback-KeyClass`
-
-The `SetCallback-KeyClass` is the optional user-written hash-map-key definition
-and shall handle all key parameter of the `SetCallbackFunction` as defined via `JavaCallbackKey`, see above.
-
-`SetCallback-KeyClass` may be used to add external key-components, e.g. current-thread or a toolkit dependent context.
-
-The `SetCallback-KeyClass` shall implement the following hash-map-key standard methods
-- `boolean equals(Object)`
-- `int hashCode()`
-- `SetCallback-KeyClassName(...)` constructor receiving all key parameter of `SetCallbackFunction` as defined via `JavaCallbackKey`, see above.
-
-
### *JavaCallback* Notes
Please consider the following *currently enabled* constraints using JavaCallback
- Only one interface callback-method binding is allowed for a native callback function, e.g. `T2_CallbackFunc01` (see above)
@@ -866,7 +908,7 @@ Please consider the following *currently enabled* constraints using JavaCallback
- ...
### JavaCallback Example 1
-This is a generic example.
+This examples demonstrates a [homogeneous *Java Object* `UserParam` mapping](#pure-java-object-user-type-default) with a [globally scoped](#javacallback-key-definition) `CallbackFunction` and `UserParam`.
The callback `T2_CallbackFunc01` has global scope, i.e. is not mapped to any key and can be only set globally.
@@ -941,6 +983,8 @@ public interface Bindingtest2 {
### JavaCallback Example 2a (Default *KeyClass*)
+This examples demonstrates a [homogeneous *Java Object* `UserParam` mapping](#pure-java-object-user-type-default) with a [key-mapped](#javacallback-key-definition) `CallbackFunction` and `UserParam`.
+
This examples is derived from OpenAL's `AL_SOFT_callback_buffer` extension.
The callback `ALBUFFERCALLBACKTYPESOFT` is mapped to `buffer` name, i.e. one callback can be set for each buffer.
@@ -1040,6 +1084,8 @@ leading to the following interface
### JavaCallback Example 2b (Custom *KeyClass*)
+This examples demonstrates a [homogeneous *Java Object* `UserParam` mapping](#pure-java-object-user-type-default) with a [custom *KeyClass*](#custom-setcallback-keyclass) to map `CallbackFunction` and `UserParam`.
+
Same as example 2a, but implementing a custom `SetCallback-KeyClass`.
Instead of `Callback0`, the unit `test2.*` uses `Callback1` to differentiate this case.
@@ -1080,6 +1126,141 @@ which uses one key, i.e. `buffer`.
}
```
+### JavaCallback Example 11a (*Homogeneous Struct Type*)
+
+This examples demonstrates a [homogeneous *Struct* `UserParam` mapping](#struct-type-user-param-homogeneous) with a [key-mapped](#javacallback-key-definition) `CallbackFunction` and `UserParam`.
+
+The callback `T2_CallbackFunc11` is passed by the toolkit to the `CallbackFunction` and by the user to the registration method `MessageCallback11b(..)`.
+
+C-API Header snipped
+```
+ typedef struct {
+ int32_t ApiVersion;
+ void* Data;
+ long i;
+ long r;
+ size_t id;
+ } T2_Callback11UserType;
+
+ typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam, long val);
+
+ void MessageCallback11a(size_t id /* key */, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam);
+ void MessageCallback11aInject(size_t id, long val);
+```
+
+and the following GlueGen configuration
+```
+ JavaCallbackDef MessageCallback11a T2_CallbackFunc11 1
+ JavaCallbackKey MessageCallback11a 0
+```
+
+leading to the following interface
+```
+ /** JavaCallback interface: T2_CallbackFunc11 -> void (*T2_CallbackFunc11)(size_t id, const T2_Callback11UserType * usrParam, long val) */
+ public static interface T2_CallbackFunc11 {
+ /** Interface to C language function: <br> <code>void callback(size_t id, const T2_Callback11UserType * usrParam, long val)</code><br>Alias for: <code>T2_CallbackFunc11</code> */
+ public void callback(long id, T2_Callback11UserType usrParam, long val);
+ }
+
+ ...
+
+ public static class MessageCallback11aKey { ... }
+
+ ...
+
+ /** Returns set of Key { long id } for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
+ public Set<MessageCallback11aKey> getMessageCallback11aKeys();
+
+ /** Returns whether callback Key { long id } is mapped for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
+ public boolean isMessageCallback11aMapped(MessageCallback11aKey key);
+
+ /** Returns T2_CallbackFunc11 callback mapped to Key { long id } for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
+ public T2_CallbackFunc11 getMessageCallback11a(MessageCallback11aKey key);
+
+ /** Returns user-param mapped to Key { long id } for <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
+ public Object getMessageCallback11aUserParam(MessageCallback11aKey key);
+
+ /** Releases all callback data mapped via Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
+ public int releaseAllMessageCallback11a();
+
+ /** Releases callback data mapped to Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam)</code> */
+ public void releaseMessageCallback11a(MessageCallback11aKey key);
+
+ /** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11a(size_t id, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType * usrParam)</code><br> */
+ public void MessageCallback11a(long id, T2_CallbackFunc11 cbFunc, T2_Callback11UserType usrParam);
+
+ /** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11aInject(size_t id, long val)</code><br> */
+ public void MessageCallback11aInject(long id, long val);
+```
+
+### JavaCallback Example 11b (*Heterogeneous Pointer/Struct Type*)
+
+This examples demonstrates a [heterogeneous *Struct* `UserParam` mapping](#struct-type-user-param-heterogeneous) with a [key-mapped](#javacallback-key-definition) `CallbackFunction` and `UserParam`.
+
+The callback `T2_CallbackFunc11` is managed by the toolkit and passed to the callback function, while user passes a *void* with the registration method `MessageCallback11b(..)`. The toolkit associates the users' `void*` pointer with the `T2_CallbackFunc11`.
+
+
+C-API Header snipped
+```
+ typedef struct {
+ int32_t ApiVersion;
+ void* Data;
+ long i;
+ long r;
+ size_t id;
+ } T2_Callback11UserType;
+
+ typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam, long val);
+
+ void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data);
+ void MessageCallback11bInject(size_t id, long val);
+```
+
+and the following GlueGen configuration
+```
+ JavaCallbackDef MessageCallback11b 2 T2_CallbackFunc11 1
+ JavaCallbackKey MessageCallback11b 0
+```
+
+leading to the following interface
+```
+ /** JavaCallback interface: T2_CallbackFunc11 -> void (*T2_CallbackFunc11)(size_t id, const T2_Callback11UserType * usrParam, long val) */
+ public static interface T2_CallbackFunc11 {
+ /** Interface to C language function: <br> <code>void callback(size_t id, const T2_Callback11UserType * usrParam, long val)</code><br>Alias for: <code>T2_CallbackFunc11</code> */
+ public void callback(long id, T2_Callback11UserType usrParam, long val);
+ }
+
+ ...
+
+ public static class MessageCallback11bKey { ... }
+
+ ...
+
+ /** Returns set of Key { long id } for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
+ public Set<MessageCallback11bKey> getMessageCallback11bKeys();
+
+ /** Returns whether callback Key { long id } is mapped for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
+ public boolean isMessageCallback11bMapped(MessageCallback11bKey key);
+
+ /** Returns T2_CallbackFunc11 callback mapped to Key { long id } for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
+ public T2_CallbackFunc11 getMessageCallback11b(MessageCallback11bKey key);
+
+ /** Returns user-param mapped to Key { long id } for <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
+ public Object getMessageCallback11bUserParam(MessageCallback11bKey key);
+
+ /** Releases all callback data mapped via Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
+ public int releaseAllMessageCallback11b();
+
+ /** Releases callback data mapped to Key { long id } skipping toolkit API. Favor passing `null` callback ref to <br> <code> void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data)</code> */
+ public void releaseMessageCallback11b(MessageCallback11bKey key);
+
+ /** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11b(size_t id, T2_CallbackFunc11 cbFunc, void * Data)</code><br> */
+ public void MessageCallback11b(long id, T2_CallbackFunc11 cbFunc, long Data);
+
+ /** Entry point (through function pointer) to C language function: <br> <code>void MessageCallback11bInject(size_t id, long val)</code><br> */
+ public void MessageCallback11bInject(long id, long val);
+```
+
*TODO: Enhance documentation*
## Misc Configurations
diff --git a/src/java/com/jogamp/gluegen/CCodeUnit.java b/src/java/com/jogamp/gluegen/CCodeUnit.java
index c70df79..5c0db27 100644
--- a/src/java/com/jogamp/gluegen/CCodeUnit.java
+++ b/src/java/com/jogamp/gluegen/CCodeUnit.java
@@ -84,11 +84,6 @@ public class CCodeUnit extends CodeUnit {
emitln( getJNIOnLoadJNIEnvCode(libraryBasename) );
}
- /** Emits {@link #JavaCallbackGlueDataDecl}. */
- public void emitJavaCallbackGlueDataDecl() {
- emitln( JavaCallbackGlueDataDecl );
- }
-
@Override
public String toString() { return "CCodeUnit[unit "+cUnitName+", file "+filename+"]"; }
@@ -113,16 +108,6 @@ public class CCodeUnit extends CodeUnit {
" return jbyteBuffer;\n"+
"}\n";
- /** JavaCallback Glue Data typedef struct */
- public static final String JavaCallbackGlueDataDecl =
- "typedef struct {\n"+
- " jobject lockObj;\n"+
- " jobject cbFunc;\n"+
- " jmethodID cbMethodID;\n"+
- " jobject userParam;\n"+
- "} T_JavaCallbackGlueData;\n"+
- "\n";
-
/**
* Returns native JNI declarations for `JavaVM* {libraryBasename}_jvmHandle`
* and `JVMUtil_GetJNIEnv(..)`.
diff --git a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
index 00cae13..9c7ed0b 100644
--- a/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/CMethodBindingEmitter.java
@@ -113,15 +113,11 @@ public class CMethodBindingEmitter extends FunctionEmitter {
protected static final String STRING_CHARS_PREFIX = "_strchars_";
- protected static final String T_JavaCallbackGlueData = "T_JavaCallbackGlueData";
-
// We need this in order to compute sizes of certain types
protected MachineDataInfo machDesc;
- private final JavaCallbackInfo javaCallback;
- private final String jcbNativeBasename;
- private final String jcbFriendlyBasename;
private final CMethodBindingEmitter jcbCMethodEmitter;
+ private final JavaCallbackEmitter javaCallbackEmitter;
/**
* Constructs an emitter for the specified binding, and sets a default
@@ -155,18 +151,17 @@ public class CMethodBindingEmitter extends FunctionEmitter {
this.forIndirectBufferAndArrayImplementation = forIndirectBufferAndArrayImplementation;
this.machDesc = machDesc;
- javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ final JavaCallbackInfo javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
if( null != javaCallback ) {
- jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.cbSimpleClazzName.replace("_", "") );
- jcbFriendlyBasename = javaCallback.setFuncName+"("+javaCallback.cbSimpleClazzName+")";
+ // jcbNativeBasename = CodeGenUtils.capitalizeString( javaCallback.setFuncName+javaCallback.cbSimpleClazzName.replace("_", "") );
jcbCMethodEmitter = new CMethodBindingEmitter(javaCallback.cbFuncBinding,
unit, javaPackageName, javaClassName, isOverloadedBinding,
isJavaMethodStatic, forImplementingMethodCall,
forIndirectBufferAndArrayImplementation, machDesc, configuration);
+ javaCallbackEmitter = new JavaCallbackEmitter(cfg, binding, javaCallback, null);
} else {
- jcbNativeBasename = null;
- jcbFriendlyBasename = null;
jcbCMethodEmitter = null;
+ javaCallbackEmitter = null;
}
setCommentEmitter(defaultCommentEmitter);
}
@@ -328,145 +323,25 @@ public class CMethodBindingEmitter extends FunctionEmitter {
*/
public final MachineDataInfo getMachineDataInfo() { return machDesc; }
- private static final boolean DEBUG_JAVACALLBACK = false;
-
@Override
- protected void emitReturnType() {
- if( null != javaCallback ) {
- LOG.log(INFO, "BindCFunc.R.JavaCallback: {0}: {1}", binding.getName(), javaCallback);
- final String staticCallbackName = "func"+jcbNativeBasename;
-
- final Type userParamType = javaCallback.cbFuncBinding.getCArgumentType(javaCallback.cbFuncUserParamIdx);
- final String userParamArgName = javaCallback.cbFuncBinding.getArgumentName(javaCallback.cbFuncUserParamIdx);
- final Type cReturnType = javaCallback.cbFuncBinding.getCReturnType();
- final JavaType jretType = javaCallback.cbFuncBinding.getJavaReturnType();
- unit.emitln();
- // javaCallback.cbFuncCEmitter.emitSignature();
- unit.emit("static "+cReturnType.getCName()+" "+staticCallbackName+"(");
- // javaCallback.cbFuncCEmitter.emitArguments();
- unit.emit(javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
- unit.emitln(") {");
- // javaCallback.cbFuncCEmitter.emitBody();
- {
- unit.emitln(" JNIEnv* env = JVMUtil_GetJNIEnv();");
- unit.emitln(" if( NULL == env ) {");
- if( !cReturnType.isVoid() ) {
- unit.emitln(" return 0;");
- } else {
- unit.emitln(" return;");
- }
- unit.emitln(" }");
- // javaCallback.cbFuncCEmitter.emitBodyVariableDeclarations();
- // javaCallback.cbFuncCEmitter.emitBodyUserVariableDeclarations();
- // javaCallback.cbFuncCEmitter.emitBodyVariablePreCallSetup();
- jcbCMethodEmitter.emitJavaCallbackBodyCToJavaPreCall(javaCallback);
-
- // javaCallback.cbFuncCEmitter.emitBodyCallCFunction();
- unit.emitln(" "+T_JavaCallbackGlueData+"* cb = ("+T_JavaCallbackGlueData+"*) "+userParamArgName+";");
- unit.emitln(" // C Params: "+javaCallback.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
- unit.emitln(" // J Params: "+javaCallback.cbFuncBinding.getJavaParameterList(new StringBuilder()).toString());
-
- final String returnStatement;
- if( !cReturnType.isVoid() ) {
- unit.emit(" "+cReturnType.getCName()+" _res = 0;");
- returnStatement = "return _res;";
- } else {
- returnStatement = "return;";
- }
- unit.emitln(" if( NULL == cb ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': NULL "+userParamArgName+", skipping!\\n\"); "+returnStatement+" }");
- unit.emitln();
- unit.emitln(" // Use-after-free of '*cb' possible up until after GetObjectRefType() check for a brief moment!");
- unit.emitln(" // Use a copy to avoid data-race between GetObjectRefType() and MonitorEnter()\");");
- unit.emitln(" jobject lockObj = cb->lockObj;");
- unit.emitln(" if( 0 == lockObj ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': NULL lock, skipping!\\n\"); "+returnStatement+" }");
- unit.emitln();
- unit.emitln(" jobjectRefType refType = (*env)->GetObjectRefType(env, lockObj);");
- unit.emitln(" if( 0 == refType ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': User after free(lock), skipping!\\n\"); "+returnStatement+" }");
- unit.emitln(" jint lockRes = (*env)->MonitorEnter(env, lockObj);");
- unit.emitln(" if( 0 != lockRes ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': MonitorEnter failed %d, skipping!\\n\", lockRes); "+returnStatement+" }");
- unit.emitln(" // synchronized block");
- /**
- * Since we have acquired the lock, in-sync w/ our Java code, cb->cbFunc and cb->userParam could not have been changed!
- *
- unit.emitln(" refType = (*env)->GetObjectRefType(env, cb->userParam);");
- unit.emitln(" if( 0 == refType ) {");
- unit.emitln(" fprintf(stderr, \"Info: Callback '"+staticCallbackName+"(..)': User after free(userParam), skipping!\\n\");");
- unit.emitln(" lockRes = (*env)->MonitorExit(env, cb->lockObj);");
- unit.emitln(" if( 0 != lockRes ) { fprintf(stderr, \"Info: Callback '"+staticCallbackName+"(..)': MonitorExit failed %d\\n\", lockRes); }");
- unit.emitln(" "+returnStatement);
- unit.emitln(" }");
- */
- if( !cReturnType.isVoid() ) {
- unit.emit(" _res = ("+cReturnType.getCName()+") ");
- } else {
- unit.emit(" ");
- }
- unit.emit("(*env)->Call" + CodeGenUtils.capitalizeString( jretType.getName() ) +"Method(env, cb->cbFunc, cb->cbMethodID, ");
- // javaCallback.cbFuncCEmitter.emitBodyPassCArguments();
- jcbCMethodEmitter.emitJavaCallbackBodyPassJavaArguments(javaCallback, "cb->userParam");
- unit.emitln(");");
- unit.emitln(" if( (*env)->ExceptionCheck(env) ) {");
- unit.emitln(" fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': Exception in Java Callback caught:\\n\");");
- unit.emitln(" (*env)->ExceptionDescribe(env);");
- unit.emitln(" (*env)->ExceptionClear(env);");
- unit.emitln(" }");
-
- // javaCallback.cbFuncCEmitter.emitBodyUserVariableAssignments();
- // javaCallback.cbFuncCEmitter.emitBodyVariablePostCallCleanup();
- // javaCallback.cbFuncCEmitter.emitBodyMapCToJNIType(-1 /* return value */, true /* addLocalVar */)
-
- unit.emitln(" lockRes = (*env)->MonitorExit(env, cb->lockObj);");
- unit.emitln(" if( 0 != lockRes ) { fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': MonitorExit failed %d\\n\", lockRes); }");
- unit.emitln(" "+returnStatement);
- }
- unit.emitln("}");
- unit.emitln();
- }
- unit.emit("JNIEXPORT ");
- unit.emit(binding.getJavaReturnType().jniTypeName());
- unit.emit(" JNICALL");
- }
- /* pp */ int emitJavaCallbackBodyCToJavaPreCall(final JavaCallbackInfo jcbi) {
- int count = 0;
- for (int i = 0; i < binding.getNumArguments(); i++) {
- if( i == jcbi.cbFuncUserParamIdx ) {
- continue;
- }
- if( emitBodyMapCToJNIType(i, true /* addLocalVar */) ) {
- ++count;
- }
- }
- return count;
- }
- /* pp */ int emitJavaCallbackBodyPassJavaArguments(final JavaCallbackInfo jcbi, final String userParamVarName) {
- int count = 0;
- boolean needsComma = false;
- for (int i = 0; i < binding.getNumArguments(); i++) {
- if (needsComma) {
- unit.emit(", ");
- needsComma = false;
- }
- if( i == jcbi.cbFuncUserParamIdx ) {
- unit.emit( userParamVarName );
- } else {
- unit.emit( binding.getArgumentName(i) + "_jni" );
- }
- needsComma = true;
- ++count;
- }
- return count;
+ protected StringBuilder appendReturnType(final StringBuilder buf) {
+ buf.append("JNIEXPORT ");
+ buf.append(binding.getJavaReturnType().jniTypeName());
+ buf.append(" JNICALL");
+ return buf;
}
@Override
- protected void emitName() {
- unit.emitln(); // start name on new line
- unit.emit(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
- unit.emit("_");
+ protected StringBuilder appendName(final StringBuilder buf) {
+ buf.append(System.lineSeparator()); // start name on new line
+ buf.append(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
+ buf.append("_");
if (isOverloadedBinding) {
- unit.emit(jniMangle(binding));
+ buf.append(jniMangle(binding));
} else {
- unit.emit(JavaEmitter.jniMangle(getImplName()));
+ buf.append(JavaEmitter.jniMangle(getImplName()));
}
+ return buf;
}
protected String getImplSuffix() {
@@ -481,24 +356,24 @@ public class CMethodBindingEmitter extends FunctionEmitter {
}
@Override
- protected int emitArguments() {
- unit.emit("JNIEnv *env, ");
+ protected int appendArguments(final StringBuilder buf) {
+ buf.append("JNIEnv *env, ");
int numEmitted = 1; // initially just the JNIEnv
if (isJavaMethodStatic && !binding.hasContainingType()) {
- unit.emit("jclass");
+ buf.append("jclass");
} else {
- unit.emit("jobject");
+ buf.append("jobject");
}
- unit.emit(" _unused");
+ buf.append(" _unused");
++numEmitted;
if( binding.isReturnCompoundByValue() ) {
- unit.emit(", jclass _clazzBuffers");
+ buf.append(", jclass _clazzBuffers");
++numEmitted;
}
if (binding.hasContainingType()) {
// "this" argument always comes down in argument 0 as direct buffer
- unit.emit(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
+ buf.append(", jobject " + JavaMethodBindingEmitter.javaThisArgumentName());
}
for (int i = 0; i < binding.getNumArguments(); i++) {
final JavaType javaArgType = binding.getJavaArgumentType(i);
@@ -512,91 +387,47 @@ public class CMethodBindingEmitter extends FunctionEmitter {
if (javaArgType.isJNIEnv() || binding.isArgumentThisPointer(i)) {
continue;
}
- unit.emit(", ");
- unit.emit(javaArgType.jniTypeName());
- unit.emit(" ");
- unit.emit(binding.getArgumentName(i));
+ buf.append(", ");
+ buf.append(javaArgType.jniTypeName());
+ buf.append(" ");
+ buf.append(binding.getArgumentName(i));
++numEmitted;
if (javaArgType.isPrimitiveArray() ||
javaArgType.isNIOBuffer()) {
- unit.emit(", jint " + byteOffsetArgName(i));
+ buf.append(", jint " + byteOffsetArgName(i));
if(forIndirectBufferAndArrayImplementation) {
- unit.emit(", jboolean " + isNIOArgName(i));
+ buf.append(", jboolean " + isNIOArgName(i));
}
} else if (javaArgType.isNIOBufferArray()) {
- unit.emit(", jintArray " +
+ buf.append(", jintArray " +
byteOffsetArrayArgName(i));
}
}
- final JavaCallbackInfo jcb = this.javaCallback;
- if( null != jcb ) {
- LOG.log(INFO, "BindCFunc.A.JavaCallback: {0}: {1}", binding.getName(), jcb);
- unit.emit(", jstring jcallbackSignature, jobject jlockObj, jlongArray jnativeUserParam");
- numEmitted+=2;
- } else {
- LOG.log(INFO, "BindCFunc.JavaCallback: {0}: NONE", binding.getName());
+ if( null != javaCallbackEmitter ) {
+ numEmitted += javaCallbackEmitter.appendCAdditionalParameter(buf);
}
return numEmitted;
}
@Override
+ protected void emitAdditionalCode() {
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitCAdditionalCode(unit, jcbCMethodEmitter);
+ }
+ }
+
+ @Override
protected void emitBody() {
unit.emitln(" {");
// unit().emitln("printf(\" - - - - "+ getName() + getImplSuffix() +" - - - -\\n\");");
emitBodyVariableDeclarations();
emitBodyUserVariableDeclarations();
emitBodyVariablePreCallSetup();
- final JavaCallbackInfo jcb = this.javaCallback;
- if( null != jcb ) {
- LOG.log(INFO, "BindCFunc.B.JavaCallback: {0}: {1}", binding.getName(), jcb);
- final String cbFuncArgName = binding.getArgumentName(jcb.setFuncCBParamIdx);
- final String userParamArgName = binding.getArgumentName(jcb.setFuncUserParamIdx);
- final String nativeCBFuncVarName = cbFuncArgName+"_native";
- final String nativeUserParamVarName = userParamArgName+"_native";
- unit.emitln();
- unit.emitln(" // JavaCallback handling");
- unit.emitln(" "+jcb.cbFuncTypeName+" "+nativeCBFuncVarName+";");
- unit.emitln(" "+T_JavaCallbackGlueData+"* "+nativeUserParamVarName+";");
- // unit.emit(", jstring jcallbackSignature, jobject jlockObj, jlongArray jnativeUserParam");
- unit.emitln(" if( NULL == jlockObj ) { (*env)->FatalError(env, \"Null jlockObj in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" if( NULL == jnativeUserParam ) { (*env)->FatalError(env, \"Null jnativeUserParam in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" const size_t jnativeUserParam_size = (*env)->GetArrayLength(env, jnativeUserParam);");
- unit.emitln(" if( 1 > jnativeUserParam_size ) { (*env)->FatalError(env, \"nativeUserParam size < 1 in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" if( NULL != "+cbFuncArgName+" ) {");
- unit.emitln(" if( NULL == "+userParamArgName+" ) { (*env)->FatalError(env, \"Null "+userParamArgName+" in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+" = ("+T_JavaCallbackGlueData+"*) calloc(1, sizeof("+T_JavaCallbackGlueData+"));");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+" ) { (*env)->FatalError(env, \"Can't alloc "+nativeUserParamVarName+" in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->lockObj = (*env)->NewGlobalRef(env, jlockObj);");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->lockObj ) { (*env)->FatalError(env, \"Failed NewGlobalRef(lock) in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->cbFunc = (*env)->NewGlobalRef(env, "+cbFuncArgName+");");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->cbFunc ) { (*env)->FatalError(env, \"Failed NewGlobalRef(func) in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->userParam = (*env)->NewGlobalRef(env, "+userParamArgName+");");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->userParam ) { (*env)->FatalError(env, \"Failed NewGlobalRef(userParam) in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" {");
- unit.emitln(" jclass cbClazz = (*env)->GetObjectClass(env, "+nativeUserParamVarName+"->cbFunc);");
- unit.emitln(" if( NULL == cbClazz ) { (*env)->FatalError(env, \"Failed GetObjectClass in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" const char* callbackSignature = (*env)->GetStringUTFChars(env, jcallbackSignature, (jboolean*)NULL);");
- unit.emitln(" if( NULL == callbackSignature ) { (*env)->FatalError(env, \"Failed callbackSignature in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" "+nativeUserParamVarName+"->cbMethodID = (*env)->GetMethodID(env, cbClazz, \"callback\", callbackSignature);");
- unit.emitln(" (*env)->ReleaseStringUTFChars(env, jcallbackSignature, callbackSignature);");
- unit.emitln(" if( NULL == "+nativeUserParamVarName+"->cbMethodID ) { (*env)->FatalError(env, \"Failed GetMethodID in '"+jcbFriendlyBasename+"'\"); }");
- unit.emitln(" }");
- unit.emitln(" "+nativeCBFuncVarName+" = func"+jcbNativeBasename+";");
- unit.emitln(" } else {");
- unit.emitln(" "+nativeCBFuncVarName+" = NULL;");
- unit.emitln(" "+nativeUserParamVarName+" = NULL;");
- unit.emitln(" }");
- unit.emitln(" {");
- unit.emitln(" jlong v = (jlong) (intptr_t) "+nativeUserParamVarName+";");
- unit.emitln(" (*env)->SetLongArrayRegion(env, jnativeUserParam, 0, (jsize)1, &v);");
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" fprintf(stderr, \"YYY user %p -> native %p\\n\", "+userParamArgName+", "+nativeUserParamVarName+");");
- }
- unit.emitln(" }");
- unit.emitln();
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitCSetFuncPreCall(unit);
}
emitBodyCallCFunction();
emitBodyUserVariableAssignments();
@@ -606,24 +437,6 @@ public class CMethodBindingEmitter extends FunctionEmitter {
}
unit.emitln("}");
unit.emitln();
- if( null != jcb ) {
- final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
- unit.emitln("JNIEXPORT void JNICALL");
- unit.emit(JavaEmitter.getJNIMethodNamePrefix(getJavaPackageName(), getJavaClassName()));
- unit.emitln("_release"+capIfaceName+"Impl(JNIEnv *env, jobject _unused, jlong jnativeUserParam) {");
- unit.emitln(" // already locked");
- unit.emitln(" "+T_JavaCallbackGlueData+"* nativeUserParam = ("+T_JavaCallbackGlueData+"*) (intptr_t) jnativeUserParam;");
- unit.emitln(" if( NULL != nativeUserParam ) {");
- unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->lockObj);");
- unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->cbFunc);");
- unit.emitln(" (*env)->DeleteGlobalRef(env, nativeUserParam->userParam);");
- unit.emitln(" // Ensure even w/ use-after-free jobject refs are NULL and invalid to avoid accidental reuse.");
- unit.emitln(" memset(nativeUserParam, 0, sizeof("+T_JavaCallbackGlueData+"));");
- unit.emitln(" free(nativeUserParam);");
- unit.emitln(" }");
- unit.emitln("}");
- unit.emitln();
- }
}
protected void emitBodyVariableDeclarations() {
@@ -1173,9 +986,8 @@ public class CMethodBindingEmitter extends FunctionEmitter {
} else {
if (javaArgType.isString()) { unit.emit(STRING_CHARS_PREFIX); }
unit.emit(binding.getArgumentName(i));
- if( null != this.javaCallback &&
- ( i == this.javaCallback.setFuncCBParamIdx || i == this.javaCallback.setFuncUserParamIdx ) ) {
- unit.emit("_native");
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitCOptArgumentSuffix(unit, i);
}
}
}
@@ -1241,7 +1053,7 @@ public class CMethodBindingEmitter extends FunctionEmitter {
* @param addLocalVar if true, emit instantiating the local JNI variable.
* @return true if a non-void result has been produced, otherwise false
*/
- protected boolean emitBodyMapCToJNIType(final int argIdx, final boolean addLocalVar)
+ public boolean emitBodyMapCToJNIType(final int argIdx, final boolean addLocalVar)
{
// WARNING: this code assumes that the return type has already been
// typedef-resolved.
@@ -1436,12 +1248,11 @@ public class CMethodBindingEmitter extends FunctionEmitter {
final StringBuilder buf = new StringBuilder();
buf.append(JavaEmitter.jniMangle(getImplName()));
buf.append(getImplSuffix());
- if( null == this.javaCallback ) {
+ if( null == javaCallbackEmitter ) {
buf.append("__");
- getJNIMangledArgs(binding, forIndirectBufferAndArrayImplementation, buf);
- if( null != this.javaCallback ) {
- getJNIMangledArg(String.class, buf, false); // to account for the additional 'jstring jcallbackSignature' parameter
- getJNIMangledArg(long[].class, buf, false); // to account for the additional 'long[] nativeUserParam' parameter
+ appendJNIMangledArgs(binding, forIndirectBufferAndArrayImplementation, buf);
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.appendCAdditionalJNIDescriptor(buf);
}
}
return buf.toString();
@@ -1454,13 +1265,13 @@ public class CMethodBindingEmitter extends FunctionEmitter {
* @param buf
* @return
*/
- public static StringBuilder getJNIMangledArgs(final MethodBinding binding, final boolean forIndirectBufferAndArrayImplementation, final StringBuilder buf) {
+ public static StringBuilder appendJNIMangledArgs(final MethodBinding binding, final boolean forIndirectBufferAndArrayImplementation, final StringBuilder buf) {
if (binding.isReturnCompoundByValue()) {
- getJNIMangledArg(Class.class, buf, true);
+ JavaType.appendJNIDescriptor(buf, Class.class, true);
}
if (binding.hasContainingType()) {
// "this" argument always comes down in argument 0 as direct buffer
- getJNIMangledArg(java.nio.ByteBuffer.class, buf, true);
+ JavaType.appendJNIDescriptor(buf, java.nio.ByteBuffer.class, true);
}
for (int i = 0; i < binding.getNumArguments(); i++) {
if (binding.isArgumentThisPointer(i)) {
@@ -1477,31 +1288,31 @@ public class CMethodBindingEmitter extends FunctionEmitter {
} else {
Class<?> c = type.getJavaClass();
if (c != null) {
- getJNIMangledArg(c, buf, false);
+ JavaType.appendJNIDescriptor(buf, c, false);
// If Buffer offset arguments were added, we need to mangle the JNI for the
// extra arguments
if (type.isNIOBuffer()) {
- getJNIMangledArg(Integer.TYPE, buf, false);
+ JavaType.appendJNIDescriptor(buf, Integer.TYPE, false);
if(forIndirectBufferAndArrayImplementation) {
- getJNIMangledArg(Boolean.TYPE, buf, false);
+ JavaType.appendJNIDescriptor(buf, Boolean.TYPE, false);
}
} else if (type.isNIOBufferArray()) {
final int[] intArrayType = new int[0];
c = intArrayType.getClass();
- getJNIMangledArg(c , buf, true);
+ JavaType.appendJNIDescriptor(buf, c , true);
}
if (type.isPrimitiveArray()) {
- getJNIMangledArg(Integer.TYPE, buf, false);
+ JavaType.appendJNIDescriptor(buf, Integer.TYPE, false);
}
} else if (type.isNamedClass()) {
buf.append(type.getJNIMethodDesciptor());
} else if (type.isCompoundTypeWrapper()) {
// Mangle wrappers for C structs as ByteBuffer
- getJNIMangledArg(java.nio.ByteBuffer.class, buf, true);
+ JavaType.appendJNIDescriptor(buf, java.nio.ByteBuffer.class, true);
} else if (type.isArrayOfCompoundTypeWrappers()) {
// Mangle arrays of C structs as ByteBuffer[]
final java.nio.ByteBuffer[] tmp = new java.nio.ByteBuffer[0];
- getJNIMangledArg(tmp.getClass(), buf, true);
+ JavaType.appendJNIDescriptor(buf, tmp.getClass(), true);
} else if (type.isJNIEnv()) {
// These are not exposed at the Java level
} else {
@@ -1514,54 +1325,6 @@ public class CMethodBindingEmitter extends FunctionEmitter {
return buf;
}
- public static void getJNIMangledArg(final Class<?> c, final StringBuilder res, final boolean syntheticArgument) {
- if (c.isPrimitive()) {
- if (c == Boolean.TYPE) res.append("Z");
- else if (c == Byte.TYPE) res.append("B");
- else if (c == Character.TYPE) res.append("C");
- else if (c == Short.TYPE) res.append("S");
- else if (c == Integer.TYPE) res.append("I");
- else if (c == Long.TYPE) res.append("J");
- else if (c == Float.TYPE) res.append("F");
- else if (c == Double.TYPE) res.append("D");
- else throw new RuntimeException("Illegal primitive type \"" + c.getName() + "\"");
- } else {
- // Arrays and NIO Buffers are always passed down as java.lang.Object.
- // The only arrays that show up as true arrays in the signature
- // are the synthetic byte offset arrays created when passing
- // down arrays of direct Buffers. Compound type wrappers are
- // passed down as ByteBuffers (no good reason, just to avoid
- // accidental conflation) so we mangle them differently.
- if (syntheticArgument) {
- if (c.isArray()) {
- res.append("_3");
- final Class<?> componentType = c.getComponentType();
- // Handle arrays of compound type wrappers differently for
- // convenience of the Java-level glue code generation
- getJNIMangledArg(componentType, res,
- (componentType == java.nio.ByteBuffer.class));
- } else {
- res.append("L");
- res.append(c.getName().replace('.', '_'));
- res.append("_2");
- }
- } else {
- if (c.isArray()) {
- res.append("_3");
- getJNIMangledArg(c.getComponentType(), res, false);
- } else if (c == java.lang.String.class) {
- res.append("L");
- res.append(c.getName().replace('.', '_'));
- res.append("_2");
- } else {
- res.append("L");
- res.append("java_lang_Object");
- res.append("_2");
- }
- }
- }
- }
-
private void emitOutOfMemoryCheck(final String varName, final String errorMessage) {
unit.emitln(" if ( NULL == " + varName + " ) {");
unit.emitln(" (*env)->ThrowNew(env, (*env)->FindClass(env, \"java/lang/OutOfMemoryError\"),");
diff --git a/src/java/com/jogamp/gluegen/FunctionEmitter.java b/src/java/com/jogamp/gluegen/FunctionEmitter.java
index a089a41..5037fc4 100644
--- a/src/java/com/jogamp/gluegen/FunctionEmitter.java
+++ b/src/java/com/jogamp/gluegen/FunctionEmitter.java
@@ -114,6 +114,7 @@ public abstract class FunctionEmitter {
* Emit the function to the {@link #getUnit()}
*/
public final void emit() {
+ emitAdditionalCode();
emitDocComment();
//output.println(" // Emitter: " + getClass().getName());
emitSignature();
@@ -139,6 +140,7 @@ public abstract class FunctionEmitter {
*/
public CommentEmitter getCommentEmitter() { return commentEmitter; }
+ protected void emitAdditionalCode() { }
protected void emitDocComment() {
if (commentEmitter != null) {
@@ -154,32 +156,42 @@ public abstract class FunctionEmitter {
}
}
- protected void emitSignature() {
+ protected final void emitSignature() {
+ unit.emit(appendSignature(new StringBuilder()).toString());
+ }
- unit.emit(getBaseIndentString()); // indent method
+ protected StringBuilder appendSignature(final StringBuilder buf) {
+ buf.append(getBaseIndentString()); // indent method
- final int numEmitted = emitModifiers();
+ final int numEmitted = appendModifiers(buf);
if (numEmitted > 0) {
- unit.emit(" ");
+ buf.append(" ");
}
- emitReturnType();
- unit.emit(" ");
+ appendReturnType(buf);
+ buf.append(" ");
- emitName();
- unit.emit("(");
+ appendName(buf);
+ buf.append("(");
- emitArguments();
- unit.emit(")");
+ appendArguments(buf);
+ buf.append(")");
+ return buf;
}
- protected int emitModifiers() {
+ protected final int emitModifiers() {
+ final StringBuilder buf = new StringBuilder();
+ final int n = appendModifiers(buf);
+ unit.emit(buf.toString());
+ return n;
+ }
+ protected int appendModifiers(final StringBuilder buf) {
int numEmitted = 0;
for (final Iterator<EmissionModifier> it = getModifiers(); it.hasNext(); ) {
- unit.emit(it.next().toString());
+ buf.append(it.next().toString());
++numEmitted;
if (it.hasNext()) {
- unit.emit(" ");
+ buf.append(" ");
}
}
return numEmitted;
@@ -190,10 +202,23 @@ public abstract class FunctionEmitter {
protected String getCommentStartString() { return "/* "; }
protected String getCommentEndString() { return " */"; }
- protected abstract void emitReturnType();
- protected abstract void emitName();
+ protected final void emitReturnType() {
+ unit.emit(appendReturnType(new StringBuilder()).toString());
+ }
+ protected abstract StringBuilder appendReturnType(StringBuilder buf);
+ protected final void emitName() {
+ unit.emit(appendName(new StringBuilder()).toString());
+ }
+ protected abstract StringBuilder appendName(StringBuilder buf);
+ /** Returns the number of arguments emitted. */
+ protected final int emitArguments() {
+ final StringBuilder buf = new StringBuilder();
+ final int n = appendArguments(buf);
+ unit.emit(buf.toString());
+ return n;
+ }
/** Returns the number of arguments emitted. */
- protected abstract int emitArguments();
+ protected abstract int appendArguments(StringBuilder buf);
protected abstract void emitBody();
public static class EmissionModifier {
diff --git a/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
new file mode 100644
index 0000000..96e1e77
--- /dev/null
+++ b/src/java/com/jogamp/gluegen/JavaCallbackEmitter.java
@@ -0,0 +1,666 @@
+/**
+ * Copyright 2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.gluegen;
+
+import com.jogamp.gluegen.JavaConfiguration.JavaCallbackInfo;
+import com.jogamp.gluegen.cgram.types.Type;
+
+public final class JavaCallbackEmitter {
+ final JavaConfiguration cfg;
+ final MethodBinding binding;
+ final String setFuncSignature;
+ final JavaCallbackInfo info;
+ final String capIfaceName;
+ final String lowIfaceName;
+ final String lockInstanceName;
+ final String dataMapInstanceName;
+ final String dataInstanceName;
+ final String DataClassName;
+ final String fqUsrParamClassName;
+ final JavaType cbFuncJavaReturnType;
+ final String jcbNextIDVarName;
+
+ final String setFuncCBArgName;
+ final Type setFuncUserParamCType;
+ final JavaType setFuncUserParamJType;
+ final String setFuncUserParamTypeName;
+ final String setFuncUserParamArgName;
+
+ final boolean customKeyClass;
+ final String KeyClassName;
+ final boolean useDataMap;
+
+ public JavaCallbackEmitter(final JavaConfiguration cfg, final MethodBinding mb, final JavaCallbackInfo javaCallback, final String setFuncSignature) {
+ this.cfg = cfg;
+ this.binding = mb;
+ this.setFuncSignature = setFuncSignature;
+ this.info = javaCallback;
+
+ capIfaceName = CodeGenUtils.capitalizeString( mb.getInterfaceName() );
+ lowIfaceName = CodeGenUtils.decapitalizeString( mb.getInterfaceName() );
+ lockInstanceName = lowIfaceName+"Lock";
+ dataMapInstanceName = lowIfaceName+"DataMap";
+ dataInstanceName = lowIfaceName+"Data";
+ DataClassName = capIfaceName+"Data";
+ fqUsrParamClassName = cfg.packageName()+"."+cfg.className()+"."+DataClassName;
+ cbFuncJavaReturnType = javaCallback.cbFuncBinding.getJavaReturnType();
+ jcbNextIDVarName = "NEXT_"+capIfaceName+"_ID";
+
+ setFuncCBArgName = binding.getArgumentName(javaCallback.setFuncCBParamIdx);
+ setFuncUserParamCType = mb.getCArgumentType(javaCallback.setFuncUserParamIdx);
+ setFuncUserParamJType = mb.getJavaArgumentType(javaCallback.setFuncUserParamIdx);
+ setFuncUserParamTypeName = setFuncUserParamJType.getName();
+ setFuncUserParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
+
+ if( null != javaCallback.setFuncKeyClassName ) {
+ customKeyClass = true;;
+ KeyClassName = javaCallback.setFuncKeyClassName;
+ useDataMap = true;
+ } else {
+ customKeyClass = false;
+ KeyClassName = capIfaceName+"Key";
+ useDataMap = javaCallback.setFuncKeyIndices.size() > 0;
+ }
+ }
+
+ public void emitJavaSetFuncPreCall(final CodeUnit unit) {
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emit (" final long nativeUserParam = ");
+ if( setFuncUserParamJType.isLong() ) {
+ unit.emitln(" "+setFuncUserParamArgName+";");
+ } else if( setFuncUserParamJType.isCompoundTypeWrapper() ) {
+ unit.emitln(" null != "+setFuncUserParamArgName+" ? "+setFuncUserParamArgName+".getDirectBufferAddress() : 0;");
+ } else {
+ unit.emitln(""+jcbNextIDVarName+"++;");
+ unit.emitln(" if( 0 >= "+jcbNextIDVarName+" ) { "+jcbNextIDVarName+" = 1; }");
+ }
+ unit.emitln(" if( null != "+setFuncCBArgName+" ) {");
+ unit.emitln(" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, true).toString()+
+ "new "+DataClassName+"("+setFuncCBArgName+", "+setFuncUserParamArgName+"));");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+
+ public void emitJavaSetFuncPostCall(final CodeUnit unit) {
+ unit.emitln(" if( null == "+setFuncCBArgName+" ) {");
+ unit.emitln(" // callback released (null func) -> release a previously mapped instance ");
+ if( useDataMap ) {
+ unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" ) );");
+ } else {
+ unit.emitln(" release"+capIfaceName+"();");
+ }
+ unit.emitln(" }");
+ unit.emitln(" } // synchronized ");
+ }
+
+ public void emitJavaAdditionalCode(final CodeUnit unit, final boolean isInterface) {
+ if( isInterface ) {
+ if( useDataMap ) {
+ if( !customKeyClass && !info.keyClassEmitted ) {
+ emitJavaKeyClass(unit);
+ unit.emitln();
+ info.keyClassEmitted = true;
+ }
+ emitJavaBriefAPIDoc(unit, "Returns ", "set of ", "", "for ");
+ unit.emitln(" public Set<"+KeyClassName+"> get"+capIfaceName+"Keys();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public boolean is"+capIfaceName+"Mapped("+KeyClassName+" key);");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public "+info.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key);");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public Object get"+capIfaceName+"UserParam("+KeyClassName+" key);");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public int releaseAll"+capIfaceName+"();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public void release"+capIfaceName+"("+KeyClassName+" key);");
+ unit.emitln();
+ } else {
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public boolean is"+capIfaceName+"Mapped();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public "+info.cbFuncTypeName+" get"+capIfaceName+"();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public Object get"+capIfaceName+"UserParam();");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public void release"+capIfaceName+"();");
+ unit.emitln();
+ }
+ } else {
+ if( useDataMap ) {
+ if( !customKeyClass && !info.keyClassEmitted ) {
+ emitJavaKeyClass(unit);
+ unit.emitln();
+ info.keyClassEmitted = true;
+ }
+ emitJavaBriefAPIDoc(unit, "Returns ", "set of ", "", "for ");
+ unit.emitln(" public final Set<"+KeyClassName+"> get"+capIfaceName+"Keys() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" return "+dataMapInstanceName+".keySet();");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public final boolean is"+capIfaceName+"Mapped("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" return null != "+dataMapInstanceName+".get(key);");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public final "+info.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
+ unit.emitln(" return null != value ? value.func : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public final Object get"+capIfaceName+"UserParam("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
+ unit.emitln(" return null != value ? value.param : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public final int releaseAll"+capIfaceName+"() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final Set<"+KeyClassName+"> keySet = "+dataMapInstanceName+".keySet();");
+ unit.emitln(" final "+KeyClassName+"[] keys = keySet.toArray(new "+KeyClassName+"[keySet.size()]);");
+ unit.emitln(" for(int i=0; i<keys.length; ++i) {");
+ unit.emitln(" final "+KeyClassName+" key = keys[i];");
+ unit.emitln(" release"+capIfaceName+"(key);");
+ unit.emitln(" }");
+ unit.emitln(" return keys.length;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public final void release"+capIfaceName+"("+KeyClassName+" key) {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" /* final "+DataClassName+" value = */ "+dataMapInstanceName+".remove(key);");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ } else {
+ emitJavaBriefAPIDoc(unit, "Returns ", "whether callback ", "if callback ", "is mapped for ");
+ unit.emitln(" public final boolean is"+capIfaceName+"Mapped() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" return null != "+dataInstanceName+";");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns "+info.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
+ unit.emitln(" public final "+info.cbFuncTypeName+" get"+capIfaceName+"() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
+ unit.emitln(" return null != value ? value.func : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Returns user-param ", "mapped to ", "", "for ");
+ unit.emitln(" public final Object get"+capIfaceName+"UserParam() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
+ unit.emitln(" return null != value ? value.param : null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+
+ emitJavaBriefAPIDoc(unit, "Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
+ unit.emitln(" public final void release"+capIfaceName+"() {");
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ unit.emitln(" // final "+DataClassName+" value = "+dataInstanceName+";");
+ unit.emitln(" "+dataInstanceName+" = null;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+ unit.emitln(" private final void add"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, true).toString()+DataClassName+" value) {");
+ if( useDataMap ) {
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" /* final "+DataClassName+" old = */ "+dataMapInstanceName+".put(key, value);");
+ } else {
+ unit.emitln(" // final "+DataClassName+" old = "+dataInstanceName+";");
+ unit.emitln(" "+dataInstanceName+" = value;");
+ }
+ unit.emitln(" }");
+ unit.emitln();
+ if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) {
+ emitJavaDataClass(unit);
+ cfg.emittedJavaCallbackUserParamClasses.add(fqUsrParamClassName);
+ }
+ if( useDataMap ) {
+ unit.emitln(" private static final Map<"+KeyClassName+", "+DataClassName+"> "+dataMapInstanceName+" = new HashMap<"+KeyClassName+", "+DataClassName+">();");
+ } else {
+ unit.emitln(" private static "+DataClassName+" "+dataInstanceName+" = null;");
+ }
+ unit.emitln(" private static long "+jcbNextIDVarName+" = 1;");
+ unit.emitln(" private static final Object "+lockInstanceName+" = new Object();");
+ unit.emitln();
+ emitJavaStaticCallback(unit);
+ }
+ }
+
+ private final void emitJavaBriefAPIDoc(final CodeUnit unit, final String actionText, final String relationToKey, final String noKeyText, final String relationToFunc) {
+ unit.emit(" /** "+actionText);
+ if( info.setFuncKeyIndices.size() > 0 ) {
+ unit.emit(relationToKey);
+ unit.emit("Key { "+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, false).toString()+" } ");
+ } else {
+ unit.emit(noKeyText);
+ }
+ unit.emit(relationToFunc);
+ unit.emitln("<br> <code>"+setFuncSignature+"</code> */");
+ }
+
+ private final void emitJavaKeyClass(final CodeUnit unit) {
+ emitJavaBriefAPIDoc(unit, "", "", "", "for ");
+ unit.emitln(" public static class "+KeyClassName+" {");
+ binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && info.setFuncKeyIndices.contains(idx) ) {
+ unit.emitln(" public final "+jType+" "+name+";");
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(" public "+KeyClassName+"("+binding.getJavaSelectParameter(new StringBuilder(), info.setFuncKeyIndices, false).toString()+") {");
+ binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && info.setFuncKeyIndices.contains(idx) ) {
+ unit.emitln(" this."+name+" = "+name+";");
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(" }");
+ unit.emitln(" @Override");
+ unit.emitln(" public boolean equals(final Object o) {");
+ unit.emitln(" if( this == o ) {");
+ unit.emitln(" return true;");
+ unit.emitln(" }");
+ unit.emitln(" if( !(o instanceof "+KeyClassName+") ) {");
+ unit.emitln(" return false;");
+ unit.emitln(" }");
+ {
+ final int count = binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && info.setFuncKeyIndices.contains(idx) ) {
+ if( 0 == consumedCount ) {
+ unit.emitln(" final "+KeyClassName+" o2 = ("+KeyClassName+")o;");
+ unit.emit (" return ");
+ } else {
+ unit.emitln(" &&");
+ unit.emit (" ");
+ }
+ if( jType.isPrimitive() || idx == info.setFuncUserParamIdx ) {
+ unit.emit(name+" == o2."+name);
+ } else {
+ unit.emit(name+".equals( o2."+name+" )");
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ if( 0 == count ) {
+ unit.emit(" return true");
+ }
+ unit.emitln(";");
+ }
+ unit.emitln(" }");
+ unit.emitln(" @Override");
+ unit.emitln(" public int hashCode() {");
+ {
+ final int count = binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() && info.setFuncKeyIndices.contains(idx) ) {
+ if( 0 == consumedCount ) {
+ unit.emitln(" // 31 * x == (x << 5) - x");
+ unit.emit (" int hash = ");
+ } else {
+ unit.emit (" hash = ((hash << 5) - hash) + ");
+ }
+ if( jType.isPrimitive() ) {
+ if( jType.isLong() ) {
+ unit.emitln("HashUtil.getAddrHash32_EqualDist( "+name+" );");
+ } else {
+ unit.emitln(name+";");
+ }
+ } else {
+ if( idx == info.setFuncUserParamIdx ) {
+ unit.emitln("System.identityHashCode( "+name+" );");
+ } else {
+ unit.emitln(name+".hashCode();");
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ if( 0 == count ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return hash;");
+ }
+ }
+ unit.emitln(" }");
+ unit.emitln(" }");
+ }
+
+ private final void emitJavaDataClass(final CodeUnit unit) {
+ unit.emitln(" private static class "+DataClassName+" {");
+ unit.emitln(" // userParamArgCType "+setFuncUserParamCType);
+ unit.emitln(" // userParamArgJType "+setFuncUserParamJType);
+ unit.emitln(" final "+info.cbFuncTypeName+" func;");
+ unit.emitln(" final "+setFuncUserParamTypeName+" param;");
+ unit.emitln(" "+DataClassName+"("+info.cbFuncTypeName+" func, "+setFuncUserParamTypeName+" param) {");
+ unit.emitln(" this.func = func;");
+ unit.emitln(" this.param = param;");
+ unit.emitln(" }");
+ unit.emitln(" }");
+ }
+
+ public final String getJavaStaticCallbackSignature() {
+ final StringBuilder buf = new StringBuilder();
+ buf.append("(");
+ info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() ) {
+ if( idx == info.cbFuncUserParamIdx ) {
+ buf.append("J");
+ } else {
+ buf.append(jType.getDescriptor());
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ buf.append(")");
+ buf.append(cbFuncJavaReturnType.getDescriptor());
+ return buf.toString();
+ }
+
+ public final int appendJavaAdditionalJNIParameter(final StringBuilder buf) {
+ buf.append("Class<?> clazz, String callbackSignature, long nativeUserParam");
+ return 3;
+ }
+ public final int appendJavaAdditionalJNIArguments(final StringBuilder buf) {
+ buf.append("this.getClass(), \"" + getJavaStaticCallbackSignature()+ "\", nativeUserParam");
+ return 3;
+ }
+ private final void emitJavaStaticCallback(final CodeUnit unit) {
+ unit.emitln(" /** Static callback invocation, dispatching to "+info.cbSimpleClazzName+" for callback <br> <code>"+
+ info.cbFuncType.toString(info.cbFuncTypeName, false, true)+"</code> */");
+ unit.emit (" /* pp */ static "+cbFuncJavaReturnType.getName()+" invoke"+capIfaceName+"(");
+ final boolean[] mapNativePtrToCompound = { false };
+ final JavaType[] origUserParamJType = { null };
+ info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() ) {
+ if( 0 < consumedCount ) { unit.emit(", "); }
+ if( idx == info.cbFuncUserParamIdx ) {
+ unit.emit("long nativeUserParamPtr");
+ if( jType.isCompoundTypeWrapper() ) {
+ mapNativePtrToCompound[0] = true;
+ origUserParamJType[0] = jType;
+ }
+ } else {
+ unit.emit(jType+" "+name);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(") {");
+ if( mapNativePtrToCompound[0] ) {
+ unit.emitln(" final "+origUserParamJType[0]+" "+info.cbFuncUserParamName+" = "+origUserParamJType[0]+".derefPointer(nativeUserParamPtr);");
+ }
+ if( useDataMap ) {
+ unit.emitln(" final "+DataClassName+" value;");
+ } else {
+ unit.emitln(" final "+DataClassName+" value;");
+ }
+ unit.emitln(" synchronized( "+lockInstanceName+" ) {");
+ if( useDataMap ) {
+ unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), info.setFuncKeyIndices, false).toString()+");");
+ unit.emitln(" value = "+dataMapInstanceName+".get(key);");
+ } else {
+ unit.emitln(" value = "+dataInstanceName+";");
+ }
+ unit.emitln(" }");
+ unit.emitln(" if( null == value ) {");
+ if( !cbFuncJavaReturnType.isVoid() ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return;");
+ }
+ unit.emitln(" }");
+ if( !cbFuncJavaReturnType.isVoid() ) {
+ unit.emit(" return ");
+ } else {
+ unit.emit(" ");
+ }
+ unit.emit("value.func.callback(");
+ info.cbFuncBinding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
+ if( !cType.isVoid() ) {
+ if( 0 < consumedCount ) { unit.emit(", "); }
+ if( idx == info.cbFuncUserParamIdx && !mapNativePtrToCompound[0] ) {
+ unit.emit("value.param");
+ } else {
+ unit.emit(name);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ } );
+ unit.emitln(");");
+ unit.emitln(" }");
+ unit.emitln();
+ }
+
+ //
+ // C JNI Code ..
+ //
+
+ public int appendCAdditionalParameter(final StringBuilder buf) {
+ buf.append(", jclass clazz, jstring jcallbackSignature, jlong jnativeUserParam");
+ return 3;
+ }
+
+ public void emitCOptArgumentSuffix(final CodeUnit unit, final int argIdx) {
+ if( ( argIdx == info.setFuncCBParamIdx || argIdx == info.setFuncUserParamIdx ) ) {
+ unit.emit("_native");
+ }
+ }
+
+ public void appendCAdditionalJNIDescriptor(final StringBuilder buf) {
+ JavaType.appendJNIDescriptor(buf, Class.class, false); // to account for the additional 'jclass clazz' parameter
+ JavaType.appendJNIDescriptor(buf, String.class, false); // to account for the additional 'jstring jcallbackSignature' parameter
+ JavaType.appendJNIDescriptor(buf, long.class, false); // to account for the additional 'long nativeUserParam' parameter
+ }
+
+ public void emitCSetFuncPreCall(final CodeUnit unit) {
+ final String jcbNativeBasename = CodeGenUtils.capitalizeString( info.setFuncName );
+ final String jcbFriendlyBasename = info.setFuncName+"("+info.cbSimpleClazzName+")";
+ final String staticBindingMethodName = "invoke"+jcbNativeBasename;
+ final String staticBindingClazzVarName = "clazz"+jcbNativeBasename;
+ final String staticBindingMethodIDVarName = "method"+jcbNativeBasename;
+ final String cbFuncArgName = binding.getArgumentName(info.setFuncCBParamIdx);
+ final String userParamTypeName = info.cbFuncUserParamType.getCName();
+ final String userParamArgName = binding.getArgumentName(info.setFuncUserParamIdx);
+ final String nativeCBFuncVarName = cbFuncArgName+"_native";
+ final String nativeUserParamVarName = userParamArgName+"_native";
+ unit.emitln();
+ unit.emitln(" // JavaCallback handling");
+ unit.emitln(" if( NULL == clazz ) { (*env)->FatalError(env, \"NULL clazz passed to '"+jcbFriendlyBasename+"'\"); }");
+ unit.emitln(" "+info.cbFuncTypeName+" "+nativeCBFuncVarName+";");
+ unit.emitln(" "+userParamTypeName+"* "+nativeUserParamVarName+";");
+ unit.emitln(" if( NULL != "+cbFuncArgName+" ) {");
+ unit.emitln(" const char* callbackSignature = (*env)->GetStringUTFChars(env, jcallbackSignature, (jboolean*)NULL);");
+ unit.emitln(" if( NULL == callbackSignature ) { (*env)->FatalError(env, \"Failed callbackSignature in '"+jcbFriendlyBasename+"'\"); }");
+ unit.emitln(" jmethodID cbMethodID = (*env)->GetStaticMethodID(env, clazz, \""+staticBindingMethodName+"\", callbackSignature);");
+ unit.emitln(" if( NULL == cbMethodID ) {");
+ unit.emitln(" char cmsg[400];");
+ unit.emitln(" snprintf(cmsg, 400, \"Failed GetStaticMethodID of '"+staticBindingMethodName+"(%s)' in '"+jcbFriendlyBasename+"'\", callbackSignature);");
+ unit.emitln(" (*env)->FatalError(env, cmsg);");
+ unit.emitln(" }");
+ unit.emitln(" (*env)->ReleaseStringUTFChars(env, jcallbackSignature, callbackSignature);");
+ unit.emitln(" "+staticBindingClazzVarName+" = clazz;");
+ unit.emitln(" "+staticBindingMethodIDVarName+" = cbMethodID;");
+ unit.emitln(" "+nativeCBFuncVarName+" = func"+jcbNativeBasename+";");
+ unit.emitln(" "+nativeUserParamVarName+" = ("+userParamTypeName+"*) jnativeUserParam;");
+ unit.emitln(" } else {");
+ unit.emitln(" "+nativeCBFuncVarName+" = NULL;");
+ unit.emitln(" "+nativeUserParamVarName+" = NULL;");
+ unit.emitln(" }");
+ unit.emitln();
+
+ }
+
+ public void emitCAdditionalCode(final CodeUnit unit, final CMethodBindingEmitter jcbCMethodEmitter) {
+ final String jcbNativeBasename = CodeGenUtils.capitalizeString( info.setFuncName );
+ final String jcbFriendlyBasename = info.setFuncName+"("+info.cbSimpleClazzName+")";
+ final String staticBindingClazzVarName = "clazz"+jcbNativeBasename;
+ final String staticBindingMethodIDVarName = "method"+jcbNativeBasename;
+ final String staticCallbackName = "func"+jcbNativeBasename;
+ // final Type userParamType = javaCallback.cbFuncBinding.getCArgumentType(javaCallback.cbFuncUserParamIdx);
+ final String userParamTypeName = info.cbFuncUserParamType.getCName();
+ final String userParamArgName = info.cbFuncBinding.getArgumentName(info.cbFuncUserParamIdx);
+ final Type cReturnType = info.cbFuncBinding.getCReturnType();
+ final JavaType jretType = info.cbFuncBinding.getJavaReturnType();
+ unit.emitln();
+ unit.emitln("static jclass "+staticBindingClazzVarName+" = NULL;");
+ unit.emitln("static jmethodID "+staticBindingMethodIDVarName+" = NULL;");
+ unit.emitln();
+ // javaCallback.cbFuncCEmitter.emitSignature();
+ unit.emit("static "+cReturnType.getCName()+" "+staticCallbackName+"(");
+ // javaCallback.cbFuncCEmitter.emitArguments();
+ unit.emit(info.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
+ unit.emitln(") {");
+ // javaCallback.cbFuncCEmitter.emitBody();
+ {
+ unit.emitln(" JNIEnv* env = JVMUtil_GetJNIEnv();");
+ unit.emitln(" jclass cbClazz = "+staticBindingClazzVarName+";");
+ unit.emitln(" jmethodID cbMethod = "+staticBindingMethodIDVarName+";");
+ unit.emitln(" if( NULL == env || NULL == cbClazz || NULL == cbMethod ) {");
+ if( !cReturnType.isVoid() ) {
+ unit.emitln(" return 0;");
+ } else {
+ unit.emitln(" return;");
+ }
+ unit.emitln(" }");
+ // javaCallback.cbFuncCEmitter.emitBodyVariableDeclarations();
+ // javaCallback.cbFuncCEmitter.emitBodyUserVariableDeclarations();
+ // javaCallback.cbFuncCEmitter.emitBodyVariablePreCallSetup();
+ emitJavaCallbackBodyCToJavaPreCall(jcbCMethodEmitter);
+
+ // javaCallback.cbFuncCEmitter.emitBodyCallCFunction();
+ unit.emitln(" "+userParamTypeName+"* "+userParamArgName+"_jni = ("+userParamTypeName+"*) "+userParamArgName+";");
+ unit.emitln(" // C Params: "+info.cbFuncBinding.getCParameterList(new StringBuilder(), false, null).toString());
+ unit.emitln(" // J Params: "+info.cbFuncBinding.getJavaParameterList(new StringBuilder()).toString());
+
+ final String returnStatement;
+ if( !cReturnType.isVoid() ) {
+ unit.emit(" "+cReturnType.getCName()+" _res = 0;");
+ returnStatement = "return _res;";
+ } else {
+ returnStatement = "return;";
+ }
+ if( !cReturnType.isVoid() ) {
+ unit.emit(" _res = ("+cReturnType.getCName()+") ");
+ } else {
+ unit.emit(" ");
+ }
+ unit.emit("(*env)->CallStatic" + CodeGenUtils.capitalizeString( jretType.getName() ) +"Method(env, cbClazz, cbMethod, ");
+ // javaCallback.cbFuncCEmitter.emitBodyPassCArguments();
+ emitJavaCallbackBodyPassJavaArguments(unit, jcbCMethodEmitter.binding, null); //"NULL");
+ unit.emitln(");");
+ unit.emitln(" if( (*env)->ExceptionCheck(env) ) {");
+ unit.emitln(" fprintf(stderr, \"Info: Callback '"+jcbFriendlyBasename+"': Exception in Java Callback caught:\\n\");");
+ unit.emitln(" (*env)->ExceptionDescribe(env);");
+ unit.emitln(" (*env)->ExceptionClear(env);");
+ unit.emitln(" }");
+
+ // javaCallback.cbFuncCEmitter.emitBodyUserVariableAssignments();
+ // javaCallback.cbFuncCEmitter.emitBodyVariablePostCallCleanup();
+ // javaCallback.cbFuncCEmitter.emitBodyMapCToJNIType(-1 /* return value */, true /* addLocalVar */)
+
+ unit.emitln(" "+returnStatement);
+ }
+ unit.emitln("}");
+ unit.emitln();
+ }
+
+ /* pp */ int emitJavaCallbackBodyCToJavaPreCall(final CMethodBindingEmitter ce) {
+ int count = 0;
+ for (int i = 0; i < ce.binding.getNumArguments(); i++) {
+ if( i == info.cbFuncUserParamIdx ) {
+ continue;
+ }
+ if( ce.emitBodyMapCToJNIType(i, true /* addLocalVar */) ) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ /* pp */ int emitJavaCallbackBodyPassJavaArguments(final CodeUnit unit, final MethodBinding binding, final String userParamVarName) {
+ int count = 0;
+ boolean needsComma = false;
+ for (int i = 0; i < binding.getNumArguments(); i++) {
+ if (needsComma) {
+ unit.emit(", ");
+ needsComma = false;
+ }
+ if( i == info.cbFuncUserParamIdx && null != userParamVarName ) {
+ unit.emit( userParamVarName );
+ } else {
+ unit.emit( binding.getArgumentName(i) + "_jni" );
+ }
+ needsComma = true;
+ ++count;
+ }
+ return count;
+ }
+
+
+}
diff --git a/src/java/com/jogamp/gluegen/JavaConfiguration.java b/src/java/com/jogamp/gluegen/JavaConfiguration.java
index 3e2e680..10f43a7 100644
--- a/src/java/com/jogamp/gluegen/JavaConfiguration.java
+++ b/src/java/com/jogamp/gluegen/JavaConfiguration.java
@@ -156,17 +156,19 @@ public class JavaConfiguration {
final int cbFuncUserParamIdx;
final String setFuncName;
final List<Integer> setFuncKeyIndices = new ArrayList<Integer>();
+ final int setFuncUserParamIdx; // optional
final String setFuncKeyClassName; // optional
- JavaCallbackDef(final String cbFuncTypeName, final int cbFuncUserParamIdx, final String setFuncName, final String setFuncKeyClassName) {
+ JavaCallbackDef(final String cbFuncTypeName, final int cbFuncUserParamIdx, final String setFuncName, final int setFuncUserParamIdx, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
this.cbFuncUserParamIdx = cbFuncUserParamIdx;
this.setFuncName = setFuncName;
+ this.setFuncUserParamIdx = setFuncUserParamIdx;
this.setFuncKeyClassName = setFuncKeyClassName;
}
@Override
public String toString() {
- return String.format("JavaCallbackDef[cbFunc[type %s, userParamIdx %d], set[%s, keys %s, KeyClass %s]]",
- cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncKeyIndices.toString(), setFuncKeyClassName);
+ return String.format("JavaCallbackDef[cbFunc[type %s, userParamIdx %d], set[%s, keys %s, userParamIdx %d, KeyClass %s]]",
+ cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncKeyIndices.toString(), setFuncUserParamIdx, setFuncKeyClassName);
}
}
private final List<JavaCallbackDef> javaCallbackList = new ArrayList<JavaCallbackDef>();
@@ -1630,7 +1632,25 @@ public class JavaConfiguration {
protected void readJavaCallbackDef(final StringTokenizer tok, final String filename, final int lineNo) {
try {
final String setFuncName = tok.nextToken();
- final String cbFuncTypeName = tok.nextToken();
+ final int setFuncUserParamIdx;
+ final String cbFuncTypeName;
+ {
+ final String stok = tok.nextToken();
+ int ival = -1;
+ String sval = null;
+ try {
+ ival = Integer.valueOf(stok);
+ } catch(final NumberFormatException nfe) {
+ sval = stok;
+ }
+ if( null == sval ) {
+ setFuncUserParamIdx = ival;
+ cbFuncTypeName = tok.nextToken();
+ } else {
+ setFuncUserParamIdx = -1;
+ cbFuncTypeName = sval;
+ }
+ }
final Integer cbFuncUserParamIdx = Integer.valueOf(tok.nextToken());
final String cbFuncKeyClassName;
if( tok.hasMoreTokens() ) {
@@ -1638,7 +1658,7 @@ public class JavaConfiguration {
} else {
cbFuncKeyClassName = null;
}
- final JavaCallbackDef jcd = new JavaCallbackDef(cbFuncTypeName, cbFuncUserParamIdx, setFuncName, cbFuncKeyClassName);
+ final JavaCallbackDef jcd = new JavaCallbackDef(cbFuncTypeName, cbFuncUserParamIdx, setFuncName, setFuncUserParamIdx, cbFuncKeyClassName);
javaCallbackList.add(jcd);
javaCallbackSetFuncToDef.put(setFuncName, jcd);
} catch (final NoSuchElementException e) {
@@ -2279,13 +2299,12 @@ public class JavaConfiguration {
final String cbFuncTypeName;
final String cbSimpleClazzName;
final String cbFQClazzName;
- final String cbMethodSignature;
+ final String staticCBMethodSignature;
final FunctionType cbFuncType;
final MethodBinding cbFuncBinding;
final int cbFuncUserParamIdx;
-
- final Type userParamType;
- final String userParamName;
+ final String cbFuncUserParamName;
+ final Type cbFuncUserParamType;
final String setFuncName;
final List<Integer> setFuncKeyIndices;
@@ -2295,38 +2314,38 @@ public class JavaConfiguration {
int setFuncUserParamIdx;
boolean keyClassEmitted;
- public JavaCallbackInfo(final String cbFuncTypeName, final String cbSimpleClazzName, final String cbFQClazzName, final String cbMethodSignature,
+ public JavaCallbackInfo(final String cbFuncTypeName, final String cbSimpleClazzName, final String cbFQClazzName, final String staticCBMethodSignature,
final FunctionType cbFuncType, final MethodBinding cbFuncBinding, final int cbFuncUserParamIdx,
- final String setFuncName, final List<Integer> setFuncKeyIndices, final String setFuncKeyClassName) {
+ final String setFuncName, final int setFuncUserParamIdx, final List<Integer> setFuncKeyIndices, final String setFuncKeyClassName) {
this.cbFuncTypeName = cbFuncTypeName;
this.cbSimpleClazzName = cbSimpleClazzName;
this.cbFQClazzName = cbFQClazzName;
- this.cbMethodSignature = cbMethodSignature;
+ this.staticCBMethodSignature = staticCBMethodSignature;
this.cbFuncType = cbFuncType;
this.cbFuncBinding = cbFuncBinding;
- int paramIdx = -2;
- Type paramType = null;
- String paramName = null;
- if( 0 <= cbFuncUserParamIdx && cbFuncUserParamIdx < cbFuncType.getNumArguments() ) {
- final Type t = cbFuncType.getArgumentType(cbFuncUserParamIdx);
- if( null != t && t.isPointer() ) {
- // OK '<something>*'
- paramIdx = cbFuncUserParamIdx;
- paramName = cbFuncType.getArgumentName(cbFuncUserParamIdx);
- paramType = t.getTargetType();
+ {
+ int paramIdx = -2;
+ Type paramType = null;
+ String paramName = null;
+ if( 0 <= cbFuncUserParamIdx && cbFuncUserParamIdx < cbFuncType.getNumArguments() ) {
+ final Type t = cbFuncType.getArgumentType(cbFuncUserParamIdx);
+ if( null != t && t.isPointer() ) {
+ // OK '<something>*'
+ paramIdx = cbFuncUserParamIdx;
+ paramName = cbFuncType.getArgumentName(cbFuncUserParamIdx);
+ paramType = t.getTargetType();
+ }
}
+ this.cbFuncUserParamIdx = paramIdx;
+ this.cbFuncUserParamName = paramName;
+ this.cbFuncUserParamType = paramType;
}
- this.cbFuncUserParamIdx = paramIdx;
-
- this.userParamType = paramType;
- this.userParamName = paramName;
-
this.setFuncName = setFuncName;
this.setFuncKeyIndices = setFuncKeyIndices;
this.setFuncKeyClassName = setFuncKeyClassName;
this.setFuncProcessed = false;
this.setFuncCBParamIdx = -1;
- this.setFuncUserParamIdx = -1;
+ this.setFuncUserParamIdx = setFuncUserParamIdx;
this.keyClassEmitted = false;
}
@@ -2335,7 +2354,13 @@ public class JavaConfiguration {
if( 0 <= cbParamIdx && 0 <= userParamIdx ) {
setFuncProcessed = true;
setFuncCBParamIdx = cbParamIdx;
- setFuncUserParamIdx = userParamIdx;
+ if( 0 <= setFuncUserParamIdx ) {
+ if( setFuncUserParamIdx != userParamIdx ) {
+ throw new IllegalArgumentException("Mismatch pre-set setFuncUserParamIdx "+setFuncUserParamIdx+", given "+userParamIdx+": "+toString());
+ }
+ } else {
+ setFuncUserParamIdx = userParamIdx;
+ }
} else {
setFuncCBParamIdx = -1;
setFuncUserParamIdx = -1;
@@ -2346,8 +2371,8 @@ public class JavaConfiguration {
@Override
public String toString() {
return String.format("JavaCallbackInfo[cbFunc[%s%s, userParam[idx %d, '%s', %s], set[%s(ok %b, cbIdx %d, upIdx %d, keys %s, KeyClass '%s'], %s]",
- cbFuncTypeName, cbMethodSignature,
- cbFuncUserParamIdx, userParamName, userParamType.getSignature(null).toString(),
+ cbFuncTypeName, staticCBMethodSignature,
+ cbFuncUserParamIdx, cbFuncUserParamName, cbFuncUserParamType.getSignature(null).toString(),
setFuncName, setFuncProcessed, setFuncCBParamIdx, setFuncUserParamIdx,
setFuncKeyIndices.toString(), setFuncKeyClassName,
cbFuncType.toString(cbFuncTypeName, false, true));
diff --git a/src/java/com/jogamp/gluegen/JavaEmitter.java b/src/java/com/jogamp/gluegen/JavaEmitter.java
index 2ea8d30..4a81a01 100644
--- a/src/java/com/jogamp/gluegen/JavaEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaEmitter.java
@@ -1471,9 +1471,9 @@ public class JavaEmitter implements GlueEmitter {
throw new UnsupportedOperationException("Reused FuncTypeName "+jcbd.cbFuncTypeName+" used with different FuncUserParamIdx "+jcbi0.cbFuncUserParamIdx+" -> "+jcbd.cbFuncUserParamIdx+". Func "+
funcType.toString(jcbd.cbFuncTypeName, false, true));
}
- final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, jcbi0.cbMethodSignature,
+ final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, jcbi0.staticCBMethodSignature,
funcType, jcbi0.cbFuncBinding, jcbi0.cbFuncUserParamIdx,
- jcbd.setFuncName, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
+ jcbd.setFuncName, jcbd.setFuncUserParamIdx, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
LOG.log(INFO, "JavaCallbackInfo: Reusing {0} -> {1}", jcbd.setFuncName, jcbi0);
} else {
@@ -1493,7 +1493,7 @@ public class JavaEmitter implements GlueEmitter {
}
final JavaCallbackInfo jcbi1 = new JavaCallbackInfo(jcbd.cbFuncTypeName, cbSimpleClazzName, cbFQClazzName, cbMethodSignature.toString(),
funcType, cbFuncBinding, jcbd.cbFuncUserParamIdx,
- jcbd.setFuncName, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
+ jcbd.setFuncName, jcbd.setFuncUserParamIdx, jcbd.setFuncKeyIndices, jcbd.setFuncKeyClassName);
cfg.setFuncToJavaCallbackMap.put(jcbd.setFuncName, jcbi1);
javaCallbackInterfaceMap.put(cbFQClazzName, jcbi1);
LOG.log(INFO, "JavaCallbackInfo: Added {0} -> {1}", jcbd.setFuncName, jcbi1);
@@ -3019,9 +3019,6 @@ public class JavaEmitter implements GlueEmitter {
LOG.log(WARNING, "JavaCallback used, but no 'LibraryOnLoad' basename specified for JNI_OnLoad(..). Exactly one native code-unit for the library must specify 'LibraryOnLoad' basename");
}
cUnit().emitHeader(cfg.libraryOnLoadName(), getImplPackageName(), cfg.implClassName(), cfg.customCCode());
- if( cfg.getJavaCallbackList().size() > 0 ) {
- cUnit().emitJavaCallbackGlueDataDecl();
- }
}
} catch (final Exception e) {
throw new RuntimeException(
@@ -3114,13 +3111,29 @@ public class JavaEmitter implements GlueEmitter {
// Replace JavaCallback type with generated interface name
jcbiSetFuncCBParamIdx=i;
mappedType = JavaType.createForNamedClass( jcbi.cbFQClazzName );
- } else if( null != jcbi && jcbi.userParamName.equals( cArgName ) &&
+ } else if( null != jcbi && i == jcbi.setFuncUserParamIdx && cArgType.isPointer() ) {
+ // Replace userParam argument '<userParamType>*' if 'void*' with Object
+ jcbiSetFuncUserParamIdx=i;
+ if( cArgType.getTargetType().isVoid() ) {
+ if( jcbi.cbFuncUserParamType.isCompound() ) {
+ mappedType = JavaType.createForClass(long.class);
+ } else {
+ mappedType = JavaType.forObjectClass();
+ }
+ }
+ } else if( null != jcbi && jcbi.cbFuncUserParamName.equals( cArgName ) &&
( !jcbi.setFuncProcessed || i == jcbi.setFuncUserParamIdx ) &&
- cArgType.isPointer() && jcbi.userParamType.equals( cArgType.getTargetType() ) )
+ cArgType.isPointer() && jcbi.cbFuncUserParamType.equals( cArgType.getTargetType() ) )
{
- // Replace optional userParam argument '<userParamType>*' with Object
+ // Replace userParam argument '<userParamType>*' if 'void*' with Object
jcbiSetFuncUserParamIdx=i;
- mappedType = JavaType.forObjectClass();
+ if( cArgType.getTargetType().isVoid() ) {
+ if( jcbi.cbFuncUserParamType.isCompound() ) {
+ mappedType = JavaType.createForClass(long.class);
+ } else {
+ mappedType = JavaType.forObjectClass();
+ }
+ }
} else if (stringArgIndices != null && stringArgIndices.contains(i)) {
// Take into account any ArgumentIsString configuration directives that apply
// System.out.println("Forcing conversion of " + binding.getName() + " arg #" + i + " from byte[] to String ");
@@ -3153,7 +3166,8 @@ public class JavaEmitter implements GlueEmitter {
}
if( null != jcbi ) {
jcbi.setFuncProcessed(jcbiSetFuncCBParamIdx, jcbiSetFuncUserParamIdx);
- LOG.log(INFO, "BindFunc.JavaCallback: {0}: {1}, {2}", sym.getName(), sym.getType().toString(sym.getName(), false, true), jcbi);
+ LOG.log(INFO, "BindFunc.JavaCallback: {0}: set[cbParamIdx {1}, userParamIdx {2}], {3}, {4}",
+ sym.getName(), jcbiSetFuncCBParamIdx, jcbiSetFuncUserParamIdx, sym.getType().toString(sym.getName(), false, true), jcbi);
}
final MethodBinding mb = new MethodBinding(sym, delegationImplName,
javaReturnType, javaArgumentTypes,
diff --git a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
index 6a93973..fe4f82a 100644
--- a/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/JavaMethodBindingEmitter.java
@@ -95,7 +95,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
private String returnedArrayLengthExpression;
private boolean returnedArrayLengthExpressionOnlyForComments = false;
- private final JavaCallbackInfo javaCallback;
+ private final JavaCallbackEmitter javaCallbackEmitter;
// A suffix used to create a temporary outgoing array of Buffers to
// represent an array of compound type wrappers
@@ -134,7 +134,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
} else {
setCommentEmitter(defaultInterfaceCommentEmitter);
}
- javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ final JavaCallbackInfo javaCallback = cfg.setFuncToJavaCallbackMap.get(binding.getName());
+ if( null != javaCallback ) {
+ javaCallbackEmitter = new JavaCallbackEmitter(cfg, binding, javaCallback, appendSignature(new StringBuilder()).toString());
+ } else {
+ javaCallbackEmitter = null;
+ }
// !forImplementingMethodCall && !isInterface
}
@@ -156,7 +161,7 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
epilogue = arg.epilogue;
returnedArrayLengthExpression = arg.returnedArrayLengthExpression;
returnedArrayLengthExpressionOnlyForComments = arg.returnedArrayLengthExpressionOnlyForComments;
- javaCallback = arg.javaCallback;
+ javaCallbackEmitter = arg.javaCallbackEmitter;
}
public boolean isNativeMethod() { return isNativeMethod; }
@@ -262,8 +267,8 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
@Override
- protected void emitReturnType() {
- unit.emit(getReturnTypeString(false));
+ protected StringBuilder appendReturnType(final StringBuilder buf) {
+ return buf.append(getReturnTypeString(false));
}
protected String erasedTypeString(final JavaType type, final boolean skipBuffers) {
@@ -335,33 +340,34 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
@Override
- protected void emitName() {
+ protected StringBuilder appendName(final StringBuilder buf) {
if (isPrivateNativeMethod) {
- unit.emit(getNativeImplMethodName());
+ buf.append(getNativeImplMethodName());
} else if( isInterface()) {
- unit.emit(getInterfaceName());
+ buf.append(getInterfaceName());
} else {
- unit.emit(getImplName());
+ buf.append(getImplName());
}
+ return buf;
}
@Override
- protected int emitArguments() {
+ protected int appendArguments(final StringBuilder buf) {
boolean needComma = false;
int numEmitted = 0;
if( hasModifier(JavaMethodBindingEmitter.NATIVE) && binding.isReturnCompoundByValue() ) {
- unit.emit("final Class<?> _clazzBuffers");
+ buf.append("final Class<?> _clazzBuffers");
++numEmitted;
needComma = true;
}
if (isPrivateNativeMethod && binding.hasContainingType()) {
// Always emit outgoing "this" argument
if (needComma) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit("ByteBuffer ");
- unit.emit(javaThisArgumentName());
+ buf.append("ByteBuffer ");
+ buf.append(javaThisArgumentName());
++numEmitted;
needComma = true;
}
@@ -385,12 +391,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
if (needComma) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit(erasedTypeString(type, false));
- unit.emit(" ");
- unit.emit(getArgumentName(i));
+ buf.append(erasedTypeString(type, false));
+ buf.append(" ");
+ buf.append(getArgumentName(i));
++numEmitted;
needComma = true;
@@ -398,12 +404,12 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
// Add Buffer and array index offset arguments after each associated argument
if (forDirectBufferImplementation || forIndirectBufferAndArrayImplementation) {
if (type.isNIOBuffer()) {
- unit.emit(", int " + byteOffsetArgName(i));
+ buf.append(", int " + byteOffsetArgName(i));
if(!useNIODirectOnly) {
- unit.emit(", boolean " + isNIOArgName(i));
+ buf.append(", boolean " + isNIOArgName(i));
}
} else if (type.isNIOBufferArray()) {
- unit.emit(", int[] " + byteOffsetArrayArgName(i));
+ buf.append(", int[] " + byteOffsetArrayArgName(i));
}
}
@@ -412,17 +418,16 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
if(useNIOOnly) {
throw new RuntimeException("NIO[Direct]Only "+binding+" is set, but "+getArgumentName(i)+" is a primitive array");
}
- unit.emit(", int " + offsetArgName(i));
+ buf.append(", int " + offsetArgName(i));
}
}
if( hasModifier(JavaMethodBindingEmitter.NATIVE) &&
- null != javaCallback )
+ null != javaCallbackEmitter )
{
if (needComma) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit("String callbackSignature, Object lockObj, long[/*1*/] nativeUserParam");
- ++numEmitted;
+ numEmitted += javaCallbackEmitter.appendJavaAdditionalJNIParameter(buf);
}
return numEmitted;
}
@@ -455,125 +460,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
return getArgumentName(i) + "_offset";
}
- private static final boolean DEBUG_JAVACALLBACK = false;
-
- private final void emitJavaCallbackBirefAPIDoc(final String actionText, final String relationToKey, final String noKeyText, final String relationToFunc) {
- unit.emit(" /** "+actionText);
- if( javaCallback.setFuncKeyIndices.size() > 0 ) {
- unit.emit(relationToKey);
- unit.emit("Key { "+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+" } ");
- } else {
- unit.emit(noKeyText);
- }
- unit.emit(relationToFunc);
- unit.emit("<br> <code>");
- emitSignature();
- unit.emitln("</code> **/");
- }
- private final void emitJavaCallbackKeyClass(final String capIfaceName, final String keyClassName) {
- emitJavaCallbackBirefAPIDoc("", "", "", "for ");
- unit.emitln(" public static class "+keyClassName+" {");
- binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
- if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
- unit.emitln(" public final "+jType+" "+name+";");
- return true;
- } else {
- return false;
- }
- } );
- unit.emitln(" public "+keyClassName+"("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+") {");
- binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
- if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
- unit.emitln(" this."+name+" = "+name+";");
- return true;
- } else {
- return false;
- }
- } );
- unit.emitln(" }");
- unit.emitln(" @Override");
- unit.emitln(" public boolean equals(final Object o) {");
- unit.emitln(" if( this == o ) {");
- unit.emitln(" return true;");
- unit.emitln(" }");
- unit.emitln(" if( !(o instanceof "+keyClassName+") ) {");
- unit.emitln(" return false;");
- unit.emitln(" }");
- {
- final int count = binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
- if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
- if( 0 == consumedCount ) {
- unit.emitln(" final "+keyClassName+" o2 = ("+keyClassName+")o;");
- unit.emit (" return ");
- } else {
- unit.emitln(" &&");
- unit.emit (" ");
- }
- if( jType.isPrimitive() || idx == javaCallback.setFuncUserParamIdx ) {
- unit.emit(name+" == o2."+name);
- } else {
- unit.emit(name+".equals( o2."+name+" )");
- }
- return true;
- } else {
- return false;
- }
- } );
- if( 0 == count ) {
- unit.emit(" return true");
- }
- unit.emitln(";");
- }
- unit.emitln(" }");
- unit.emitln(" @Override");
- unit.emitln(" public int hashCode() {");
- {
- final int count = binding.forEachParameter( ( final int idx, final int consumedCount, final Type cType, final JavaType jType, final String name ) -> {
- if( !cType.isVoid() && javaCallback.setFuncKeyIndices.contains(idx) ) {
- if( 0 == consumedCount ) {
- unit.emitln(" // 31 * x == (x << 5) - x");
- unit.emit (" int hash = ");
- } else {
- unit.emit (" hash = ((hash << 5) - hash) + ");
- }
- if( jType.isPrimitive() ) {
- if( jType.isLong() ) {
- unit.emitln("HashUtil.getAddrHash32_EqualDist( "+name+" );");
- } else {
- unit.emitln(name+";");
- }
- } else {
- if( idx == javaCallback.setFuncUserParamIdx ) {
- unit.emitln("System.identityHashCode( "+name+" );");
- } else {
- unit.emitln(name+".hashCode();");
- }
- }
- return true;
- } else {
- return false;
- }
- } );
- if( 0 == count ) {
- unit.emitln(" return 0;");
- } else {
- unit.emitln(" return hash;");
- }
- }
- unit.emitln(" }");
- unit.emitln(" }");
- }
- private final void emitJavaCallbackDataClass(final String capIfaceName, final String dataClassName) {
- unit.emitln(" private static class "+dataClassName+" {");
- unit.emitln(" final "+javaCallback.cbFuncTypeName+" func;");
- unit.emitln(" final Object param;");
- unit.emitln(" final long nativeParam;");
- unit.emitln(" "+dataClassName+"("+javaCallback.cbFuncTypeName+" func, Object param, long nativeParam) {");
- unit.emitln(" this.func = func;");
- unit.emitln(" this.param = param;");
- unit.emitln(" this.nativeParam = nativeParam;");
- unit.emitln(" }");
- unit.emitln(" }");
+ @Override
+ protected void emitAdditionalCode() {
+ if( null != javaCallbackEmitter && !isPrivateNativeMethod ) {
+ javaCallbackEmitter.emitJavaAdditionalCode(unit, isInterface());
+ }
}
@Override
@@ -594,201 +485,6 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
unit.emitln(" }");
}
- if( null != javaCallback && !isPrivateNativeMethod ) {
- final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
- final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
- final String lockInstanceName = lowIfaceName+"Lock";
- final String dataMapInstanceName = lowIfaceName+"DataMap";
- final String dataInstanceName = lowIfaceName+"Data";
- final boolean customKeyClass;
- final String KeyClassName;
- final boolean useDataMap;
- if( null != javaCallback.setFuncKeyClassName ) {
- customKeyClass = true;;
- KeyClassName = javaCallback.setFuncKeyClassName;
- useDataMap = true;
- } else {
- customKeyClass = false;
- KeyClassName = CodeGenUtils.capitalizeString(capIfaceName+"Key");
- useDataMap = javaCallback.setFuncKeyIndices.size() > 0;
- }
- final String DataClassName = CodeGenUtils.capitalizeString( javaCallback.cbFuncTypeName+"Data" );
- final String fqUsrParamClassName = cfg.packageName()+"."+cfg.className()+"."+DataClassName;
- unit.emitln();
- if( isInterface() ) {
- if( useDataMap ) {
- if( !customKeyClass && !javaCallback.keyClassEmitted ) {
- emitJavaCallbackKeyClass(capIfaceName, KeyClassName);
- unit.emitln();
- javaCallback.keyClassEmitted = true;
- }
- emitJavaCallbackBirefAPIDoc("Returns ", "set of ", "", "for ");
- unit.emitln(" public Set<"+KeyClassName+"> get"+capIfaceName+"Keys();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public boolean is"+capIfaceName+"Mapped("+KeyClassName+" key);");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key);");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public Object get"+capIfaceName+"UserParam("+KeyClassName+" key);");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public int releaseAll"+capIfaceName+"();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public void release"+capIfaceName+"("+KeyClassName+" key);");
- unit.emitln();
- } else {
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public boolean is"+capIfaceName+"Mapped();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public Object get"+capIfaceName+"UserParam();");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public void release"+capIfaceName+"();");
- unit.emitln();
- }
- } else {
- if( useDataMap ) {
- if( !customKeyClass && !javaCallback.keyClassEmitted ) {
- emitJavaCallbackKeyClass(capIfaceName, KeyClassName);
- unit.emitln();
- javaCallback.keyClassEmitted = true;
- }
- emitJavaCallbackBirefAPIDoc("Returns ", "set of ", "", "for ");
- unit.emitln(" public final Set<"+KeyClassName+"> get"+capIfaceName+"Keys() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" return "+dataMapInstanceName+".keySet();");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public final boolean is"+capIfaceName+"Mapped("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" return null != "+dataMapInstanceName+".get(key);");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public final "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
- unit.emitln(" return null != value ? value.func : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public final Object get"+capIfaceName+"UserParam("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".get(key);");
- unit.emitln(" return null != value ? value.param : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases all callback data ", "mapped via ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public final int releaseAll"+capIfaceName+"() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final Set<"+KeyClassName+"> keySet = "+dataMapInstanceName+".keySet();");
- unit.emitln(" final "+KeyClassName+"[] keys = keySet.toArray(new "+KeyClassName+"[keySet.size()]);");
- unit.emitln(" for(int i=0; i<keys.length; ++i) {");
- unit.emitln(" final "+KeyClassName+" key = keys[i];");
- unit.emitln(" release"+capIfaceName+"(key);");
- unit.emitln(" }");
- unit.emitln(" return keys.length;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "mapped to ", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public final void release"+capIfaceName+"("+KeyClassName+" key) {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataMapInstanceName+".remove(key);");
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" System.err.println(\"ZZZ Release \"+key+\" -> value.nativeParam 0x\"+Long.toHexString(null!=value?value.nativeParam:0));");
- }
- unit.emitln(" if( null != value ) {");
- unit.emitln(" release"+capIfaceName+"Impl(value.nativeParam);");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln(" }");
- } else {
- emitJavaCallbackBirefAPIDoc("Returns ", "whether callback ", "if callback ", "is mapped for ");
- unit.emitln(" public final boolean is"+capIfaceName+"Mapped() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" return null != "+dataInstanceName+";");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns "+javaCallback.cbFuncTypeName+" callback ", "mapped to ", "", "for ");
- unit.emitln(" public final "+javaCallback.cbFuncTypeName+" get"+capIfaceName+"() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
- unit.emitln(" return null != value ? value.func : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Returns user-param ", "mapped to ", "", "for ");
- unit.emitln(" public final Object get"+capIfaceName+"UserParam() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
- unit.emitln(" return null != value ? value.param : null;");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln();
-
- emitJavaCallbackBirefAPIDoc("Releases callback data ", "", "", "skipping toolkit API. Favor passing `null` callback ref to ");
- unit.emitln(" public final void release"+capIfaceName+"() {");
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final "+DataClassName+" value = "+dataInstanceName+";");
- unit.emitln(" "+dataInstanceName+" = null;");
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" System.err.println(\"ZZZ Release \"+key+\" -> value.nativeParam 0x\"+Long.toHexString(null!=value?value.nativeParam:0));");
- }
- unit.emitln(" if( null != value ) {");
- unit.emitln(" release"+capIfaceName+"Impl(value.nativeParam);");
- unit.emitln(" }");
- unit.emitln(" }");
- unit.emitln(" }");
- }
- unit.emitln(" private native void release"+capIfaceName+"Impl(long nativeUserParam);");
- unit.emitln();
- unit.emitln(" private final void add"+capIfaceName+"("+binding.getJavaSelectParameter(new StringBuilder(), javaCallback.setFuncKeyIndices, true).toString()+DataClassName+" value) {");
- if( useDataMap ) {
- unit.emitln(" final "+KeyClassName+" key = new "+KeyClassName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+");");
- unit.emitln(" final "+DataClassName+" old = "+dataMapInstanceName+".put(key, value);");
- } else {
- unit.emitln(" final "+DataClassName+" old = "+dataInstanceName+";");
- unit.emitln(" "+dataInstanceName+" = value;");
- }
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" System.err.println(\"ZZZ Map \"+key+\" -> value.nativeParam 0x\"+Long.toHexString(null!=value?value.nativeParam:0));");
- }
- unit.emitln(" if( null != old ) {");
- unit.emitln(" release"+capIfaceName+"Impl(old.nativeParam);");
- unit.emitln(" }");
- unit.emitln(" }");
- if( !cfg.emittedJavaCallbackUserParamClasses.contains(fqUsrParamClassName) ) {
- emitJavaCallbackDataClass(capIfaceName, DataClassName);
- cfg.emittedJavaCallbackUserParamClasses.add(fqUsrParamClassName);
- }
- if( useDataMap ) {
- unit.emitln(" private final Map<"+KeyClassName+", "+DataClassName+"> "+dataMapInstanceName+" = new HashMap<"+KeyClassName+", "+DataClassName+">();");
- } else {
- unit.emitln(" private "+DataClassName+" "+dataInstanceName+" = null;");
- }
- unit.emitln(" private final Object "+lockInstanceName+" = new Object();");
- unit.emitln();
- }
- }
}
protected void emitPrologueOrEpilogue(final List<String> code) {
@@ -901,15 +597,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
protected void emitReturnVariableSetupAndCall(final MethodBinding binding) {
final JavaType returnType = binding.getJavaReturnType();
+
boolean needsResultAssignment = false;
- final String capIfaceName = CodeGenUtils.capitalizeString( getInterfaceName() );
- if( null != javaCallback ) {
- final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
- final String lockInstanceName = lowIfaceName+"Lock";
- unit.emitln(" synchronized( "+lockInstanceName+" ) {");
- unit.emitln(" final long[] nativeUserParam = { 0 };");
- unit.emitln();
+ if( null != javaCallbackEmitter ) {
+ javaCallbackEmitter.emitJavaSetFuncPreCall(unit);
}
if (!returnType.isVoid()) {
unit.emit(" ");
@@ -941,36 +633,9 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
emitCall(binding);
unit.emitln();
- if( null != javaCallback ) {
- final String funcArgName = binding.getArgumentName(javaCallback.setFuncCBParamIdx);
- final String userParamArgName = binding.getArgumentName(javaCallback.setFuncUserParamIdx);
- final String DataClassName = CodeGenUtils.capitalizeString( javaCallback.cbFuncTypeName+"Data" );
- final String KeyClassName;
- final boolean useDataMap;
- if( null != javaCallback.setFuncKeyClassName ) {
- KeyClassName = javaCallback.setFuncKeyClassName;
- useDataMap = true;
- } else {
- KeyClassName = CodeGenUtils.capitalizeString(capIfaceName+"Key");
- useDataMap = javaCallback.setFuncKeyIndices.size() > 0;
- }
- if( DEBUG_JAVACALLBACK ) {
- unit.emitln(" System.err.println(\"ZZZ returned nativeUserParam 0x\"+Long.toHexString(nativeUserParam[0]));");
- }
+ if( null != javaCallbackEmitter ) {
unit.emitln();
- unit.emitln(" if( 0 != nativeUserParam[0] ) {");
- unit.emitln(" // callback registrated -> add will release a previously mapped instance ");
- unit.emitln(" add"+capIfaceName+"("+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, true).toString()+
- "new "+DataClassName+"("+funcArgName+", "+userParamArgName+", nativeUserParam[0]));");
- unit.emitln(" } else {");
- unit.emitln(" // callback released (null func) -> release a previously mapped instance ");
- if( useDataMap ) {
- unit.emitln(" release"+capIfaceName+"( new "+KeyClassName+"( "+binding.getJavaCallSelectArguments(new StringBuilder(), javaCallback.setFuncKeyIndices, false).toString()+" ) );");
- } else {
- unit.emitln(" release"+capIfaceName+"();");
- }
- unit.emitln(" }");
- unit.emitln(" } // synchronized ");
+ javaCallbackEmitter.emitJavaSetFuncPostCall(unit);
}
emitPostCallCleanup(binding);
@@ -1094,14 +759,13 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
needComma = true;
++numArgsEmitted;
}
- if( null != javaCallback ) {
- final String lowIfaceName = CodeGenUtils.decapitalizeString( getInterfaceName() );
- final String lockInstanceName = lowIfaceName+"Lock";
+ if( null != javaCallbackEmitter ) {
if (needComma) {
unit.emit(", ");
}
- unit.emit("\"" + javaCallback.cbMethodSignature + "\", "+lockInstanceName+", nativeUserParam");
- ++numArgsEmitted;
+ final StringBuilder buf = new StringBuilder();
+ numArgsEmitted += javaCallbackEmitter.appendJavaAdditionalJNIArguments(buf);
+ unit.emit(buf.toString());
}
return numArgsEmitted;
}
@@ -1301,12 +965,11 @@ public class JavaMethodBindingEmitter extends FunctionEmitter {
}
}
- protected class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter {
-
- @Override
- protected void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer) {
- writer.print("Interface to C language function: <br> ");
- }
+ protected class InterfaceCommentEmitter extends JavaMethodBindingEmitter.DefaultCommentEmitter {
+ @Override
+ protected void emitBeginning(final FunctionEmitter emitter, final PrintWriter writer) {
+ writer.print("Interface to C language function: <br> ");
}
+ }
}
diff --git a/src/java/com/jogamp/gluegen/JavaType.java b/src/java/com/jogamp/gluegen/JavaType.java
index 682a95a..3d6d839 100644
--- a/src/java/com/jogamp/gluegen/JavaType.java
+++ b/src/java/com/jogamp/gluegen/JavaType.java
@@ -334,6 +334,84 @@ public class JavaType {
}
/**
+ * Appends the descriptor (internal type signature) corresponding to the given Class<?> c.
+ * @param buf the StringBuilder sink
+ * @param c the Class<?> to append the descriptor for
+ * @param useTrueType if true, use the actual Class<?> name for non primitives, otherwise java.lang.Object will be used (flattened)
+ * @return the given StringBuilder sink for chaining
+ */
+ public static StringBuilder appendDescriptor(final StringBuilder buf, final Class<?> c, final boolean useTrueType) {
+ if (c.isPrimitive()) {
+ if (c == Boolean.TYPE) buf.append("Z");
+ else if (c == Byte.TYPE) buf.append("B");
+ else if (c == Character.TYPE) buf.append("C");
+ else if (c == Short.TYPE) buf.append("S");
+ else if (c == Integer.TYPE) buf.append("I");
+ else if (c == Long.TYPE) buf.append("J");
+ else if (c == Float.TYPE) buf.append("F");
+ else if (c == Double.TYPE) buf.append("D");
+ else throw new RuntimeException("Illegal primitive type \"" + c.getName() + "\"");
+ } else {
+ // Arrays and NIO Buffers are always passed down as java.lang.Object.
+ // The only arrays that show up as true arrays in the signature
+ // are the synthetic byte offset arrays created when passing
+ // down arrays of direct Buffers. Compound type wrappers are
+ // passed down as ByteBuffers (no good reason, just to avoid
+ // accidental conflation) so we mangle them differently.
+ if (useTrueType) {
+ if (c.isArray()) {
+ buf.append("[");
+ final Class<?> componentType = c.getComponentType();
+ // Handle arrays of compound type wrappers differently for
+ // convenience of the Java-level glue code generation
+ appendDescriptor(buf, componentType,
+ (componentType == java.nio.ByteBuffer.class));
+ } else {
+ buf.append("L");
+ buf.append(c.getName().replace('.', '/'));
+ buf.append(";");
+ }
+ } else {
+ if (c.isArray()) {
+ buf.append("[");
+ appendDescriptor(buf, c.getComponentType(), false);
+ } else if (c == java.lang.String.class) {
+ buf.append("L");
+ buf.append(c.getName().replace('.', '/'));
+ buf.append(";");
+ } else {
+ buf.append("L");
+ buf.append("java_lang_Object");
+ buf.append(";");
+ }
+ }
+ }
+ return buf;
+ }
+
+ /**
+ * Appends the native (JNI) method-name descriptor corresponding to the given Class<?> c,
+ * i.e. replacing chars {@link #appendDescriptor(StringBuilder, Class, boolean)} as follows
+ * <ul>
+ * <li>`_` -> `_1`</li>
+ * <li>`/` -> `_`</li>
+ * <li>`;` -> `_2`</li>
+ * <li>`[` -> `_3`</li>
+ * </ul>
+ * Only the newly appended segment to the StringBuilder sink will be converted to (JNI) method-name using {@link #toJNIMethodDescriptor(StringBuilder, int)}.
+ * @param buf the StringBuilder sink
+ * @param c the Class<?> to append the descriptor for
+ * @param useTrueType if true, use the actual Class<?> name for non primitives, otherwise java.lang.Object will be used (flattened)
+ * @return the given StringBuilder sink for chaining
+ * @see JNI Spec 2, Chapter 2, Resolving Native Method Names
+ * @see #toJNIMethodDescriptor(StringBuilder)
+ */
+ public static StringBuilder appendJNIDescriptor(final StringBuilder res, final Class<?> c, final boolean useTrueType) {
+ final int start = res.length();
+ return toJNIMethodDescriptor( appendDescriptor(res, c, useTrueType), start );
+ }
+
+ /**
* Converts the assumed descriptor (internal type signature) to a native (JNI) method-name descriptor,
* i.e. replacing chars {@link #getDescriptor()} as follows
* <ul>
@@ -342,6 +420,7 @@ public class JavaType {
* <li>`;` -> `_2`</li>
* <li>`[` -> `_3`</li>
* </ul>
+ * @param descriptor the char sequence holding the original descriptor
* @see JNI Spec 2, Chapter 2, Resolving Native Method Names
*/
public static String toJNIMethodDescriptor(final String descriptor) {
@@ -351,6 +430,36 @@ public class JavaType {
.replace("[", "_3");
}
+ /**
+ * Converts the assumed descriptor (internal type signature) to a native (JNI) method-name descriptor,
+ * i.e. replacing chars {@link #getDescriptor()} as follows
+ * <ul>
+ * <li>`_` -> `_1`</li>
+ * <li>`/` -> `_`</li>
+ * <li>`;` -> `_2`</li>
+ * <li>`[` -> `_3`</li>
+ * </ul>
+ * @param descriptor the char buffer holding the original descriptor
+ * @param start start position of the segment to convert, use 0 if whole buffr shall be converted
+ * @return returns passed descriptor buffer for chaining
+ * @see JNI Spec 2, Chapter 2, Resolving Native Method Names
+ */
+ public static StringBuilder toJNIMethodDescriptor(final StringBuilder descriptor, final int start) {
+ replace(descriptor, start, "_", "_1");
+ replace(descriptor, start, "/", "_");
+ replace(descriptor, start, ";", "_2");
+ replace(descriptor, start, "[", "_3");
+ return descriptor;
+ }
+ private static StringBuilder replace(final StringBuilder buf, int start, final String target, final String replacement) {
+ start = buf.indexOf(target, start);
+ while( 0 <= start ) {
+ buf.replace(start, start + target.length(), replacement);
+ start = buf.indexOf(target, start + replacement.length());
+ }
+ return buf;
+ }
+
/** Returns the String corresponding to the JNI type for this type,
or NULL if it can't be represented (i.e., it's a boxing class
that we need to call getBuffer() on.) */
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
index a280d6e..c20b07a 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressCMethodBindingEmitter.java
@@ -102,17 +102,16 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
}
@Override
- protected int emitArguments() {
- int numEmitted = super.emitArguments();
+ protected int appendArguments(final StringBuilder buf) {
+ int numEmitted = super.appendArguments(buf);
if (callThroughProcAddress) {
if (numEmitted > 0) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit(procAddressJavaTypeName);
- unit.emit(" procAddress");
+ buf.append(procAddressJavaTypeName);
+ buf.append(" procAddress");
++numEmitted;
}
-
return numEmitted;
}
@@ -224,7 +223,7 @@ public class ProcAddressCMethodBindingEmitter extends CMethodBindingEmitter {
protected String jniMangle(final MethodBinding binding) {
final StringBuilder buf = new StringBuilder(super.jniMangle(binding));
if (callThroughProcAddress && 0 <= buf.indexOf("__") ) {
- getJNIMangledArg(Long.TYPE, buf, false); // to account for the additional _addr_ parameter
+ JavaType.appendJNIDescriptor(buf, Long.TYPE, false); // to account for the additional _addr_ parameter
}
return buf.toString();
}
diff --git a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
index 0d5de1c..b6ed21b 100644
--- a/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
+++ b/src/java/com/jogamp/gluegen/procaddress/ProcAddressJavaMethodBindingEmitter.java
@@ -91,19 +91,18 @@ public class ProcAddressJavaMethodBindingEmitter extends JavaMethodBindingEmitte
}
@Override
- protected int emitArguments() {
- int numEmitted = super.emitArguments();
+ protected int appendArguments(final StringBuilder buf) {
+ int numEmitted = super.appendArguments(buf);
if (callThroughProcAddress) {
if (changeNameAndArguments) {
if (numEmitted > 0) {
- unit.emit(", ");
+ buf.append(", ");
}
- unit.emit("long procAddress");
+ buf.append("long procAddress");
++numEmitted;
}
}
-
return numEmitted;
}
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java b/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java
index 406008a..8c1d726 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/Test4JavaCallback.java
@@ -34,7 +34,10 @@ import java.util.Set;
import com.jogamp.common.os.NativeLibrary;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.ALBUFFERCALLBACKTYPESOFT;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.AlBufferCallback0Key;
+import com.jogamp.gluegen.test.junit.generation.Bindingtest2.MessageCallback11aKey;
+import com.jogamp.gluegen.test.junit.generation.Bindingtest2.MessageCallback11bKey;
import com.jogamp.gluegen.test.junit.generation.Bindingtest2.T2_CallbackFunc01;
+import com.jogamp.gluegen.test.junit.generation.Bindingtest2.T2_CallbackFunc11;
import com.jogamp.gluegen.test.junit.generation.impl.Bindingtest2Impl;
import org.junit.AfterClass;
@@ -197,8 +200,9 @@ public class Test4JavaCallback extends BaseClass {
@Override
public void callback(final int buffer, final Object userptr, final int sampledata, final int numbytes) {
final MyUserParam02 myUserParam = (MyUserParam02)userptr;
- id_res[0] = sampledata + numbytes + myUserParam.i;
- myUserParam.j = id_res[0];
+ final long res = sampledata + numbytes + myUserParam.i;
+ id_res[0] = res;
+ myUserParam.j = res;
myUserParam.buffer = buffer;
System.err.println("chapter02.myCallback01: buffer "+buffer+", sampledata "+sampledata+", numbytes "+numbytes);
}
@@ -207,8 +211,9 @@ public class Test4JavaCallback extends BaseClass {
@Override
public void callback(final int buffer, final Object userptr, final int sampledata, final int numbytes) {
final MyUserParam02 myUserParam = (MyUserParam02)userptr;
- id_res[0] = sampledata * numbytes + myUserParam.i;
- myUserParam.j = id_res[0];
+ final long res = sampledata * numbytes + myUserParam.i;
+ id_res[0] = res;
+ myUserParam.j = res;
myUserParam.buffer = buffer;
System.err.println("chapter02.myCallback02: buffer "+buffer+", sampledata "+sampledata+", numbytes "+numbytes);
}
@@ -402,8 +407,9 @@ public class Test4JavaCallback extends BaseClass {
@Override
public void callback(final int buffer, final Object userptr, final int sampledata, final int numbytes) {
final MyUserParam02 myUserParam = (MyUserParam02)userptr;
- id_res[0] = sampledata + numbytes + myUserParam.i;
- myUserParam.j = id_res[0];
+ final long res = sampledata + numbytes + myUserParam.i;
+ id_res[0] = res;
+ myUserParam.j = res;;
myUserParam.buffer = buffer;
System.err.println("chapter03.myCallback01: buffer "+buffer+", sampledata "+sampledata+", numbytes "+numbytes);
}
@@ -412,8 +418,9 @@ public class Test4JavaCallback extends BaseClass {
@Override
public void callback(final int buffer, final Object userptr, final int sampledata, final int numbytes) {
final MyUserParam02 myUserParam = (MyUserParam02)userptr;
- id_res[0] = sampledata * numbytes + myUserParam.i;
- myUserParam.j = id_res[0];
+ final long res = sampledata * numbytes + myUserParam.i;
+ id_res[0] = res;
+ myUserParam.j = res;
myUserParam.buffer = buffer;
System.err.println("chapter03.myCallback02: buffer "+buffer+", sampledata "+sampledata+", numbytes "+numbytes);
}
@@ -633,8 +640,9 @@ public class Test4JavaCallback extends BaseClass {
myUserParam.throwPreAction = false;
throw new RuntimeException("Exception test.pre: chapter04.myCallback01");
}
- id_res[0] = sampledata + numbytes + myUserParam.i;
- myUserParam.j = id_res[0];
+ final long res = sampledata + numbytes + myUserParam.i;
+ id_res[0] = res;
+ myUserParam.j = res;
myUserParam.buffer = buffer;
System.err.println("chapter04.myCallback01: buffer "+buffer+", sampledata "+sampledata+", numbytes "+numbytes);
if( myUserParam.throwPostAction ) {
@@ -651,8 +659,9 @@ public class Test4JavaCallback extends BaseClass {
myUserParam.throwPreAction = false;
throw new RuntimeException("Exception test.pre: chapter04.myCallback02");
}
- id_res[0] = sampledata * numbytes + myUserParam.i;
- myUserParam.j = id_res[0];
+ final long res = sampledata * numbytes + myUserParam.i;
+ id_res[0] = res;
+ myUserParam.j = res;
myUserParam.buffer = buffer;
System.err.println("chapter04.myCallback02: buffer "+buffer+", sampledata "+sampledata+", numbytes "+numbytes);
if( myUserParam.throwPostAction ) {
@@ -872,6 +881,404 @@ public class Test4JavaCallback extends BaseClass {
}
}
+ /**
+ * Test Bindingtest2 with T2_CallbackFunc11 JavaCallback via MessageCallback11a()
+ * using the default MessageCallback11aKey class.
+ */
+ @Test
+ public void chapter11a() throws Exception {
+ final Bindingtest2 bt2 = new Bindingtest2Impl();
+
+ final long userParam01Ptr = 0xAFFEBEAFC0FFEEL;
+ final long userParam02Ptr = 0xC0FFEEDEADBEAFL;
+
+ final long[] id_res = { -1 };
+ final T2_CallbackFunc11 myCallback01 = new T2_CallbackFunc11() {
+ @Override
+ public void callback(final long id, final T2_Callback11UserType usrParam, final long val) {
+ Assert.assertEquals(42, usrParam.getApiVersion()); // native toolkit should have set API version
+ if( 1 == id ) {
+ BaseClass.assertAPTR(userParam01Ptr, usrParam.getData());
+ } else if( 2 == id ) {
+ BaseClass.assertAPTR(userParam02Ptr, usrParam.getData());
+ }
+ final long res = val + usrParam.getI();
+ id_res[0] = res;
+ usrParam.setR(res);
+ usrParam.setId(id);
+ System.err.println("chapter11a.myCallback01: id "+id+", val "+val);
+ }
+ };
+ final T2_CallbackFunc11 myCallback02 = new T2_CallbackFunc11() {
+ @Override
+ public void callback(final long id, final T2_Callback11UserType usrParam, final long val) {
+ Assert.assertEquals(42, usrParam.getApiVersion()); // native toolkit should have set API version
+ if( 1 == id ) {
+ BaseClass.assertAPTR(userParam01Ptr, usrParam.getData());
+ } else if( 2 == id ) {
+ BaseClass.assertAPTR(userParam02Ptr, usrParam.getData());
+ }
+ final long res = val * usrParam.getI();
+ id_res[0] = res;
+ usrParam.setR(res);
+ usrParam.setId(id);
+ System.err.println("chapter11a.myCallback02: id "+id+", val "+val);
+ }
+ };
+ final int id1 = 1;
+ final int id2 = 2;
+ final int id3 = 3;
+ final MessageCallback11aKey id1Key = new MessageCallback11aKey(id1);
+ final MessageCallback11aKey id2Key = new MessageCallback11aKey(id2);
+ final MessageCallback11aKey id3Key = new MessageCallback11aKey(id3);
+ final T2_Callback11UserType userParam01 = T2_Callback11UserType.create(); // native toolkit should set API version
+ userParam01.setData(userParam01Ptr);
+ userParam01.setI(1);
+ final T2_Callback11UserType userParam02 = T2_Callback11UserType.create(); // native toolkit should set API version
+ userParam02.setData(userParam02Ptr);
+ userParam02.setI(2);
+ Assert.assertEquals( 1, userParam01.getI());
+ Assert.assertEquals( 0, userParam01.getR());
+ Assert.assertEquals( 0, userParam01.getId());
+ Assert.assertEquals( 2, userParam02.getI());
+ Assert.assertEquals( 0, userParam02.getR());
+ Assert.assertEquals( 0, userParam02.getId());
+
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id3Key));
+ Assert.assertEquals(0, bt2.getMessageCallback11aKeys().size());
+
+ // 1st mapping: buffer1 -> myCallback01, userParam01
+ bt2.MessageCallback11a(id1, myCallback01, userParam01);
+ Assert.assertEquals(true, bt2.isMessageCallback11aMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id3Key));
+ Assert.assertEquals(userParam01, bt2.getMessageCallback11aUserParam(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11a(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id3Key));
+ Assert.assertEquals(1, bt2.getMessageCallback11aKeys().size());
+ {
+ final Set<MessageCallback11aKey> keys = bt2.getMessageCallback11aKeys();
+ Assert.assertEquals(true, keys.contains(id1Key));
+ Assert.assertEquals(false, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ // 2nd mapping: buffer2 -> myCallback02, userParam02
+ bt2.MessageCallback11a(id2, myCallback02, userParam02);
+ Assert.assertEquals(true, bt2.isMessageCallback11aMapped(id1Key));
+ Assert.assertEquals(true, bt2.isMessageCallback11aMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id3Key));
+ Assert.assertEquals(userParam01, bt2.getMessageCallback11aUserParam(id1Key));
+ Assert.assertEquals(userParam02, bt2.getMessageCallback11aUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11a(id1Key));
+ Assert.assertEquals(myCallback02, bt2.getMessageCallback11a(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id3Key));
+ Assert.assertEquals(2, bt2.getMessageCallback11aKeys().size());
+ {
+ final Set<MessageCallback11aKey> keys = bt2.getMessageCallback11aKeys();
+ Assert.assertEquals(true, keys.contains(id1Key));
+ Assert.assertEquals(true, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ {
+ final Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ bt2.MessageCallback11aInject(id1, 10); // buffer1 -> myCallback01, userParam01
+ }
+ });
+ thread.start();
+ thread.join();
+ Assert.assertEquals( 10+1, id_res[0]);
+ Assert.assertEquals( 1, userParam01.getI());
+ Assert.assertEquals( 10+1, userParam01.getR());
+ Assert.assertEquals( 1, userParam01.getId());
+ Assert.assertEquals( 2, userParam02.getI());
+ Assert.assertEquals( 0, userParam02.getR());
+ Assert.assertEquals( 0, userParam02.getId());
+ }
+ {
+ bt2.MessageCallback11aInject(id2, 10); // buffer2 -> myCallback02, userParam02
+ Assert.assertEquals( 10*2, id_res[0]);
+ Assert.assertEquals( 1, userParam01.getI());
+ Assert.assertEquals( 10+1, userParam01.getR());
+ Assert.assertEquals( 1, userParam01.getId());
+ Assert.assertEquals( 2, userParam02.getI());
+ Assert.assertEquals( 10*2, userParam02.getR());
+ Assert.assertEquals( 2, userParam02.getId());
+ }
+
+ // Switch the callback function for buffer2 -> myCallback01, userParam02
+ bt2.MessageCallback11a(id2, myCallback01, userParam02);
+ Assert.assertEquals(true, bt2.isMessageCallback11aMapped(id1Key));
+ Assert.assertEquals(true, bt2.isMessageCallback11aMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id3Key));
+ Assert.assertEquals(userParam01, bt2.getMessageCallback11aUserParam(id1Key));
+ Assert.assertEquals(userParam02, bt2.getMessageCallback11aUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11a(id1Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11a(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id3Key));
+
+ {
+ bt2.MessageCallback11aInject(id1, 11); // buffer1 -> myCallback01, userParam01
+ Assert.assertEquals( 11+1, id_res[0]);
+ Assert.assertEquals( 1, userParam01.getI());
+ Assert.assertEquals( 11+1, userParam01.getR());
+ Assert.assertEquals( 1, userParam01.getId());
+ Assert.assertEquals( 2, userParam02.getI());
+ Assert.assertEquals( 10*2, userParam02.getR());
+ Assert.assertEquals( 2, userParam02.getId());
+ }
+ {
+ final Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ bt2.MessageCallback11aInject(id2, 22); // buffer2 -> myCallback01, userParam02
+ }
+ });
+ thread.start();
+ thread.join();
+ Assert.assertEquals( 22+2, id_res[0]);
+ Assert.assertEquals( 1, userParam01.getI());
+ Assert.assertEquals( 11+1, userParam01.getR());
+ Assert.assertEquals( 1, userParam01.getId());
+ Assert.assertEquals( 2, userParam02.getI());
+ Assert.assertEquals( 22+2, userParam02.getR());
+ Assert.assertEquals( 2, userParam02.getId());
+ }
+
+ // Just release the buffer2 callback and mapped resources
+ bt2.MessageCallback11a(id2, null, userParam02); // usrptr is not key, only id is key!
+ Assert.assertEquals(true, bt2.isMessageCallback11aMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id3Key));
+ Assert.assertEquals(userParam01, bt2.getMessageCallback11aUserParam(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11a(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id3Key));
+ Assert.assertEquals(1, bt2.getMessageCallback11aKeys().size());
+ {
+ final Set<MessageCallback11aKey> keys = bt2.getMessageCallback11aKeys();
+ Assert.assertEquals(true, keys.contains(id1Key));
+ Assert.assertEquals(false, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ // Just release the buffer1 callback and mapped resources
+ bt2.MessageCallback11a(id1, null, null); // usrptr is not key, only id is key!
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11aMapped(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11aUserParam(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11a(id3Key));
+ Assert.assertEquals(0, bt2.getMessageCallback11aKeys().size());
+ {
+ final Set<MessageCallback11aKey> keys = bt2.getMessageCallback11aKeys();
+ Assert.assertEquals(false, keys.contains(id1Key));
+ Assert.assertEquals(false, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ {
+ bt2.MessageCallback11aInject(id2, 5); // unmapped, no change in data
+ Assert.assertEquals( 22+2, id_res[0]);
+ Assert.assertEquals( 1, userParam01.getI());
+ Assert.assertEquals( 11+1, userParam01.getR());
+ Assert.assertEquals( 1, userParam01.getId());
+ Assert.assertEquals( 2, userParam02.getI());
+ Assert.assertEquals( 22+2, userParam02.getR());
+ Assert.assertEquals( 2, userParam02.getId());
+ }
+ }
+
+ /**
+ * Test Bindingtest2 with T2_CallbackFunc11 JavaCallback via MessageCallback11b()
+ * using the default MessageCallback11bKey class.
+ */
+ @Test
+ public void chapter11b() throws Exception {
+ final Bindingtest2 bt2 = new Bindingtest2Impl();
+
+ final long userParam01Ptr = 0xAFFEBEAFC0FFEEL;
+ final long userParam02Ptr = 0xC0FFEEDEADBEAFL;
+
+ final long[] id_res = { -1 };
+ final T2_CallbackFunc11 myCallback01 = new T2_CallbackFunc11() {
+ @Override
+ public void callback(final long id, final T2_Callback11UserType usrParam, final long val) {
+ Assert.assertEquals(42, usrParam.getApiVersion()); // native toolkit should have set API version
+ if( 1 == id ) {
+ BaseClass.assertAPTR(userParam01Ptr, usrParam.getData());
+ } else if( 2 == id ) {
+ BaseClass.assertAPTR(userParam02Ptr, usrParam.getData());
+ }
+ final long res = val + id;
+ id_res[0] = res;
+ usrParam.setR(res);
+ usrParam.setId(id);
+ System.err.println("chapter11b.myCallback01: id "+id+", val "+val);
+ }
+ };
+ final T2_CallbackFunc11 myCallback02 = new T2_CallbackFunc11() {
+ @Override
+ public void callback(final long id, final T2_Callback11UserType usrParam, final long val) {
+ Assert.assertEquals(42, usrParam.getApiVersion()); // native toolkit should have set API version
+ if( 1 == id ) {
+ BaseClass.assertAPTR(userParam01Ptr, usrParam.getData());
+ } else if( 2 == id ) {
+ BaseClass.assertAPTR(userParam02Ptr, usrParam.getData());
+ }
+ final long res = val * id;
+ id_res[0] = res;
+ usrParam.setR(res);
+ usrParam.setId(id);
+ System.err.println("chapter11b.myCallback02: id "+id+", val "+val);
+ }
+ };
+ final int id1 = 1;
+ final int id2 = 2;
+ final int id3 = 3;
+ final MessageCallback11bKey id1Key = new MessageCallback11bKey(id1);
+ final MessageCallback11bKey id2Key = new MessageCallback11bKey(id2);
+ final MessageCallback11bKey id3Key = new MessageCallback11bKey(id3);
+
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id3Key));
+ Assert.assertEquals(0, bt2.getMessageCallback11bKeys().size());
+
+ // 1st mapping: buffer1 -> myCallback01, userParam01Ptr
+ bt2.MessageCallback11b(id1, myCallback01, userParam01Ptr);
+ Assert.assertEquals(true, bt2.isMessageCallback11bMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11b(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id3Key));
+ Assert.assertEquals(1, bt2.getMessageCallback11bKeys().size());
+ {
+ final Set<MessageCallback11bKey> keys = bt2.getMessageCallback11bKeys();
+ Assert.assertEquals(true, keys.contains(id1Key));
+ Assert.assertEquals(false, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ // 2nd mapping: buffer2 -> myCallback02, userParam02Ptr
+ bt2.MessageCallback11b(id2, myCallback02, userParam02Ptr);
+ Assert.assertEquals(true, bt2.isMessageCallback11bMapped(id1Key));
+ Assert.assertEquals(true, bt2.isMessageCallback11bMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id3Key));
+ Assert.assertEquals(2, bt2.getMessageCallback11bKeys().size());
+ {
+ final Set<MessageCallback11bKey> keys = bt2.getMessageCallback11bKeys();
+ Assert.assertEquals(true, keys.contains(id1Key));
+ Assert.assertEquals(true, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ {
+ final Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ bt2.MessageCallback11bInject(id1, 10); // buffer1 -> myCallback01, userParam01
+ }
+ });
+ thread.start();
+ thread.join();
+ Assert.assertEquals( 10+1, id_res[0]);
+ }
+ {
+ bt2.MessageCallback11bInject(id2, 10); // buffer2 -> myCallback02, userParam02
+ Assert.assertEquals( 10*2, id_res[0]);
+ }
+
+ // Switch the callback function for buffer2 -> myCallback01, userParam02Ptr
+ bt2.MessageCallback11b(id2, myCallback01, userParam02Ptr);
+ Assert.assertEquals(true, bt2.isMessageCallback11bMapped(id1Key));
+ Assert.assertEquals(true, bt2.isMessageCallback11bMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11b(id1Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11b(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id3Key));
+
+ {
+ bt2.MessageCallback11bInject(id1, 11); // buffer1 -> myCallback01, userParam01
+ Assert.assertEquals( 11+1, id_res[0]);
+ }
+ {
+ final Thread thread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ bt2.MessageCallback11bInject(id2, 22); // buffer2 -> myCallback01, userParam02
+ }
+ });
+ thread.start();
+ thread.join();
+ Assert.assertEquals( 22+2, id_res[0]);
+ }
+
+ // Just release the buffer2 callback and mapped resources
+ bt2.MessageCallback11b(id2, null, userParam02Ptr); // usrptr is not key, only id is key!
+ Assert.assertEquals(true, bt2.isMessageCallback11bMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id3Key));
+ Assert.assertEquals(myCallback01, bt2.getMessageCallback11b(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id3Key));
+ Assert.assertEquals(1, bt2.getMessageCallback11bKeys().size());
+ {
+ final Set<MessageCallback11bKey> keys = bt2.getMessageCallback11bKeys();
+ Assert.assertEquals(true, keys.contains(id1Key));
+ Assert.assertEquals(false, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ // Just release the buffer1 callback and mapped resources
+ bt2.MessageCallback11b(id1, null, 0); // usrptr is not key, only id is key!
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id1Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id2Key));
+ Assert.assertEquals(false, bt2.isMessageCallback11bMapped(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11bUserParam(id3Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id1Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id2Key));
+ Assert.assertEquals(null, bt2.getMessageCallback11b(id3Key));
+ Assert.assertEquals(0, bt2.getMessageCallback11bKeys().size());
+ {
+ final Set<MessageCallback11bKey> keys = bt2.getMessageCallback11bKeys();
+ Assert.assertEquals(false, keys.contains(id1Key));
+ Assert.assertEquals(false, keys.contains(id2Key));
+ Assert.assertEquals(false, keys.contains(id3Key));
+ }
+
+ {
+ bt2.MessageCallback11bInject(id2, 5); // unmapped, no change in data
+ Assert.assertEquals( 22+2, id_res[0]);
+ }
+ }
+
public static class CustomMessageCallback11Key {
public CustomMessageCallback11Key() {
}
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c
index 7a7cb43..28fb3aa 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.c
@@ -34,16 +34,16 @@ T2_PointerStorage * createT2PointerStorage() {
for(int i=0; i<10; ++i) {
s->int32PtrArray[i] = &StaticInt32Array[i];
}
- s->undefStructPtr = &StaticUndefStructArray[0];
+ s->undefStructPtr = (T2_UndefStructPtr) &StaticUndefStructArray[0];
for(int i=0; i<10; ++i) {
- s->undefStructPtrArray[i] = &StaticUndefStructArray[i];
+ s->undefStructPtrArray[i] = (T2_UndefStructPtr) &StaticUndefStructArray[i];
}
for(int i=0; i<10; ++i) {
- s->customFuncAVariantsArray[i] = ( i %2 == 0 ) ? CustomFuncA1 : CustomFuncA2;
+ s->customFuncAVariantsArray[i] = (T2_CustomFuncA) ( ( i %2 == 0 ) ? CustomFuncA1 : CustomFuncA2 );
}
for(int i=0; i<10; ++i) {
- s->customFuncBVariantsArray[i] = ( i %2 == 0 ) ? CustomFuncB1 : CustomFuncB2;
+ s->customFuncBVariantsArray[i] = (T2_CustomFuncB) ( ( i %2 == 0 ) ? CustomFuncB1 : CustomFuncB2 );
}
return s;
}
@@ -61,8 +61,8 @@ int Initialize(T2_InitializeOptions* Options) {
strncpy((char*)Options->ProductVersion, "Product Version", 100); // yuck: nonsense-warning
Options->ApiVersion = 1;
Options->Reserved1 = (void*) 0x0000CAFFEEBEEFUL;
- Options->CustomFuncA1 = CustomFuncA1;
- *( (T2_CustomFuncA*) &Options->CustomFuncA2 ) = CustomFuncA2; // yuck: real yuck
+ Options->CustomFuncA1 = (T2_CustomFuncA) CustomFuncA1;
+ *( (T2_CustomFuncA*) &Options->CustomFuncA2 ) = (T2_CustomFuncA) CustomFuncA2; // yuck: real yuck
Options->CustomFuncB1 = CustomFuncB1;
Options->CustomFuncB2 = CustomFuncB2;
Options->customFuncBVariants[0] = CustomFuncB1;
@@ -148,6 +148,8 @@ void alBufferCallback0(int buffer /* key */, int format, int freq, ALBUFFERCALLB
void alBufferCallback0Inject(int buffer, int sampledata, int numbytes) {
if( buffer < 0 || MAX_AL_BUFFER <= buffer ) {
fprintf(stderr, "Error: alBufferCallback0Inject: buffer not in range [0..%d), is %d\n", MAX_AL_BUFFER, buffer);
+ fflush(NULL);
+ return;
}
if( NULL != alBufferCallback0_callback[buffer] ) {
fprintf(stderr, "XXX alBufferCallback0Inject: buffer %d, func %p, user %p\n", buffer, alBufferCallback0_callback[buffer], alBufferCallback0_userptr[buffer]);
@@ -176,6 +178,8 @@ void alBufferCallback1(int buffer /* key */, int format, int freq, ALBUFFERCALLB
void alBufferCallback1Inject(int buffer, int sampledata, int numbytes) {
if( buffer < 0 || MAX_AL_BUFFER <= buffer ) {
fprintf(stderr, "Error: alBufferCallback1Inject: buffer not in range [0..%d), is %d\n", MAX_AL_BUFFER, buffer);
+ fflush(NULL);
+ return;
}
if( NULL != alBufferCallback1_callback[buffer] ) {
fprintf(stderr, "XXX alBufferCallback1Inject: buffer %d, func %p, user %p\n", buffer, alBufferCallback1_callback[buffer], alBufferCallback1_userptr[buffer]);
@@ -184,3 +188,69 @@ void alBufferCallback1Inject(int buffer, int sampledata, int numbytes) {
}
}
+//
+//
+//
+
+static const int MAX_C11_BUFFER = 5;
+
+static T2_CallbackFunc11 MessageCallback11a_callback[] = { NULL, NULL, NULL, NULL, NULL };
+static T2_Callback11UserType* MessageCallback11a_userptr[] = { NULL, NULL, NULL, NULL, NULL };
+
+void MessageCallback11a(size_t id /* key */, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam) {
+ if( id < 0 || MAX_C11_BUFFER <= id ) {
+ fprintf(stderr, "Error: MessageCallback11a: id not in range [0..%d), is %d\n", MAX_C11_BUFFER, id);
+ } else {
+ MessageCallback11a_callback[id] = cbFunc;
+ MessageCallback11a_userptr[id] = (T2_Callback11UserType*)usrParam;
+ if( NULL != usrParam ) {
+ MessageCallback11a_userptr[id]->ApiVersion = 42;
+ }
+ fprintf(stderr, "XXX MessageCallback11a id %d -> func %p, user %p\n", id, cbFunc, usrParam);
+ }
+ fflush(NULL);
+}
+void MessageCallback11aInject(size_t id, long val) {
+ if( id < 0 || MAX_C11_BUFFER <= id ) {
+ fprintf(stderr, "Error: MessageCallback11aInjecta: id not in range [0..%d), is %d\n", MAX_C11_BUFFER, id);
+ fflush(NULL);
+ return;
+ }
+ if( NULL != MessageCallback11a_callback[id] ) {
+ fprintf(stderr, "XXX MessageCallback11aInjecta: id %d, func %p, user %p\n", id, MessageCallback11a_callback[id], MessageCallback11a_userptr[id]);
+ fflush(NULL);
+ (*MessageCallback11a_callback[id])(id, MessageCallback11a_userptr[id], val);
+ }
+}
+
+//
+//
+//
+
+static T2_CallbackFunc11 MessageCallback11b_callback[] = { NULL, NULL, NULL, NULL, NULL };
+static T2_Callback11UserType MessageCallback11b_userptr[];
+
+void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data) {
+ if( id < 0 || MAX_C11_BUFFER <= id ) {
+ fprintf(stderr, "Error: MessageCallback11b: id not in range [0..%d), is %d\n", MAX_C11_BUFFER, id);
+ } else {
+ MessageCallback11b_callback[id] = cbFunc;
+ MessageCallback11b_userptr[id].ApiVersion = 42;
+ MessageCallback11b_userptr[id].Data = Data;
+ fprintf(stderr, "XXX MessageCallback11b id %d -> func %p, user %p\n", id, cbFunc, Data);
+ }
+ fflush(NULL);
+}
+void MessageCallback11bInject(size_t id, long val) {
+ if( id < 0 || MAX_C11_BUFFER <= id ) {
+ fprintf(stderr, "Error: MessageCallback11bInject: id not in range [0..%d), is %d\n", MAX_C11_BUFFER, id);
+ fflush(NULL);
+ return;
+ }
+ if( NULL != MessageCallback11b_callback[id] ) {
+ fprintf(stderr, "XXX MessageCallback11bInject: id %d, func %p, user %p\n", id, MessageCallback11b_callback[id], &MessageCallback11b_userptr[id]);
+ fflush(NULL);
+ (*MessageCallback11b_callback[id])(id, &MessageCallback11b_userptr[id], val);
+ }
+}
+
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
index 472471c..83045cb 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.cfg
@@ -158,14 +158,20 @@ JavaCallbackKey alBufferCallback1 0
# Begin JavaCallback
#
-# typedef void ( * T2_CallbackFunc11)(const T2_Callback11UserType* usrParam);
-# void MessageCallback11(T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam);
-# void InjectMessageCallback11(size_t id, const char* msg);
-ArgumentIsString InjectMessageCallback11 1
-JavaCallbackDef MessageCallback11 T2_CallbackFunc11 0 com.jogamp.gluegen.test.junit.generation.Test4JavaCallback.CustomMessageCallback11Key
+# typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam);
+# void MessageCallback11a(size_t id /* key */, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam);
+# void MessageCallback11aInject(size_t id);
+#JavaCallbackDef MessageCallback11a T2_CallbackFunc11 1 com.jogamp.gluegen.test.junit.generation.Test4JavaCallback.CustomMessageCallback11Key
+JavaCallbackDef MessageCallback11a T2_CallbackFunc11 1
+JavaCallbackKey MessageCallback11a 0
#
# End JavaCallback
+# void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data);
+# void MessageCallback11bInject(size_t id);
+JavaCallbackDef MessageCallback11b 2 T2_CallbackFunc11 1
+JavaCallbackKey MessageCallback11b 0
+
CustomCCode #include "test2.h"
Import com.jogamp.gluegen.test.junit.generation.Bindingtest2
@@ -173,6 +179,7 @@ Import com.jogamp.gluegen.test.junit.generation.T2_PointerStorage
Import com.jogamp.gluegen.test.junit.generation.T2_InitializeOptions
Import com.jogamp.gluegen.test.junit.generation.T2_ThreadAffinity
Import com.jogamp.gluegen.test.junit.generation.T2_UserData
+Import com.jogamp.gluegen.test.junit.generation.T2_Callback11UserType
CustomJavaCode Bindingtest2Impl private static Bindingtest2ProcAddressTable _table = new Bindingtest2ProcAddressTable();
CustomJavaCode Bindingtest2Impl public static void resetProcAddressTable(DynamicLookupHelper lookup) {
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
index d067390..183f905 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/test2.h
@@ -89,15 +89,21 @@ void alBufferCallback1(int buffer /* key */, int format, int freq, ALBUFFERCALLB
void alBufferCallback1Inject(int buffer, int sampledata, int numbytes);
//
-// T2_CallbackFunc11
+// T2_CallbackFunc11[ab]
//
typedef struct {
int32_t ApiVersion;
void* Data;
+ long i;
+ long r;
+ size_t id;
} T2_Callback11UserType;
-typedef void ( * T2_CallbackFunc11)(const T2_Callback11UserType* usrParam);
+typedef void ( * T2_CallbackFunc11)(size_t id, const T2_Callback11UserType* usrParam, long val);
-void MessageCallback11(T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam);
-void InjectMessageCallback11(size_t id, const char* msg);
+void MessageCallback11a(size_t id /* key */, T2_CallbackFunc11 cbFunc, const T2_Callback11UserType* usrParam);
+void MessageCallback11aInject(size_t id, long val);
+
+void MessageCallback11b(size_t id /* key */, T2_CallbackFunc11 cbFunc, void* Data);
+void MessageCallback11bInject(size_t id, long val);
diff --git a/www/index.html b/www/index.html
index 812d3b3..b424ec5 100644
--- a/www/index.html
+++ b/www/index.html
@@ -73,7 +73,7 @@
potential calls to <a href="../doc/GlueGen_Mapping.html#struct-function-pointer-support">embedded function pointer</a>.
</p>
<p>
- GlueGen supports <a href="../doc/GlueGen_Mapping.html#java-callback-from-native-c-api-support">registering Java™ callback methods</a>
+ GlueGen supports <a href="../doc/GlueGen_Mapping.html#java-callback">registering Java™ callback methods</a>
to receive asynchronous and off-thread native toolkit events,
where a generated native callback function dispatches the events to Java™.
</p>