diff --git a/.github/workflows/build_and_upload.yml b/.github/workflows/build_and_upload.yml
index 614cce03..55d366da 100644
--- a/.github/workflows/build_and_upload.yml
+++ b/.github/workflows/build_and_upload.yml
@@ -51,16 +51,28 @@ jobs:
value: $env:PATH;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build
- name: Build idl-helper project
- run: ./gradlew idl_helper_build_project_windows64
+ run: ./gradlew idl_helper_build_project_jni_windows64
+
+ - name: Build idl-helper FFM project
+ run: ./gradlew idl_helper_build_project_ffm_windows64
- name: Build TestLib project
- run: ./gradlew TestLib_build_project_windows64
+ run: ./gradlew TestLib_build_project_jni_windows64
+
+ - name: Build TestLib FFM project
+ run: ./gradlew TestLib_build_project_ffm_windows64
- name: Build Shared LibA project
- run: ./gradlew LibA_build_project_windows64
+ run: ./gradlew LibA_build_project_jni_windows64
+
+ - name: Build Shared LibA FFM project
+ run: ./gradlew LibA_build_project_ffm_windows64
- name: Build Shared LibB project
- run: ./gradlew LibB_build_project_windows64
+ run: ./gradlew LibB_build_project_jni_windows64
+
+ - name: Build Shared LibB FFM project
+ run: ./gradlew LibB_build_project_ffm_windows64
# - name: Test Shared Lib
# run: ./gradlew :examples:SharedLib:app:core:test
@@ -98,16 +110,28 @@ jobs:
run: chmod +x ./gradlew
- name: Build idl-helper project
- run: ./gradlew idl_helper_build_project_linux64
+ run: ./gradlew idl_helper_build_project_jni_linux64
+
+ - name: Build idl-helper FFM project
+ run: ./gradlew idl_helper_build_project_ffm_linux64
- name: Build TestLib project
- run: ./gradlew TestLib_build_project_linux64
+ run: ./gradlew TestLib_build_project_jni_linux64
+
+ - name: Build TestLib FFM project
+ run: ./gradlew TestLib_build_project_ffm_linux64
- name: Build Shared LibA project
- run: ./gradlew LibA_build_project_linux64
+ run: ./gradlew LibA_build_project_jni_linux64
+
+ - name: Build Shared LibA FFM project
+ run: ./gradlew LibA_build_project_ffm_linux64
- name: Build Shared LibB project
- run: ./gradlew LibB_build_project_linux64
+ run: ./gradlew LibB_build_project_jni_linux64
+
+ - name: Build Shared LibB FFM project
+ run: ./gradlew LibB_build_project_ffm_linux64
# - name: Test Shared Lib
# run: ./gradlew :examples:SharedLib:app:core:test
@@ -141,19 +165,34 @@ jobs:
run: chmod +x ./gradlew
- name: Build project idl-helper
- run: ./gradlew idl_helper_build_project_mac64
+ run: ./gradlew idl_helper_build_project_jni_mac64
+
+ - name: Build idl-helper FFM project
+ run: ./gradlew idl_helper_build_project_ffm_mac64
- name: Build TestLib project
run: |
- ./gradlew TestLib_build_project_mac64
+ ./gradlew TestLib_build_project_jni_mac64
+
+ - name: Build TestLib FFM project
+ run: |
+ ./gradlew TestLib_build_project_ffm_mac64
# - name: Build Shared LibA project
# run: |
-# ./gradlew LibA_build_project_mac64
+# ./gradlew LibA_build_project_jni_mac64
+#
+# - name: Build Shared LibA FFM project
+# run: |
+# ./gradlew LibA_build_project_ffm_mac64
#
# - name: Build Shared LibB project
# run: |
-# ./gradlew LibB_build_project_mac64
+# ./gradlew LibB_build_project_jni_mac64
+#
+# - name: Build Shared LibB FFM project
+# run: |
+# ./gradlew LibB_build_project_ffm_mac64
# - name: Test Shared Lib
# run: ./gradlew :examples:SharedLib:app:core:test
@@ -187,19 +226,34 @@ jobs:
run: chmod +x ./gradlew
- name: Build project idl-helper
- run: ./gradlew idl_helper_build_project_macArm
+ run: ./gradlew idl_helper_build_project_jni_macArm
+
+ - name: Build idl-helper FFM project
+ run: ./gradlew idl_helper_build_project_ffm_macArm
- name: Build TestLib project
run: |
- ./gradlew TestLib_build_project_macArm
+ ./gradlew TestLib_build_project_jni_macArm
+
+ - name: Build TestLib FFM project
+ run: |
+ ./gradlew TestLib_build_project_ffm_macArm
# - name: Build Shared LibA project
# run: |
-# ./gradlew LibA_build_project_macArm
+# ./gradlew LibA_build_project_jni_macArm
+#
+# - name: Build Shared LibA FFM project
+# run: |
+# ./gradlew LibA_build_project_ffm_macArm
#
# - name: Build Shared LibB project
# run: |
-# ./gradlew LibB_build_project_macArm
+# ./gradlew LibB_build_project_jni_macArm
+#
+# - name: Build Shared LibB FFM project
+# run: |
+# ./gradlew LibB_build_project_ffm_macArm
# - name: Test Shared Lib
# run: ./gradlew :examples:SharedLib:app:core:test
@@ -289,12 +343,12 @@ jobs:
run: chmod +x ./gradlew
- name: Build project idl-helper
- run: ./gradlew idl_helper_build_project_android
+ run: ./gradlew idl_helper_build_project_jni_android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- name: Build project
- run: ./gradlew TestLib_build_project_android
+ run: ./gradlew TestLib_build_project_jni_android
env:
NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
diff --git a/.gitignore b/.gitignore
index fdc75723..9f1c56f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,16 +31,26 @@ out/
**/idl-helper/idl-helper-teavm/src/main/java/**
**/idl-helper/idl-helper-core/src/main/java/**
+**/idl-helper/idl-helper-desktop-ffm/src/main/java/**
+**/idl-helper/idl-helper-desktop-jni/src/main/java/**
**/webapp/**
**/lib/core/src/**
**/lib/desktop/src/main/**
**/lib/lib-teavm/src/main/java/**
**/lib/lib-core/src/main/java/**
+**/lib/lib-desktop-ffm/src/main/java/**
+**/lib/lib-desktop-jni/src/main/java/**
**/libA/lib-teavm/src/main/java/**
**/libA/lib-core/src/main/java/**
+**/libA/lib-desktop-ffm/src/main/java/**
+**/libA/lib-desktop-jni/src/main/java/**
**/libB/lib-teavm/src/main/java/**
**/libB/lib-core/src/main/java/**
+**/libB/lib-desktop-ffm/src/main/java/**
+**/libB/lib-desktop-jni/src/main/java/**
**/app/android/libs/
.codiumai
-.kotlin/
\ No newline at end of file
+.kotlin/
+
+LOCAL_AGENT.MD
\ No newline at end of file
diff --git a/.run/LibA_build_project_android.run.xml b/.run/LibA_build_project_android.run.xml
deleted file mode 100644
index 85112d31..00000000
--- a/.run/LibA_build_project_android.run.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
+
+ A Java code-generation library that bridges C/C++ native code to JVM platforms — desktop, mobile, and web.
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- jParser
+
+ * Each benchmark measures the cost of crossing the Java → native boundary for + * different parameter types. The native work is intentionally trivial so the + * measurement isolates bridge overhead, not native computation. + *
+ * Results are printed to stdout. Run this on desktop with either lib-core (JNI)
+ * or lib-ffm (FFM) on the classpath to compare. On TeaVM the iteration count
+ * is reduced automatically.
+ */
+public class NativeBridgeBenchmark {
+
+ // ---------------------------------------------------------------------------
+ // Configuration
+ // ---------------------------------------------------------------------------
+
+ /** Number of warm-up iterations (allows JIT to stabilise). */
+ private static final int WARMUP_ITERATIONS = 2;
+ /** Number of timed iterations whose median is reported. */
+ private static final int TIMED_ITERATIONS = 3;
+
+ /** Calls per timed iteration – adjusted for TeaVM. */
+ private static long CALLS_PER_ITERATION = 1_000_000L;
+
+ // Reusable native objects – allocated once to avoid measuring allocation.
+ private static TestMethodClass methodObj;
+ private static TestObjectClass objectA;
+ private static TestObjectClass objectB;
+ private static TestAttributeClass attrObj;
+ private static TestBufferManualClass bufferObj;
+ private static IDLIntArray intArray;
+ private static ByteBuffer byteBuffer;
+
+ /** Collected results for CSV export. */
+ private static final ArrayList
+ * Usage: {@code java NativeBridgeBenchmarkCompare
+ * Each frame executes a fixed number of native calls for the current scenario,
+ * then returns to let GDX render. A state machine cycles through all scenarios,
+ * measuring average and minimum FPS for each.
+ *
+ * This complements {@link NativeBridgeBenchmark} which measures raw throughput
+ * in a tight loop. The FPS benchmark shows real-world frame rate impact.
+ */
+public class NativeBridgeFpsBenchmark {
+
+ // ---------------------------------------------------------------------------
+ // Configuration
+ // ---------------------------------------------------------------------------
+
+ /** Native calls executed per frame for every scenario. */
+ private static final int CALLS_PER_FRAME = 50_000;
+ /** Seconds to warm up before measuring (lets JIT stabilise). */
+ private static final float WARMUP_SECONDS = 2f;
+ /** Seconds to measure FPS after warm-up. */
+ private static final float MEASURE_SECONDS = 5f;
+
+ // ---------------------------------------------------------------------------
+ // State machine
+ // ---------------------------------------------------------------------------
+
+ private enum State { IDLE, WARMUP, MEASURE, NEXT, DONE }
+
+ private State state = State.IDLE;
+ private float elapsed;
+ private int frameCount;
+ private float minFrameTime; // worst (longest) frame during measurement
+ private int scenarioIndex;
+
+ // Reusable native objects
+ private TestMethodClass methodObj;
+ private TestObjectClass objectA;
+ private TestObjectClass objectB;
+ private TestAttributeClass attrObj;
+ private TestBufferManualClass bufferObj;
+ private IDLIntArray intArray;
+ private ByteBuffer byteBuffer;
+
+ // Scenario definitions
+ private String[] labels;
+ private Runnable[] workloads;
+
+ // Collected results
+ private final ArrayList
+ * Usage: {@code java NativeBridgeFpsBenchmarkCompare For each native method, generates:
+ *
+ *
+ */
+public class FFMCodeParser extends IDLDefaultCodeParser {
+
+ private static final String HEADER_CMD = "FFM";
+
+ // Same template tags as CppCodeParser (the C++ code is largely the same)
+ protected static final String TEMPLATE_TAG_TYPE = "[TYPE]";
+ protected static final String TEMPLATE_TAG_METHOD = "[METHOD]";
+ protected static final String TEMPLATE_TAG_OPERATOR = "[OPERATOR]";
+ protected static final String TEMPLATE_TAG_ATTRIBUTE = "[ATTRIBUTE]";
+ protected static final String TEMPLATE_TAG_ENUM = "[ENUM]";
+ protected static final String TEMPLATE_TAG_ATTRIBUTE_TYPE = "[ATTRIBUTE_TYPE]";
+ protected static final String TEMPLATE_TAG_RETURN_TYPE = "[RETURN_TYPE]";
+ protected static final String TEMPLATE_TAG_CONST = "[CONST]";
+ protected static final String TEMPLATE_TAG_COPY_TYPE = "[COPY_TYPE]";
+ protected static final String TEMPLATE_TAG_COPY_PARAM = "[COPY_PARAM]";
+ protected static final String TEMPLATE_TAG_CONSTRUCTOR = "[CONSTRUCTOR]";
+ protected static final String TEMPLATE_TAG_CAST = "[CAST]";
+
+ // C++ templates — identical to CppCodeParser but with int64_t casts instead of jlong
+ protected static final String GET_CONSTRUCTOR_OBJ_POINTER_TEMPLATE =
+ "\nreturn (int64_t)new [CONSTRUCTOR];\n";
+
+ protected static final String METHOD_DELETE_OBJ_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "delete nativeObject;\n";
+
+ // --- Attribute templates (int64_t instead of jlong, int32_t instead of jint) ---
+
+ protected static final String ATTRIBUTE_SET_PRIMITIVE_STATIC_TEMPLATE =
+ "\n[TYPE]::[ATTRIBUTE] = [ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_SET_PRIMITIVE_STATIC_TEMPLATE =
+ "\n[TYPE]::[ATTRIBUTE][index] = [ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_SET_PRIMITIVE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[ATTRIBUTE] = [CAST][ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_SET_PRIMITIVE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[ATTRIBUTE][index] = [CAST][ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_SET_OBJECT_POINTER_STATIC_TEMPLATE =
+ "\n[TYPE]::[ATTRIBUTE] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n";
+
+ protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_STATIC_TEMPLATE =
+ "\n[TYPE]::[ATTRIBUTE][index] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n";
+
+ protected static final String ATTRIBUTE_SET_OBJECT_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[ATTRIBUTE] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n";
+
+ protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[ATTRIBUTE][index] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n";
+
+ protected static final String ATTRIBUTE_SET_OBJECT_VALUE_STATIC_TEMPLATE =
+ "\n[TYPE]::[ATTRIBUTE] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n";
+
+ protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_STATIC_TEMPLATE =
+ "\n[TYPE]::[ATTRIBUTE][index] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n";
+
+ protected static final String ATTRIBUTE_SET_OBJECT_VALUE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[ATTRIBUTE] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n";
+
+ protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[ATTRIBUTE][index] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n";
+
+ protected static final String ATTRIBUTE_GET_OBJECT_VALUE_STATIC_TEMPLATE =
+ "\nreturn (int64_t)&[TYPE]::[ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_STATIC_TEMPLATE =
+ "\nreturn (int64_t)&[TYPE]::[ATTRIBUTE][index];\n";
+
+ protected static final String ATTRIBUTE_GET_OBJECT_VALUE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return (int64_t)&nativeObject->[ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return (int64_t)&nativeObject->[ATTRIBUTE][index];\n";
+
+ protected static final String ATTRIBUTE_GET_OBJECT_POINTER_STATIC_TEMPLATE =
+ "\nreturn (int64_t)[TYPE]::[ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_STATIC_TEMPLATE =
+ "\nreturn (int64_t)([TYPE]::[ATTRIBUTE][index]);\n";
+
+ protected static final String ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "[CONST][ATTRIBUTE_TYPE]* attr = nativeObject->[ATTRIBUTE];\n" +
+ "return (int64_t)attr;\n";
+
+ protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "[CONST][ATTRIBUTE_TYPE]* attr = (nativeObject->[ATTRIBUTE][index]);\n" +
+ "return (int64_t)attr;\n";
+
+ protected static final String ATTRIBUTE_GET_PRIMITIVE_STATIC_TEMPLATE =
+ "\nreturn [TYPE]::[ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_GET_PRIMITIVE_STATIC_TEMPLATE =
+ "\nreturn [TYPE]::[ATTRIBUTE][index];\n";
+
+ protected static final String ATTRIBUTE_GET_PRIMITIVE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return [CAST]nativeObject->[ATTRIBUTE];\n";
+
+ protected static final String ATTRIBUTE_ARRAY_GET_PRIMITIVE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return [CAST]nativeObject->[ATTRIBUTE][index];\n";
+
+ // --- Method templates ---
+
+ protected static final String METHOD_GET_OBJ_VALUE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "static [COPY_TYPE] [COPY_PARAM];\n" +
+ "[COPY_PARAM] = nativeObject->[METHOD];\n" +
+ "return (int64_t)&[COPY_PARAM];";
+
+ protected static final String METHOD_GET_OBJ_VALUE_ARITHMETIC_OPERATOR_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "static [COPY_TYPE] [COPY_PARAM];\n" +
+ "[COPY_PARAM] = [OPERATOR];\n" +
+ "return (int64_t)&[COPY_PARAM];";
+
+ protected static final String METHOD_GET_OBJ_VALUE_STATIC_TEMPLATE =
+ "\nstatic [COPY_TYPE] [COPY_PARAM];\n" +
+ "[COPY_PARAM] = [TYPE]::[METHOD];\n" +
+ "return (int64_t)&[COPY_PARAM];";
+
+ protected static final String METHOD_CALL_VOID_STATIC_TEMPLATE =
+ "\n[TYPE]::[METHOD];\n";
+
+ protected static final String METHOD_CALL_VOID_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "nativeObject->[METHOD];\n";
+
+ protected static final String METHOD_GET_OBJ_POINTER_STATIC_TEMPLATE =
+ "\nreturn (int64_t)[TYPE]::[METHOD];\n";
+
+ protected static final String METHOD_GET_OBJ_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "[CONST][RETURN_TYPE]* obj = nativeObject->[METHOD];\n" +
+ "return (int64_t)obj;\n";
+
+ protected static final String METHOD_GET_OBJ_POINTER_OPERATOR_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "[CONST][RETURN_TYPE]* obj = [OPERATOR];\n" +
+ "return (int64_t)obj;\n";
+
+ protected static final String METHOD_GET_REF_OBJ_POINTER_STATIC_TEMPLATE =
+ "\nreturn (int64_t)&[TYPE]::[METHOD];\n";
+
+ protected static final String METHOD_GET_REF_OBJ_POINTER_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return (int64_t)&nativeObject->[METHOD];\n";
+
+ protected static final String METHOD_GET_REF_OBJ_POINTER_OPERATOR_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return (int64_t)&[OPERATOR];\n";
+
+ protected static final String METHOD_GET_PRIMITIVE_STATIC_TEMPLATE =
+ "\nreturn [CAST][TYPE]::[METHOD];\n";
+
+ protected static final String METHOD_GET_PRIMITIVE_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return [CAST]nativeObject->[METHOD];\n";
+
+ protected static final String METHOD_GET_PRIMITIVE_OPERATOR_TEMPLATE =
+ "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" +
+ "return ([OPERATOR]);";
+
+ protected static final String ENUM_GET_INT_TEMPLATE =
+ "\nreturn (int64_t)[ENUM];\n";
+
+ private final FFMNativeCodeGenerator cppGenerator;
+ private final FFMMethodHandleRegistry registry = new FFMMethodHandleRegistry();
+
+ public FFMCodeParser(FFMNativeCodeGenerator cppGenerator, String cppDir) {
+ this(cppGenerator, null, "", cppDir);
+ }
+
+ public FFMCodeParser(FFMNativeCodeGenerator cppGenerator, IDLReader idlReader, String basePackage, String cppDir) {
+ super(basePackage, HEADER_CMD, idlReader, cppDir);
+ this.cppGenerator = cppGenerator;
+ }
+
+ // ==================== IDL Generation Hooks ====================
+
+ @Override
+ public void onIDLConstructorGenerated(JParser jParser, IDLConstructor idlConstructor,
+ ClassOrInterfaceDeclaration classDeclaration,
+ ConstructorDeclaration constructorDeclaration,
+ MethodDeclaration nativeMethodDeclaration) {
+ IDLClass idlClass = idlConstructor.idlClass;
+ String classTypeName = idlClass.getCPPName();
+
+ NodeList