Electrostat-Lab / jSnapLoader

A high-performance cross-platform native Library loader API for JVM Applications
BSD 3-Clause "New" or "Revised" License
3 stars 2 forks source link

[DLCs-Pattern] Create a core native DLL Loader libraries and a pattern for DLCs using the Finite-Automata model #35

Open pavly-gerges opened 2 months ago

pavly-gerges commented 2 months ago

This is an enhancement proposal that entails building a native DLL Loader API coded in C, so that the native libraries (e.g., Bullet Physics) can dynamically link other dependencies through a generic JNI layer without rewriting JNI layers for those native libraries. This issue requires the plugins from the Electrostatic-Sandbox project.

pavly-gerges commented 2 months ago

Here is a simple example to what the provisional design might entail:

[electrostatic4j_dll_loader_DllPluginLoader.cpp]

#include <jni.h>
#include <electrostatic4j_dll_loader_DllPluginLoader.h>
#include <dll_loader_cpp_ext.h>
#include <jni/util.h>
#include <electrostatic/algorithm/arithmos/adt/map.h>

extern "C" {
   hash_map map = {
       ...
    };

   JNIEXPORT void 
         JNICALL Java_electrostatic4j_dll_loader_DllPluginLoader_loadFunction(JNIEnv *env, jweak file_handle, jstring handle, jclass clazz) {
         const char *c_handle = to_cstring(env, handle);
         void *c_filehandle = to_cfilehandle(env, file_handle);
         void *address = loadFunction(c_filehandle, c_handle);
         map->insert(HASH(c_handle), address);
   }

     JNIEXPORT void 
         JNICALL Java_electrostatic4j_dll_loader_DllPluginLoader_callMethod(JNIEnv *env, jstring handle, jobjectArray params, jclass clazz) {
         const char *c_handle = to_cstring(env, handle);
         void *callMethod = map->get(HASH(c_handle));
         void **params = to_carray(env, params);
        // ???
        // 2 automata could be used here!
        // First Automata: written in C and involves a common conventional call API.
       // Second Automata: written C/Asm that involves a platform-specific conventional call API.
   }
}

// ???

[dll_loader_cpp_ext.cpp]

extern "C" {

   void* loadFunction(void *file_handle, const char *function_handle) {
         // sanity checks 
        ...
        // link and load symbol 
      dlsym(handle, "create_footbar");
   }

}

[DllPluginLoader.java]

public final DllPluginLoader extends NativeBinaryLoader {
     ...
    private static native Object callFunction(final String functionHandler);

    <T> public static T call(final String functionHandle) {
            return (T) callFunction(functionHandle);
    }

    ...
    // extracts the library to the file system and defer loading to the Native plugin loader coded in C
   // this removes the burden of writing JNI layers
}
pavly-gerges commented 2 months ago

Alright here is a simple example from the current WIP Electrostatic-Sandbox conventional caller API: [hello_dll_service.c]

#include <electrostatic/util/loader/dll_loader.h>
#include <electrostatic/util/console/colors.h>
#include <stdlib.h>
#include <stdio.h>

void *dll_conventional_routine(routine_data *data);

void *dll_conventional_routine(routine_data *data) {
    // interpret the conventional call into a service job
    const char *caller = data->dispatcher_name;

    fprintf(stdout, MAGENTA "Dispatched service from caller substrate --- %s\n" MAGENTA, caller);
    fprintf(stdout, GREEN "%s" GREEN, ((const char **) data->routine_inputs)[0]);
    fprintf(stdout, GREEN "%s" GREEN, ((const char **) data->routine_inputs)[1]);

    return "Hello Back\n";
}

[hello_dll_substrate.c]

#include <electrostatic/util/loader/dll_loader.h>
#include <electrostatic/util/console/colors.h>
#include <stdlib.h>
#include <stdio.h>
#include <gnu/lib-names.h>

int main() {
    dll_function_table function_table = {
    };

    routine_data *data = calloc(1, sizeof(routine_data));
    // allocate 2 blocks for memory addresses of binary address size
    data->routine_inputs = calloc(2, sizeof(void *));
    // name caller service handler
    data->dispatcher_name = "DLL_SUBSTRATE-00144";
    data->dll_flags = RTLD_LAZY;
    // pass some args
    data->routine_inputs[0] = "Hello";
    data->routine_inputs[1] = " World\n";
    // define the absolute directory for the dll file
    data->dll_name = "/media/pavl-machine/pavl-g/Projects/Electrostatic-Sandbox/electrostatic-sandbox-framework/electrostatic-examples/build/linux/x86-64/libhello_dll_service.c.so";
    // define the service conventional routine name
    data->routine_name = "dll_conventional_routine";

    // initialize the default functions
    init(&function_table);

    // open the dll
    function_table.dll_open(data);
    function_table.dll_function_loading(data, &function_table);
    call_dll_convention(data, &function_table);

    printf("Convention Output = %s", (const char *) data->routine_output);

    function_table.dll_close(data);

    free(data->routine_inputs);
    free(data);
    return 0;
}