[Kotlin] Generalize JNI signature logic.

There's going to be a third client for this in the
C -> Kotlin structure converters.

Change-Id: I36f50523f9ebd08500b4b997e7b1add404d53ea5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/197994
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Jim Blackler <jimblackler@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/generator/templates/art/api_jni_types.kt b/generator/templates/art/api_jni_types.kt
index 7525672..2af0259 100644
--- a/generator/templates/art/api_jni_types.kt
+++ b/generator/templates/art/api_jni_types.kt
@@ -52,3 +52,35 @@
         {{ jni_primitives[type.name.get()] }}
     {% endif %}
 {% endmacro %}
+
+{% macro jni_signature(member) %}
+    {%- if member.length == 'strlen' -%}
+        Ljava/lang/String;
+    {%- elif member.length and member.length != 'constant' -%}
+        {%- if member.type.category in ['bitmask', 'enum', 'function pointer', 'object', 'structure'] -%}
+            //*  JvmInline does not inline bitmask/enums in arrays.
+            [L{{ jni_name(member.type) }};
+        {%- elif member.type.name.get() == 'uint32_t' -%}
+            [I
+        {%- else -%}
+            {{ unreachable_code() }}
+        {%- endif -%}
+    {%- elif member.type.category in ['function pointer', 'object', 'structure'] -%}
+        L{{ jni_name(member.type) }};
+    {%- elif member.type.name.get() in ['int', 'int64_t', 'uint64_t', 'size_t', 'void'] -%}  {# remove void #}
+        J
+    {%- elif member.type.name.get() in ['int', 'int32_t', 'uint32_t'] or member.type.category in ['bitmask', 'enum'] -%}
+        //*  JvmInline makes lone bitmask/enums appear as integer to JNI.
+        I
+    {%- elif member.type.name.get() in ['int16_t', 'uint16_t'] -%}
+        S
+    {%- elif member.type.name.get() == 'double' -%}
+        D
+    {%- elif member.type.name.get() == 'float' -%}
+        F
+    {%- elif member.type.name.get() == 'bool' -%}
+        Z
+    {%- else -%}
+        {{ unreachable_code() }}
+    {%- endif -%}
+{% endmacro %}
diff --git a/generator/templates/art/methods.cpp b/generator/templates/art/methods.cpp
index c5493ee..1ec546f 100644
--- a/generator/templates/art/methods.cpp
+++ b/generator/templates/art/methods.cpp
@@ -24,7 +24,7 @@
 //* 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.
-{% from 'art/api_jni_types.kt' import arg_to_jni_type, to_jni_type with context %}
+{% from 'art/api_jni_types.kt' import arg_to_jni_type, jni_signature, to_jni_type with context %}
 #include <jni.h>
 #include <stdlib.h>
 #include "dawn/webgpu.h"
@@ -182,15 +182,7 @@
                 jmethodID callbackMethod = env->GetMethodID(
                         env->FindClass("{{ jni_name(arg.type) }}"), "callback", "(
                     {%- for callbackArg in filter_arguments(arg.type.arguments) -%}
-                        {%- if callbackArg.type.category in ['bitmask', 'enum'] -%}
-                            I
-                        {%- elif callbackArg.type.category in ['object', 'structure'] -%}
-                            L{{ jni_name(callbackArg.type) }};
-                        {%- elif callbackArg.type.name.get() == 'char' -%}
-                            Ljava/lang/String;
-                        {%- else -%}
-                            {{ unreachable_code() }}
-                        {%- endif -%}
+                        {{- jni_signature(callbackArg) -}}
                     {%- endfor %})V");
 
                 //* Call the callback with all converted parameters.
diff --git a/generator/templates/art/structures.cpp b/generator/templates/art/structures.cpp
index bfb14db..52e476f 100644
--- a/generator/templates/art/structures.cpp
+++ b/generator/templates/art/structures.cpp
@@ -24,6 +24,8 @@
 //* 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.
+{% from 'art/api_jni_types.kt' import jni_signature with context %}
+
 #include <jni.h>
 #include "dawn/webgpu.h"
 #include "structures.h"
@@ -39,23 +41,20 @@
 
         //* Convert each member in turn from corresponding members of the Kotlin object obtained via
         //* JNI calls
-        {% for member in structure.members if include_structure_member(structure, member) %}
-            {% if member.length == 'strlen' %} {
-                jobject mObj = env->CallObjectMethod(obj,
-                        env->GetMethodID(clz, "get{{ member.name.CamelCase() }}",
-                                "()Ljava/lang/String;"));
+        {% for member in structure.members if include_structure_member(structure, member) %} {
+            jmethodID method = env->GetMethodID(
+                    clz, "get{{ member.name.CamelCase() }}", "(){{ jni_signature(member) }}");
+            {% if member.length == 'strlen' %}
+                jobject mObj = env->CallObjectMethod(obj, method);
                 if (mObj) {
                     //* TODO(b/330293719): free associated resources.
                     converted->{{ member.name.camelCase() }} =
                             env->GetStringUTFChars(reinterpret_cast<jstring>(mObj), 0);
                 }
-            }
-            {% elif member.constant_length == 1 %} {
+            {% elif member.constant_length == 1 %}
                 {% if member.type.category == 'structure' %}
                     //* Convert optional structure if present.
-                    jobject mObj = env->CallObjectMethod(obj,
-                            env->GetMethodID(clz, "get{{ member.name.CamelCase() }}",
-                                    "()L{{ jni_name(member.type) }};"));
+                    jobject mObj = env->CallObjectMethod(obj, method);
                     if (mObj) {
                         //* TODO(b/330293719): free associated resources.
                         auto convertedMember = new {{ as_cType(member.type.name) }}();
@@ -63,13 +62,11 @@
                         converted->{{ member.name.camelCase() }} = convertedMember;
                     }
                 {% elif member.type.name.get() == 'void' %}
-                    converted->{{ member.name.camelCase() }} = reinterpret_cast<void*>(
-                            env->CallLongMethod(obj, env->GetMethodID(
-                                    clz, "get{{ member.name.CamelCase() }}", "()J")));
+                    converted->{{ member.name.camelCase() }} =
+                            reinterpret_cast<void*>(env->CallLongMethod(obj, method));
                 {% else %}
                     {{ unreachable_code() }}
                 {% endif %}
-            }
 
             {% elif member.length %}
                 {% if member.constant_length %}
@@ -78,8 +75,7 @@
                 //* Convert container, including the length field.
                 {% if member.type.name.get() == 'uint32_t' %} {
                     //* This container type is represented in Kotlin as a primitive array.
-                    jintArray array = static_cast<jintArray>(env->CallObjectMethod(obj,
-                            env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()[I")));
+                    jintArray array = static_cast<jintArray>(env->CallObjectMethod(obj, method));
                     //* TODO(b/330293719): free associated resources.
                     converted->{{ member.name.camelCase() }} =
                             reinterpret_cast<{{ as_cType(member.type.name) }}*>(
@@ -88,9 +84,7 @@
                 }
                 {% else %} {
                     //* These container types are represented in Kotlin as arrays of objects.
-                    jmethodID getMethod = env->GetMethodID(clz,
-                            "get{{ member.name.CamelCase() }}", "()[L{{ jni_name(member.type) }};");
-                    auto in = static_cast<jobjectArray>(env->CallObjectMethod(obj, getMethod));
+                    auto in = static_cast<jobjectArray>(env->CallObjectMethod(obj, method));
                     size_t length = env->GetArrayLength(in);
                     //* TODO(b/330293719): free associated resources.
                     auto out = new {{ as_cType(member.type.name) }}[length]();
@@ -125,9 +119,8 @@
                 {% endif %}
 
             //* From here members are single values.
-            {% elif member.type.category == 'object' %} {
-                jobject mObj = env->CallObjectMethod(obj, env->GetMethodID(clz,
-                        "get{{ member.name.CamelCase() }}", "()L{{ jni_name(member.type) }};"));
+            {% elif member.type.category == 'object' %}
+                jobject mObj = env->CallObjectMethod(obj, method);
                 if (mObj) {
                     jclass memberClass = env->FindClass("{{ jni_name(member.type) }}");
                     jmethodID getHandle = env->GetMethodID(memberClass, "getHandle", "()J");
@@ -135,39 +128,33 @@
                             reinterpret_cast<{{ as_cType(member.type.name) }}>(
                                     env->CallLongMethod(mObj, getHandle));
                 }
-            }
-            {% elif member.type.category == 'structure' or member.type.category == 'callback info' %}
-                //* Mandatory structure.
-                Convert(env, env->CallObjectMethod(obj,
-                        env->GetMethodID(clz, "get{{ member.name.CamelCase() }}",
-                                "()L{{ jni_name(member.type) }};")),
-                                &converted->{{ member.name.camelCase() }});
-            {% elif member.type.name.get() == 'bool' %}
-                converted->{{ member.name.camelCase() }} = env->CallBooleanMethod(obj,
-                        env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()Z"));
-            {% elif member.type.name.get() == 'uint16_t' %}
-                converted->{{ member.name.camelCase() }} =
-                        static_cast<{{ as_cType(member.type.name) }}>(env->CallShortMethod(obj,
-                                env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()S")));
-            {% elif member.type.name.get() in ['int', 'int32_t', 'uint32_t']
-                    or member.type.category in ['bitmask', 'enum'] %}
-                converted->{{ member.name.camelCase() }} =
-                        static_cast<{{ as_cType(member.type.name) }}>(env->CallIntMethod(obj,
-                                env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()I")));
-            {% elif member.type.name.get() == 'float' %}
-                converted->{{ member.name.camelCase() }} = env->CallFloatMethod(obj,
-                        env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()F"));
-            {% elif member.type.name.get() in ['size_t', 'uint64_t'] %}
-                converted->{{ member.name.camelCase() }} =
-                        static_cast<{{ as_cType(member.type.name) }}>(env->CallLongMethod(obj,
-                                env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()J")));
-            {% elif member.type.name.get() == 'double' %}
-                converted->{{ member.name.camelCase() }} = env->CallDoubleMethod(obj,
-                        env->GetMethodID(clz, "get{{ member.name.CamelCase() }}", "()D"));
             {% else %}
-                {{ unreachable_code() }}
+                {% if member.type.category == 'structure' or member.type.category == 'callback info' %}
+                    //* Mandatory structure.
+                    Convert(env, env->CallObjectMethod(obj, method),
+                            &converted->{{ member.name.camelCase() }});
+                {% else %}
+                    converted->{{ member.name.camelCase() }} =
+                            static_cast<{{ as_cType(member.type.name) }}>(env->
+                    {% if member.type.name.get() == 'bool' %}
+                        CallBooleanMethod
+                    {% elif member.type.name.get() == 'uint16_t' %}
+                        CallShortMethod
+                    {% elif member.type.name.get() in ['int', 'int32_t', 'uint32_t']
+                            or member.type.category in ['bitmask', 'enum'] %}
+                        CallIntMethod
+                    {% elif member.type.name.get() == 'float' %}
+                        CallFloatMethod
+                    {% elif member.type.name.get() in ['size_t', 'uint64_t'] %}
+                        CallLongMethod
+                    {% elif member.type.name.get() == 'double' %}
+                        CallDoubleMethod
+                    {% else %}
+                        {{ unreachable_code() }}
+                    {% endif %} (obj, method));
+                {% endif %}
             {% endif %}
-        {% endfor %}
+        } {% endfor %}
 
         //* Set up the chain type and links for child objects.
         {% if structure.chained %}