From e4b6f10ff74256ced6485be0d322eb4eed09471e Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Wed, 12 Jun 2024 16:15:56 -0500 Subject: [PATCH 1/9] requested changes to java.c, configure.ac, and internal state to coblocal.h Fixed conflicts --- configure.ac | 21 +++++ libcob/Makefile.am | 6 ++ libcob/coblocal.h | 27 ++++++- libcob/java.c | 189 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 libcob/java.c diff --git a/configure.ac b/configure.ac index c490cfecc..17b268858 100644 --- a/configure.ac +++ b/configure.ac @@ -468,6 +468,23 @@ AC_DEFUN([AC_PROG_CXX], []) AC_PROG_LN_S AC_PROG_INSTALL +PRINT_VAR(JAVA_HOME) +PRINT_VAR(JAVA) +PRINT_VAR(JAVAC) +PRINT_VAR(JAVAH) +PRINT_VAR(JAR) +PRINT_VAR(JNI_INCLUDES) + +AC_PATH_PROG(javahome,java, "/usr/bin") +javahome=`dirname ${javahome}` +javahome=`dirname ${javahome}` +echo "JAVAHOME=${javahome}" +for each in `ls ${javahome}/include` ;do + if [ test -d ${javahome}/include/${each} ] ;then + javaos=${each} + fi; +done; + AC_PROG_MAKE_SET AC_LIB_RPATH @@ -480,6 +497,10 @@ dnl AC_CHECK_HEADERS([stdint.h whcar.h malloc.h]) # mandatory: AC_CHECK_HEADERS([sys/types.h signal.h stddef.h], [], [AC_MSG_ERROR([mandatory header could not be found or included])]) +AC_CHECK_HEADERS([jni.h], [], + [AC_MSG_ERROR([jni.h is required but could not be found])]) +AC_CHECK_HEADERS([jni_md.h], [], + [AC_MSG_ERROR([jni_md.h is required but could not be found])]) # optional: AC_CHECK_HEADERS([sys/time.h locale.h fcntl.h dlfcn.h sys/wait.h sys/sysmacros.h]) diff --git a/libcob/Makefile.am b/libcob/Makefile.am index 272481a4c..baee7d6ee 100644 --- a/libcob/Makefile.am +++ b/libcob/Makefile.am @@ -19,6 +19,12 @@ # You should have received a copy of the GNU General Public License # along with GnuCOBOL. If not, see . +lib_LTLIBRARIES = libcob.la +libcob_la_SOURCES = common.c move.c numeric.c strings.c \ + fileio.c call.c intrinsic.c termio.c screenio.c reportio.c cobgetopt.c \ + java.c \ + mlio.c coblocal.h cconv.c system.def profiling.c + if LOCAL_CJSON nodist_libcob_la_SOURCES = cJSON.c DISTCLEANFILES = cJSON.c cJSON.h diff --git a/libcob/coblocal.h b/libcob/coblocal.h index c8e49f088..07ea9e173 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -1,6 +1,6 @@ /* - Copyright (C) 2007-2012, 2014-2022 Free Software Foundation, Inc. - Written by Roger While, Simon Sobisch, Ron Norman + Copyright (C) 2007-2012, 2014-2024 Free Software Foundation, Inc. + Written by Roger While, Simon Sobisch, Ron Norman, Vedant Tewari This file is part of GnuCOBOL. @@ -449,6 +449,29 @@ COB_HIDDEN const char *cob_get_last_exception_name (void); COB_EXPIMP void cob_field_to_string (const cob_field *, void *, const size_t); COB_HIDDEN void cob_parameter_check (const char *, const int); +COB_HIDDEN char* cob_get_strerror (void); + +COB_HIDDEN JNIEnv* cob_create_vm (); +COB_HIDDEN void cob_handle_error (JavaVM* jvm, char* methodSig); +COB_HIDDEN char* cob_gen_method_sig (const char** paramType, int paramCount, const char** returnType); + +COB_HIDDEN void cob_lookup_static_method (JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, + const char *methodSig, const char *returnType, const char** paramTypes, int paramCount); + +COB_HIDDEN void cob_static_method (JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid); +COB_HIDDEN void cob_call_java_static_method (JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input); + +enum cob_case_modifier { + CCM_NONE, + CCM_LOWER, + CCM_UPPER, + CCM_LOWER_LOCALE, + CCM_UPPER_LOCALE +}; +COB_HIDDEN unsigned char cob_toupper (const unsigned char); +COB_HIDDEN unsigned char cob_tolower (const unsigned char); +COB_HIDDEN int cob_field_to_string (const cob_field *, void *, + const size_t, const enum cob_case_modifier target_case); COB_HIDDEN cob_settings *cob_get_settings_ptr (void); diff --git a/libcob/java.c b/libcob/java.c new file mode 100644 index 000000000..f7b1c5103 --- /dev/null +++ b/libcob/java.c @@ -0,0 +1,189 @@ +/* + Copyright (C) 2024 Free Software Foundation, Inc. + Written by Vedant Tewari + + This file is part of GnuCOBOL. + + The GnuCOBOL runtime library is free software: you can redistribute it + and/or modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + GnuCOBOL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with GnuCOBOL. If not, see . +*/ + +#include +#include +#include +#include + +/* For caching which is an optimization but can we internally implement it as well? */ +typedef struct { + jclass cls; + jmethodID mid; +} MethodCache; + +MethodCache* cache = NULL; +int cacheSize = 0; + +static JavaVM *jvm = NULL; +/* pointer to native method interface */ +static JNIEnv* env = NULL; + +static void +add_to_cache(jclass cls, jmethodID mid) { + cacheSize++; + cache = (MethodCache*)realloc(cache, sizeof(MethodCache) * cacheSize); + cache[cacheSize - 1].cls = cls; + cache[cacheSize - 1].mid = mid; +} + +jmethodID +get_from_cache(jclass cls, const char* methodName, const char* methodSig) { + for (int i = 0; i < cacheSize; i++) { + if (cache[i].cls == cls) { + return cache[i].mid; + } + } + return; +} + +static JNIEnv* +cob_create_vm() { + /* JDK/JRE 6 VM initialization arguments */ + JavaVMInitArgs args; + JavaVMOption* options = (JavaVMOption*)cob_malloc(sizeof(JavaVMOption) * 1); + args.version = JNI_VERSION_1_6; + /* inline */ + args.nOptions = 1; + options[0].optionString = "-Djava.class.path=/usr/lib/java"; + args.options = &options; + args.ignoreUnrecognized = 1; + int rv; + /* loading and initializing a Java VM, returning as JNI interface */ + rv = JNI_CreateJavaVM(jvm, (void**)&env, &args); + if (rv < 0 || !env) + return; + else + return rv; + return env; +} + +static void +cob_handle_error(JavaVM* jvm, char* methodSig) { + if (methodSig != NULL) { + free(methodSig); + } + if (jvm != NULL) { + (*jvm)->DestroyJavaVM(jvm); + } +} + +static char* +cob_gen_method_sig(const char** paramType, int paramCount, const char** returnType) { + /* (param_list) + return_type */ + int length = 2 + strlen(returnType); + for(int i = 0; i < paramCount; i++) { + length += strlen(paramType[i]); + } + + /* internal malloc */ + char* sig = (char*)cob_malloc(length + 1); + sig[0] = '('; + int pos = 1; + for(int i = 0; i < paramCount; i++) { + strcpy(sig + pos, paramType[i]); + pos += strlen(paramType[i]); + } + sig[pos++] = ')'; + strcpy(sig + pos, returnType); + return sig; +} + +static void +cob_lookup_static_method(JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, +const char *methodSig, const char *returnType, const char** paramTypes, int paramCount) { + jclass cls = (*env)->FindClass(env, className); + if (cls == NULL) { + (*jvm)->DestroyJavaVM(jvm); + return; + } + + jmethodID mid = get_from_cache(cls, methodName, methodSig); + if (mid == NULL) { + char* signature = generate_method_signature(paramTypes, paramCount, returnType); + mid = (*env)->GetStaticMethodID(env, cls, methodName, signature); + if (mid == NULL) { + free(signature); + (*jvm)->DestroyJavaVM(jvm); + return; + } + add_to_cache(cls, mid); + free(signature); + } + + cob_static_method(env, jvm, cls, mid); +} + +static void +cob_static_method(JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid) { + (*env)->CallStaticVoidMethod(env, cls, mid, NULL); +} + +static void +JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input) { + const char* paramTypes[] = {"Ljava/lang/String;"}; + char* methodSig = generate_method_signature(paramTypes, 1, "Ljava/lang/String;"); + + jclass cls = (*env)->FindClass(env, className); + if (cls == NULL) { + cob_handle_error(jvm, methodSig); + return; + } + + jmethodID mid = (*env)->GetStaticMethodID(env, cls, methodName, methodSig); + if (mid == NULL) { + cob_handle_error(jvm, methodSig); + return; + } + + const char *nativeInput = (*env)->GetStringUTFChars(env, input, NULL); + jstring result = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid, (*env)->NewStringUTF(env, nativeInput)); + + const char *nativeResult = (*env)->GetStringUTFChars(env, result, 0); + + (*env)->ReleaseStringUTFChars(env, input, nativeInput); + (*env)->ReleaseStringUTFChars(env, result, nativeResult); + + free(methodSig); +} + +/* +extern "C" +JNIEXPORT jstring JNICALL Java_callJavaMemberFunction(JNIEnv *env, jobject obj, jobject javaObject, jstring input) { + jclass cls = (*env)->GetObjectClass(env, javaObject); + if (cls == NULL) { + return NULL; + } + + const char* paramTypes[] = {"Ljava/lang/String;"}; + char* methodSig = generate_method_signature(paramTypes, 1, "Ljava/lang/String;"); + + jmethodID mid = (*env)->GetMethodID(env, cls, "greet", methodSig); + if (mid == NULL) { + free(methodSig); + return NULL; + } + + jstring result = (jstring)(*env)->CallObjectMethod(env, javaObject, mid, input); + + free(methodSig); + return result; +} +*/ \ No newline at end of file From 35f3ff4f455db2a64b4d108ce5e529cd50580e60 Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Sun, 16 Jun 2024 23:23:05 -0500 Subject: [PATCH 2/9] Requested changes in PR #149, added modifications to CHANGELOG and DEPENDENCIES --- ChangeLog | 3 +++ DEPENDENCIES | 13 +++++++++++++ DEPENDENCIES.md | 12 ++++++++++++ configure.ac | 1 - libcob/ChangeLog | 5 +++++ libcob/coblocal.h | 2 +- 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 08b159cb2..246e0ace3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2024-06-12 Vedant Tewari + + * configure.ac: Add support for JNI (Java Native Interface) 2023-02-25 Ron Norman diff --git a/DEPENDENCIES b/DEPENDENCIES index 2a1bde415..a29c6d797 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -137,6 +137,19 @@ The following libraries ARE required WHEN : JSON-C is distributed under Expat License. +5) JNI (Java Native Interface) support is used + + BOTH runtime AND development components required. + + One of the following: + + o Java Development Kit (JDK) 8 or later + https://openjdk.java.net/ + + The JDK is distributed under various open-source licenses depending on the vendor and version. Common licenses include the GNU General Public License (GPL) and the Oracle Binary Code License Agreement. + + To enable JNI support, ensure that the JDK is installed on your system, and set the appropriate environment variables (e.g., JAVA_HOME) to point to the JDK installation directory. + See HACKING if you wish to hack the GnuCOBOL source or build directly from version control as this includes the list of additional tools diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 266459ff7..27e8b1450 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -119,3 +119,15 @@ Support for GENERATE JSON is provided by *one* of the following: JSON-C is distributed under Expat License. +JNI Support +------------ + +Support for JNI (Java Native Interface) is provided by: + +* [Java Development Kit (JDK)](https://openjdk.java.net/) 8 or later. + + The JDK is distributed under various open-source licenses depending on the vendor and version. Common licenses include the GNU General Public License (GPL) and the Oracle Binary Code License Agreement. + +To enable JNI support, ensure that the JDK is installed on your system, and set the appropriate environment variables (e.g., JAVA_HOME) to point to the JDK installation directory. + + diff --git a/configure.ac b/configure.ac index 17b268858..d0041553e 100644 --- a/configure.ac +++ b/configure.ac @@ -477,7 +477,6 @@ PRINT_VAR(JNI_INCLUDES) AC_PATH_PROG(javahome,java, "/usr/bin") javahome=`dirname ${javahome}` -javahome=`dirname ${javahome}` echo "JAVAHOME=${javahome}" for each in `ls ${javahome}/include` ;do if [ test -d ${javahome}/include/${each} ] ;then diff --git a/libcob/ChangeLog b/libcob/ChangeLog index b5bb0ab8c..5f094c17f 100644 --- a/libcob/ChangeLog +++ b/libcob/ChangeLog @@ -1,3 +1,8 @@ +2024-06-12 Vedant Tewari + + * Makefile.am: Updated to include JNI-related files. + * coblocal.h: Added internal state for JNI support. + * java.c: Implemented JNI support for GnuCOBOL. 2023-06-02 Simon Sobisch diff --git a/libcob/coblocal.h b/libcob/coblocal.h index 07ea9e173..75dd817a3 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2007-2012, 2014-2024 Free Software Foundation, Inc. + Copyright (C) 2007-2012, 2014-2022 Free Software Foundation, Inc. Written by Roger While, Simon Sobisch, Ron Norman, Vedant Tewari This file is part of GnuCOBOL. From 1409cdfc35212f61162d7319101d16b303e1ea58 Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Mon, 17 Jun 2024 09:55:08 -0500 Subject: [PATCH 3/9] Formatted Changes to PR --- libcob/coblocal.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libcob/coblocal.h b/libcob/coblocal.h index 75dd817a3..9ca92c82f 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -468,8 +468,7 @@ enum cob_case_modifier { CCM_LOWER_LOCALE, CCM_UPPER_LOCALE }; -COB_HIDDEN unsigned char cob_toupper (const unsigned char); -COB_HIDDEN unsigned char cob_tolower (const unsigned char); + COB_HIDDEN int cob_field_to_string (const cob_field *, void *, const size_t, const enum cob_case_modifier target_case); From 10761c7c2da632055222f5a67fd8bcbb079b4ff5 Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Mon, 1 Jul 2024 10:53:39 -0500 Subject: [PATCH 4/9] Added changes to java.c for adding types and data structures for bidirectional communication --- cobc/codegen.c | 2 +- configure.ac | 24 +++++++- libcob/call.c | 17 ++++++ libcob/coblocal.h | 6 ++ libcob/java.c | 152 +++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 197 insertions(+), 4 deletions(-) diff --git a/cobc/codegen.c b/cobc/codegen.c index 20f576571..ec3ae7198 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -7070,7 +7070,7 @@ output_call (struct cb_call *p) ret_ptr = 1; } system_call = NULL; - + // check the name where it is translated, check if the string begins with java then encode the string differently #ifdef _WIN32 if (p->convention & CB_CONV_STDCALL) { convention = "_std"; diff --git a/configure.ac b/configure.ac index d0041553e..217769ca3 100644 --- a/configure.ac +++ b/configure.ac @@ -496,13 +496,33 @@ dnl AC_CHECK_HEADERS([stdint.h whcar.h malloc.h]) # mandatory: AC_CHECK_HEADERS([sys/types.h signal.h stddef.h], [], [AC_MSG_ERROR([mandatory header could not be found or included])]) -AC_CHECK_HEADERS([jni.h], [], +AC_CHECK_HEADERS([jni.h], [have_jni=yes], [AC_MSG_ERROR([jni.h is required but could not be found])]) AC_CHECK_HEADERS([jni_md.h], [], [AC_MSG_ERROR([jni_md.h is required but could not be found])]) # optional: AC_CHECK_HEADERS([sys/time.h locale.h fcntl.h dlfcn.h sys/wait.h sys/sysmacros.h]) - +AC_ARG_VAR([JAVA_HOME], [Java Runtime Environment (JRE) location]) +AC_ARG_ENABLE([java-feature], + [AC_HELP_STRING([--disable-java-feature], + [disable Java feature])]) +case $target_cpu in + x86_64) JVM_ARCH=amd64 ;; + i?86) JVM_ARCH=i386 ;; + *) JVM_ARCH=$target_cpu ;; +esac +AC_SUBST([JVM_ARCH]) +AS_IF([test X$enable_java_feature != Xno], +[AS_IF([test X$have_jni != Xyes], + [AC_MSG_FAILURE([The Java Native Interface is required for Java feature.])]) +AS_IF([test -z "$JAVA_HOME"], +[AC_MSG_WARN([JAVA_HOME has not been set. JAVA_HOME must be set at run time to locate libjvm.])], +[save_LDFLAGS=$LDFLAGS +LDFLAGS="-L$JAVA_HOME/lib/$JVM_ARCH/client -L$JAVA_HOME/lib/$JVM_ARCH/server $LDFLAGS" +AC_CHECK_LIB([jvm], [JNI_CreateJavaVM], [LIBS=$LIBS], + [AC_MSG_WARN([no libjvm found at JAVA_HOME])]) +LDFLAGS=$save_LDFLAGS +])]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff --git a/libcob/call.c b/libcob/call.c index 76534493c..41385a408 100644 --- a/libcob/call.c +++ b/libcob/call.c @@ -840,6 +840,15 @@ cob_resolve_internal (const char *name, const char *dirent, s = (const unsigned char *)name; + if(module_type == COB_MODULE_TYPE_FUNCTION && strmcmp ("Java.", s, 6) == 0) { + (void*)func = cob_lookup_static_java_method(s + 6); /* <- java.c, declared in coblocal.h */ + if(func != NULL) { + insert(name, func, NULL, NULL, NULL, 1); + resolve_error = NULL; + return func; + } + } + /* Encode program name, including case folding */ cob_encode_program_id (s, (unsigned char *)call_entry_buff, COB_MINI_MAX, fold_case); @@ -1383,6 +1392,14 @@ cob_call (const char *name, const int argc, void **argv) /* LCOV_EXCL_STOP */ unifunc.funcvoid = cob_resolve_cobol (name, 0, 1); pargv = cob_malloc (MAX_CALL_FIELD_PARAMS * sizeof(void *)); + + #ifndef HAVE_JNI + /* Distinguishing lookup from call*/ + if(strncmp("Java.", name, 6) == 0) { + static_java_method = cob_lookup_static_method(s + 6, argv); + cob_call_java_static_method(method); + } + /*HAVE_JNI*/ /* Set number of parameters */ cobglobptr->cob_call_params = argc; cobglobptr->cob_call_from_c = 1; diff --git a/libcob/coblocal.h b/libcob/coblocal.h index 9ca92c82f..018dfd8bb 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -461,6 +461,12 @@ COB_HIDDEN void cob_lookup_static_method (JNIEnv* env, JavaVM* jvm, const char COB_HIDDEN void cob_static_method (JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid); COB_HIDDEN void cob_call_java_static_method (JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input); +COB_HIDDEN jobject cob_create_java_object(JNIEnv* env, const char* className, const char* constructorSig, jvalue* args); +COB_HIDDEN void cob_set_java_field(JNIEnv* env, jobject obj, const char* fieldName, const char* fieldSig, jvalue value); + +COB_HIDDEN jvalue cob_get_java_field(JNIEnv* env, jobject obj, const char* fieldName, const char* fieldSig); +COB_HIDDEN jvalue cob_call_java_method(JNIEnv* env, jobject obj, const char* methodName, const char* methodSig, jvalue* args); + enum cob_case_modifier { CCM_NONE, CCM_LOWER, diff --git a/libcob/java.c b/libcob/java.c index f7b1c5103..984945148 100644 --- a/libcob/java.c +++ b/libcob/java.c @@ -34,7 +34,7 @@ int cacheSize = 0; static JavaVM *jvm = NULL; /* pointer to native method interface */ -static JNIEnv* env = NULL; +static JNIEnv *env = NULL; static void add_to_cache(jclass cls, jmethodID mid) { @@ -75,6 +75,10 @@ cob_create_vm() { return env; } +void cob_destroy_jni() { + (*jvm)->DestroyJavaVM(jvm); +} + static void cob_handle_error(JavaVM* jvm, char* methodSig) { if (methodSig != NULL) { @@ -164,6 +168,152 @@ JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, const char *classN free(methodSig); } +jobject cob_create_java_object(JNIEnv *env, const char *className, const char *constructorSig, jvalue *args) { + jclass cls = (*env)->FindClass(env, className); + if (cls == NULL) { + return NULL; + } + + jmethodID constructor = (*env)->GetMethodID(env, cls, "", constructorSig); + if (constructor == NULL) { + return NULL; + } + + jobject obj = (*env)->NewObjectA(env, cls, constructor, args); + return obj; +} + +void cob_set_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig, jvalue value) { + jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID fieldID = (*env)->GetFieldID(env, cls, fieldName, fieldSig); + if (fieldID == NULL) { + return; + } + + switch (fieldSig[0]) { + case 'Z': // jboolean + (*env)->SetBooleanField(env, obj, fieldID, value.z); + break; + case 'B': // jbyte + (*env)->SetByteField(env, obj, fieldID, value.b); + break; + case 'C': // jchar + (*env)->SetCharField(env, obj, fieldID, value.c); + break; + case 'S': // jshort + (*env)->SetShortField(env, obj, fieldID, value.s); + break; + case 'I': // jint + (*env)->SetIntField(env, obj, fieldID, value.i); + break; + case 'J': // jlong + (*env)->SetLongField(env, obj, fieldID, value.j); + break; + case 'F': // jfloat + (*env)->SetFloatField(env, obj, fieldID, value.f); + break; + case 'D': // jdouble + (*env)->SetDoubleField(env, obj, fieldID, value.d); + break; + case 'L': // jobject + (*env)->SetObjectField(env, obj, fieldID, value.l); + break; + default: + break; + } +} + +jvalue cob_get_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig) { + jvalue result; + memset(&result, 0, sizeof(result)); + + jclass cls = (*env)->GetObjectClass(env, obj); + jfieldID fieldID = (*env)->GetFieldID(env, cls, fieldName, fieldSig); + if (fieldID == NULL) { + return result; + } + + switch (fieldSig[0]) { + case 'Z': // jboolean + result.z = (*env)->GetBooleanField(env, obj, fieldID); + break; + case 'B': // jbyte + result.b = (*env)->GetByteField(env, obj, fieldID); + break; + case 'C': // jchar + result.c = (*env)->GetCharField(env, obj, fieldID); + break; + case 'S': // jshort + result.s = (*env)->GetShortField(env, obj, fieldID); + break; + case 'I': // jint + result.i = (*env)->GetIntField(env, obj, fieldID); + break; + case 'J': // jlong + result.j = (*env)->GetLongField(env, obj, fieldID); + break; + case 'F': // jfloat + result.f = (*env)->GetFloatField(env, obj, fieldID); + break; + case 'D': // jdouble + result.d = (*env)->GetDoubleField(env, obj, fieldID); + break; + case 'L': // jobject + result.l = (*env)->GetObjectField(env, obj, fieldID); + break; + default: + break; + } + return result; +} + +jvalue cob_call_java_method(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, jvalue *args) { + jvalue result; + memset(&result, 0, sizeof(result)); + + jclass cls = (*env)->GetObjectClass(env, obj); + jmethodID methodID = (*env)->GetMethodID(env, cls, methodName, methodSig); + if (methodID == NULL) { + return result; + } + + switch (methodSig[strlen(methodSig) - 1]) { + case 'V': // void + (*env)->CallVoidMethodA(env, obj, methodID, args); + break; + case 'Z': // jboolean + result.z = (*env)->CallBooleanMethodA(env, obj, methodID, args); + break; + case 'B': // jbyte + result.b = (*env)->CallByteMethodA(env, obj, methodID, args); + break; + case 'C': // jchar + result.c = (*env)->CallCharMethodA(env, obj, methodID, args); + break; + case 'S': // jshort + result.s = (*env)->CallShortMethodA(env, obj, methodID, args); + break; + case 'I': // jint + result.i = (*env)->CallIntMethodA(env, obj, methodID, args); + break; + case 'J': // jlong + result.j = (*env)->CallLongMethodA(env, obj, methodID, args); + break; + case 'F': // jfloat + result.f = (*env)->CallFloatMethodA(env, obj, methodID, args); + break; + case 'D': // jdouble + result.d = (*env)->CallDoubleMethodA(env, obj, methodID, args); + break; + case 'L': // jobject + result.l = (*env)->CallObjectMethodA(env, obj, methodID, args); + break; + default: + break; + } + return result; +} + /* extern "C" JNIEXPORT jstring JNICALL Java_callJavaMemberFunction(JNIEnv *env, jobject obj, jobject javaObject, jstring input) { From 1ef39f06f277a8cdf533a23214c94270b7872e9a Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Mon, 1 Jul 2024 13:48:25 -0500 Subject: [PATCH 5/9] Refactoring for generating static methods --- libcob/coblocal.h | 3 ++ libcob/java.c | 78 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/libcob/coblocal.h b/libcob/coblocal.h index 018dfd8bb..4c9e4f3f0 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -457,6 +457,9 @@ COB_HIDDEN char* cob_gen_method_sig (const char** paramType, int paramCount, co COB_HIDDEN void cob_lookup_static_method (JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, const char *methodSig, const char *returnType, const char** paramTypes, int paramCount); +COB_HIDDEN static char* cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, const char *returnType); + +COB_HIDDEN jobjectArray cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName); COB_HIDDEN void cob_static_method (JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid); COB_HIDDEN void cob_call_java_static_method (JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input); diff --git a/libcob/java.c b/libcob/java.c index 984945148..77e66ca77 100644 --- a/libcob/java.c +++ b/libcob/java.c @@ -75,7 +75,8 @@ cob_create_vm() { return env; } -void cob_destroy_jni() { +void +cob_destroy_jni() { (*jvm)->DestroyJavaVM(jvm); } @@ -85,7 +86,7 @@ cob_handle_error(JavaVM* jvm, char* methodSig) { free(methodSig); } if (jvm != NULL) { - (*jvm)->DestroyJavaVM(jvm); + cob_destroy_jni(); } } @@ -110,6 +111,22 @@ cob_gen_method_sig(const char** paramType, int paramCount, const char** returnTy return sig; } +static char* +cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, const char *returnType) { + int paramCount = (*env)->GetArrayLength(env, paramTypes); + const char **paramTypeStrings = (const char **) malloc(paramCount * sizeof(const char *)); + if (paramTypeStrings == NULL) { + return NULL; + } + for (int i = 0; i < paramCount; i++) { + jobject paramType = (*env)->GetObjectArrayElement(env, paramTypes, i); + paramTypeStrings[i] = className; + (*env)->DeleteLocalRef(env, paramType); + } + + return cob_gen_method_sig(paramTypeStrings, paramCount, returnType); +} + static void cob_lookup_static_method(JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, const char *methodSig, const char *returnType, const char** paramTypes, int paramCount) { @@ -121,7 +138,7 @@ const char *methodSig, const char *returnType, const char** paramTypes, int para jmethodID mid = get_from_cache(cls, methodName, methodSig); if (mid == NULL) { - char* signature = generate_method_signature(paramTypes, paramCount, returnType); + char* signature = cob_gen_method_sig(paramTypes, paramCount, returnType); mid = (*env)->GetStaticMethodID(env, cls, methodName, signature); if (mid == NULL) { free(signature); @@ -135,15 +152,50 @@ const char *methodSig, const char *returnType, const char** paramTypes, int para cob_static_method(env, jvm, cls, mid); } +jobjectArray +cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName) { + jmethodID methodId = (*env)->GetMethodID(env, clazz, methodName, NULL); + if (methodId == NULL) { + return NULL; + } + + jint argCount = (*env)->GetArrayLength(env, methodId); + if (argCount <= 0) { + return NULL; + } + + jclass classClass = (*env)->FindClass(env, "java/lang/Class"); + if (classClass == NULL) { + return NULL; + } + + jobjectArray paramTypes = (*env)->NewObjectArray(env, argCount, classClass, NULL); + if (paramTypes == NULL) { + (*env)->DeleteLocalRef(env, classClass); + return NULL; + } + + for (int i = 0; i < argCount; ++i) { + jclass paramType = (*env)->GetObjectArrayElement(env, paramTypes, i); + if (paramType == NULL) { + (*env)->DeleteLocalRef(env, classClass); + (*env)->DeleteLocalRef(env, paramTypes); + return NULL; + } + (*env)->SetObjectArrayElement(env, paramTypes, i, paramType); + } + return paramTypes; +} + static void cob_static_method(JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid) { (*env)->CallStaticVoidMethod(env, cls, mid, NULL); } static void -JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input) { - const char* paramTypes[] = {"Ljava/lang/String;"}; - char* methodSig = generate_method_signature(paramTypes, 1, "Ljava/lang/String;"); +JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, jclass cls, char *className, const char* methodName, const char *returnType, jobject obj, jstring input) { + char* paramTypes = cob_get_method_parameter_types(env, cls, methodName); + char* methodSig = cob_gen_method_sig(paramTypes, 1, returnType); jclass cls = (*env)->FindClass(env, className); if (cls == NULL) { @@ -168,7 +220,8 @@ JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, const char *classN free(methodSig); } -jobject cob_create_java_object(JNIEnv *env, const char *className, const char *constructorSig, jvalue *args) { +jobject +cob_create_java_object(JNIEnv *env, const char *className, const char *constructorSig, jvalue *args) { jclass cls = (*env)->FindClass(env, className); if (cls == NULL) { return NULL; @@ -183,7 +236,8 @@ jobject cob_create_java_object(JNIEnv *env, const char *className, const char *c return obj; } -void cob_set_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig, jvalue value) { +void +cob_set_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig, jvalue value) { jclass cls = (*env)->GetObjectClass(env, obj); jfieldID fieldID = (*env)->GetFieldID(env, cls, fieldName, fieldSig); if (fieldID == NULL) { @@ -223,7 +277,8 @@ void cob_set_java_field(JNIEnv *env, jobject obj, const char *fieldName, const c } } -jvalue cob_get_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig) { +jvalue +cob_get_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig) { jvalue result; memset(&result, 0, sizeof(result)); @@ -267,7 +322,8 @@ jvalue cob_get_java_field(JNIEnv *env, jobject obj, const char *fieldName, const return result; } -jvalue cob_call_java_method(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, jvalue *args) { +jvalue +cob_call_java_method(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, jvalue *args) { jvalue result; memset(&result, 0, sizeof(result)); @@ -323,7 +379,7 @@ JNIEXPORT jstring JNICALL Java_callJavaMemberFunction(JNIEnv *env, jobject obj, } const char* paramTypes[] = {"Ljava/lang/String;"}; - char* methodSig = generate_method_signature(paramTypes, 1, "Ljava/lang/String;"); + char* methodSig = cob_gen_method_sig(paramTypes, 1, "Ljava/lang/String;"); jmethodID mid = (*env)->GetMethodID(env, cls, "greet", methodSig); if (mid == NULL) { From e2722fcd25cfb6a37c638d6f06c10aa6352d8277 Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Wed, 3 Jul 2024 06:41:36 -0500 Subject: [PATCH 6/9] More Changes --- cobc/codegen.c | 8 +++ libcob/call.c | 9 ---- libcob/coblocal.h | 20 +++++--- libcob/common.h | 8 +++ libcob/java.c | 124 ++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 141 insertions(+), 28 deletions(-) diff --git a/cobc/codegen.c b/cobc/codegen.c index ec3ae7198..71e961e4e 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -7529,6 +7529,14 @@ output_call (struct cb_call *p) } } else { /* Dynamic link */ + if(module_type == COB_MODULE_TYPE_FUNCTION && strmcmp ("Java.", s, 6) == 0) { + (void*)func = cob_lookup_static_java_method(s + 6); /* <- java.c, declared in coblocal.h */ + if(func != NULL) { + insert(name, func, NULL, NULL, NULL, 1); + resolve_error = NULL; + return func; + } + } if (name_is_literal_or_prototype) { s = get_program_id_str (p->name); name_str = cb_encode_program_id (s, 1, cb_fold_call); diff --git a/libcob/call.c b/libcob/call.c index 41385a408..5ae2af27f 100644 --- a/libcob/call.c +++ b/libcob/call.c @@ -840,15 +840,6 @@ cob_resolve_internal (const char *name, const char *dirent, s = (const unsigned char *)name; - if(module_type == COB_MODULE_TYPE_FUNCTION && strmcmp ("Java.", s, 6) == 0) { - (void*)func = cob_lookup_static_java_method(s + 6); /* <- java.c, declared in coblocal.h */ - if(func != NULL) { - insert(name, func, NULL, NULL, NULL, 1); - resolve_error = NULL; - return func; - } - } - /* Encode program name, including case folding */ cob_encode_program_id (s, (unsigned char *)call_entry_buff, COB_MINI_MAX, fold_case); diff --git a/libcob/coblocal.h b/libcob/coblocal.h index 4c9e4f3f0..5958d0f80 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -451,17 +451,21 @@ COB_EXPIMP void cob_field_to_string (const cob_field *, void *, COB_HIDDEN void cob_parameter_check (const char *, const int); COB_HIDDEN char* cob_get_strerror (void); -COB_HIDDEN JNIEnv* cob_create_vm (); -COB_HIDDEN void cob_handle_error (JavaVM* jvm, char* methodSig); -COB_HIDDEN char* cob_gen_method_sig (const char** paramType, int paramCount, const char** returnType); +// COB_HIDDEN JNIEnv* cob_create_vm (); +// COB_HIDDEN void cob_handle_error (JavaVM* jvm, char* methodSig); +// COB_HIDDEN char* cob_gen_method_sig (const char** paramType, int paramCount, const char** returnType); -COB_HIDDEN void cob_lookup_static_method (JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, - const char *methodSig, const char *returnType, const char** paramTypes, int paramCount); -COB_HIDDEN static char* cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, const char *returnType); +#ifdef COB_WITH_JNI +COB_EXPIMP cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) +#endif + +// COB_HIDDEN void cob_lookup_static_method (JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, +// const char *methodSig, const char *returnType, const char** paramTypes, int paramCount); +// COB_HIDDEN static char* cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, const char *returnType); -COB_HIDDEN jobjectArray cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName); +// COB_HIDDEN jobjectArray cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName); -COB_HIDDEN void cob_static_method (JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid); +// COB_HIDDEN void cob_static_method (JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid); COB_HIDDEN void cob_call_java_static_method (JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input); COB_HIDDEN jobject cob_create_java_object(JNIEnv* env, const char* className, const char* constructorSig, jvalue* args); diff --git a/libcob/common.h b/libcob/common.h index 2ae5954ee..5a199de5b 100644 --- a/libcob/common.h +++ b/libcob/common.h @@ -1294,6 +1294,14 @@ struct cob_call_struct { cob_call_union cob_cstr_cancel; /* Cancel entry */ }; +#ifdef COB_HAVE_JNI +COB_EXPIMP cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) +typedef struct __cob_java_static_method { + jclass cls; + jmethodID mid; +} cob_java_static_method_handle; +#endif + /* Screen structure */ typedef struct __cob_screen { struct __cob_screen *next; /* Pointer to next */ diff --git a/libcob/java.c b/libcob/java.c index 77e66ca77..adc8f3588 100644 --- a/libcob/java.c +++ b/libcob/java.c @@ -22,6 +22,7 @@ #include #include #include +#include /* For caching which is an optimization but can we internally implement it as well? */ typedef struct { @@ -81,7 +82,7 @@ cob_destroy_jni() { } static void -cob_handle_error(JavaVM* jvm, char* methodSig) { +cob_handle_error(char* methodSig) { if (methodSig != NULL) { free(methodSig); } @@ -112,7 +113,7 @@ cob_gen_method_sig(const char** paramType, int paramCount, const char** returnTy } static char* -cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, const char *returnType) { +cob_gen_method_sig(jobjectArray paramTypes, const char *className, const char *returnType) { int paramCount = (*env)->GetArrayLength(env, paramTypes); const char **paramTypeStrings = (const char **) malloc(paramCount * sizeof(const char *)); if (paramTypeStrings == NULL) { @@ -128,7 +129,77 @@ cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, } static void -cob_lookup_static_method(JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, +cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) { + jclass cls = (*env)->FindClass(env, className); + if (cls == NULL) { + fprintf(stderr, "Failed to find class: %s\n", className); + cob_destroy_jni(); + return; + } + + char* methodSig = cob_gen_method_sig(paramTypes, paramCount, returnType); + if (methodSig == NULL) { + fprintf(stderr, "Failed to generate method signature\n"); + cob_destroy_jni(); + return; + } + + jmethodID mid = get_from_cache(cls, methodName, methodSig); + if (mid == NULL) { + mid = (*env)->GetStaticMethodID(env, cls, methodName, methodSig); + if (mid == NULL) { + fprintf(stderr, "Failed to get method ID for method: %s\n", methodName); + free(methodSig); + cob_destroy_jni(); + return; + } + add_to_cache(cls, mid); + } + + jvalue result; + memset(&result, 0, sizeof(result)); + + switch (methodSig[strlen(methodSig) - 1]) { + case 'V': // void + (*env)->CallStaticVoidMethodA(env, cls, mid, args); + break; + case 'Z': // jboolean + result.z = (*env)->CallStaticBooleanMethodA(env, cls, mid, args); + break; + case 'B': // jbyte + result.b = (*env)->CallStaticByteMethodA(env, cls, mid, args); + break; + case 'C': // jchar + result.c = (*env)->CallStaticCharMethodA(env, cls, mid, args); + break; + case 'S': // jshort + result.s = (*env)->CallStaticShortMethodA(env, cls, mid, args); + break; + case 'I': // jint + result.i = (*env)->CallStaticIntMethodA(env, cls, mid, args); + break; + case 'J': // jlong + result.j = (*env)->CallStaticLongMethodA(env, cls, mid, args); + break; + case 'F': // jfloat + result.f = (*env)->CallStaticFloatMethodA(env, cls, mid, args); + break; + case 'D': // jdouble + result.d = (*env)->CallStaticDoubleMethodA(env, cls, mid, args); + break; + case 'L': // jobject + result.l = (*env)->CallStaticObjectMethodA(env, cls, mid, args); + break; + default: + fprintf(stderr, "Unsupported return type: %s\n", returnType); + break; + } + + free(methodSig); +} + +static void +cob_lookup_static_method(const char *className, const char *methodName, const char *methodSig, const char *returnType, const char** paramTypes, int paramCount) { jclass cls = (*env)->FindClass(env, className); if (cls == NULL) { @@ -153,7 +224,7 @@ const char *methodSig, const char *returnType, const char** paramTypes, int para } jobjectArray -cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName) { +cob_get_method_parameter_types(jclass clazz, const char* methodName) { jmethodID methodId = (*env)->GetMethodID(env, clazz, methodName, NULL); if (methodId == NULL) { return NULL; @@ -188,12 +259,12 @@ cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName } static void -cob_static_method(JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid) { +cob_static_method(jclass cls, jmethodID mid) { (*env)->CallStaticVoidMethod(env, cls, mid, NULL); } static void -JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, jclass cls, char *className, const char* methodName, const char *returnType, jobject obj, jstring input) { +JNICALL cob_call_java_static_method(jclass cls, char *className, const char* methodName, const char *returnType, jobject obj, jstring input) { char* paramTypes = cob_get_method_parameter_types(env, cls, methodName); char* methodSig = cob_gen_method_sig(paramTypes, 1, returnType); @@ -221,7 +292,7 @@ JNICALL cob_call_java_static_method(JNIEnv *env, JavaVM *jvm, jclass cls, char * } jobject -cob_create_java_object(JNIEnv *env, const char *className, const char *constructorSig, jvalue *args) { +cob_create_java_object(const char *className, const char *constructorSig, jvalue *args) { jclass cls = (*env)->FindClass(env, className); if (cls == NULL) { return NULL; @@ -237,7 +308,7 @@ cob_create_java_object(JNIEnv *env, const char *className, const char *construct } void -cob_set_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig, jvalue value) { +cob_set_java_field(jobject obj, const char *fieldName, const char *fieldSig, jvalue value) { jclass cls = (*env)->GetObjectClass(env, obj); jfieldID fieldID = (*env)->GetFieldID(env, cls, fieldName, fieldSig); if (fieldID == NULL) { @@ -278,7 +349,7 @@ cob_set_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char * } jvalue -cob_get_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char *fieldSig) { +cob_get_java_field(jobject obj, const char *fieldName, const char *fieldSig) { jvalue result; memset(&result, 0, sizeof(result)); @@ -323,7 +394,7 @@ cob_get_java_field(JNIEnv *env, jobject obj, const char *fieldName, const char * } jvalue -cob_call_java_method(JNIEnv *env, jobject obj, const char *methodName, const char *methodSig, jvalue *args) { +cob_call_java_method(jobject obj, const char *methodName, const char *methodSig, jvalue *args) { jvalue result; memset(&result, 0, sizeof(result)); @@ -370,9 +441,40 @@ cob_call_java_method(JNIEnv *env, jobject obj, const char *methodName, const cha return result; } +int +cob_call_java(const cob_java_static_method_handle *method_handle) { + JNIEnv *env; + va_list args; + jobject result; + + if (method_handle == NULL) { + cob_set_exception(COB_EC_INVALID_ARGUMENT); + return -1; + } + + env = cob_get_jni_env(); + if (env == NULL) { + cob_fatal_error("Failed to get JNI environment"); + return -1; + } + + va_start(args, method_handle); + result = (*env)->CallStaticObjectMethodV(env, method_handle->cls, method_handle->mid, args); + va_end(args); + + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); + cob_set_exception(COB_EC_JAVA_EXCEPTION); + return -1; + } + + return (result != NULL) ? 0 : -1; +} + /* extern "C" -JNIEXPORT jstring JNICALL Java_callJavaMemberFunction(JNIEnv *env, jobject obj, jobject javaObject, jstring input) { +JNIEXPORT jstring JNICALL Java_callJavaMemberFunction(jobject obj, jobject javaObject, jstring input) { jclass cls = (*env)->GetObjectClass(env, javaObject); if (cls == NULL) { return NULL; From 2f20deaa402d10358abdf9dd0941bb51a9144263 Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Wed, 3 Jul 2024 06:44:21 -0500 Subject: [PATCH 7/9] Small Fix --- libcob/java.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libcob/java.c b/libcob/java.c index adc8f3588..b999ac78e 100644 --- a/libcob/java.c +++ b/libcob/java.c @@ -132,14 +132,12 @@ static void cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) { jclass cls = (*env)->FindClass(env, className); if (cls == NULL) { - fprintf(stderr, "Failed to find class: %s\n", className); cob_destroy_jni(); return; } char* methodSig = cob_gen_method_sig(paramTypes, paramCount, returnType); if (methodSig == NULL) { - fprintf(stderr, "Failed to generate method signature\n"); cob_destroy_jni(); return; } @@ -148,7 +146,6 @@ cob_call_java_static_method(const char *className, const char* methodName, const if (mid == NULL) { mid = (*env)->GetStaticMethodID(env, cls, methodName, methodSig); if (mid == NULL) { - fprintf(stderr, "Failed to get method ID for method: %s\n", methodName); free(methodSig); cob_destroy_jni(); return; @@ -191,7 +188,6 @@ cob_call_java_static_method(const char *className, const char* methodName, const result.l = (*env)->CallStaticObjectMethodA(env, cls, mid, args); break; default: - fprintf(stderr, "Unsupported return type: %s\n", returnType); break; } From 3b5d8607fcf8b75cdb820a76881abc692d66520f Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Fri, 5 Jul 2024 06:43:08 -0500 Subject: [PATCH 8/9] Reverted all prior changes and cleaned up java.c --- cobc/codegen.c | 73 +++++--- configure.ac | 25 +-- libcob/call.c | 8 - libcob/coblocal.h | 23 --- libcob/common.h | 9 +- libcob/java.c | 437 +++++++++------------------------------------- 6 files changed, 148 insertions(+), 427 deletions(-) diff --git a/cobc/codegen.c b/cobc/codegen.c index 71e961e4e..4617821eb 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -146,6 +146,8 @@ static struct literal_list *literal_cache = NULL; static struct field_list *field_cache = NULL; static struct field_list *local_field_cache = NULL; static struct call_list *call_cache = NULL; +extern JavaVM *jvm; +extern JNIEnv *env; static struct call_list *func_call_cache = NULL; static struct static_call_list *static_call_cache = NULL; static struct base_list *base_cache = NULL; @@ -387,6 +389,21 @@ lookup_source (const char *p) return source_id++; } +static void lookup_java_call(const char *p) { + struct call_list *clp; + + for (clp = call_cache; clp; clp = clp->next) { + if (strcmp(p, clp->call_name) == 0) { + return; + } + } + + clp = (struct call_list *)cob_malloc(sizeof(struct call_list)); + clp->call_name = p; + clp->next = call_cache; + call_cache = clp; +} + static void lookup_call (const char *p) { @@ -7529,38 +7546,42 @@ output_call (struct cb_call *p) } } else { /* Dynamic link */ - if(module_type == COB_MODULE_TYPE_FUNCTION && strmcmp ("Java.", s, 6) == 0) { - (void*)func = cob_lookup_static_java_method(s + 6); /* <- java.c, declared in coblocal.h */ - if(func != NULL) { - insert(name, func, NULL, NULL, NULL, 1); - resolve_error = NULL; - return func; - } - } if (name_is_literal_or_prototype) { s = get_program_id_str (p->name); name_str = cb_encode_program_id (s, 1, cb_fold_call); - lookup_call (name_str); - callname = s; +#ifdef HAVE_JNI + /* Distinguishing lookup from call*/ + if(strncmp("Java.", name, 6) == 0) { + void static_java_method = lookup_static_call(s + 6, p->argv[0], COB_RETURN_NULL); + cob_call_java(static_java_method); + } else { + // rest +#endif + // we need to use lookup_java_call instead (implement) + lookup_java_call (name_str); + callname = s; - output_line ("if (call_%s.funcvoid == NULL || cob_glob_ptr->cob_physical_cancel)", name_str); - output_block_open (); - output_prefix (); + output_line ("if (call_%s.funcvoid == NULL || cob_glob_ptr->cob_physical_cancel)", name_str); + output_block_open (); + output_prefix (); - nlp = find_nested_prog_with_id (name_str); - if (nlp) { - output ("call_%s.funcint = %s_%d__;", - name_str, name_str, - nlp->nested_prog->toplev_count); - } else { - output ("call_%s.funcvoid = ", name_str); - output ("cob_resolve_cobol ("); - output_string ((const unsigned char *)s, - (int)strlen (s), 0); - output (", %d, %d);", cb_fold_call, !p->stmt1); + nlp = find_nested_prog_with_id (name_str); + if (nlp) { + output ("call_%s.funcint = %s_%d__;", + name_str, name_str, + nlp->nested_prog->toplev_count); + } else { + output ("call_%s.funcvoid = ", name_str); + output ("cob_resolve_cobol ("); + output_string ((const unsigned char *)s, + (int)strlen (s), 0); + output (", %d, %d);", cb_fold_call, !p->stmt1); + } + output_newline (); + output_block_close (); +#ifdef HAVE_JNI } - output_newline (); - output_block_close (); +#endif } else { name_str = NULL; needs_unifunc = 1; diff --git a/configure.ac b/configure.ac index 217769ca3..7c10c5fac 100644 --- a/configure.ac +++ b/configure.ac @@ -503,9 +503,9 @@ AC_CHECK_HEADERS([jni_md.h], [], # optional: AC_CHECK_HEADERS([sys/time.h locale.h fcntl.h dlfcn.h sys/wait.h sys/sysmacros.h]) AC_ARG_VAR([JAVA_HOME], [Java Runtime Environment (JRE) location]) -AC_ARG_ENABLE([java-feature], - [AC_HELP_STRING([--disable-java-feature], - [disable Java feature])]) +AC_ARG_ENABLE([java], + [AC_HELP_STRING([--disable-java], + [disable Java Interoperatibility])]) case $target_cpu in x86_64) JVM_ARCH=amd64 ;; i?86) JVM_ARCH=i386 ;; @@ -513,15 +513,16 @@ case $target_cpu in esac AC_SUBST([JVM_ARCH]) AS_IF([test X$enable_java_feature != Xno], -[AS_IF([test X$have_jni != Xyes], - [AC_MSG_FAILURE([The Java Native Interface is required for Java feature.])]) -AS_IF([test -z "$JAVA_HOME"], -[AC_MSG_WARN([JAVA_HOME has not been set. JAVA_HOME must be set at run time to locate libjvm.])], -[save_LDFLAGS=$LDFLAGS -LDFLAGS="-L$JAVA_HOME/lib/$JVM_ARCH/client -L$JAVA_HOME/lib/$JVM_ARCH/server $LDFLAGS" -AC_CHECK_LIB([jvm], [JNI_CreateJavaVM], [LIBS=$LIBS], - [AC_MSG_WARN([no libjvm found at JAVA_HOME])]) -LDFLAGS=$save_LDFLAGS + [AS_IF([test X$have_jni != Xyes], + [AC_MSG_FAILURE([The Java Native Interface is required for Java feature.])]) + AS_IF([test -z "$JAVA_HOME"], + [AC_MSG_WARN([JAVA_HOME has not been set. JAVA_HOME must be set at run time to locate libjvm.])], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="-L$JAVA_HOME/lib/$JVM_ARCH/client -L$JAVA_HOME/lib/$JVM_ARCH/server $LDFLAGS" + AC_CHECK_LIB([jvm], [JNI_CreateJavaVM], [LIBS=$LIBS], + [AC_MSG_WARN([no libjvm found at JAVA_HOME])]) + AC_DEFINE([WITH_JNI], [1]) + LDFLAGS=$save_LDFLAGS ])]) # Checks for typedefs, structures, and compiler characteristics. diff --git a/libcob/call.c b/libcob/call.c index 5ae2af27f..76534493c 100644 --- a/libcob/call.c +++ b/libcob/call.c @@ -1383,14 +1383,6 @@ cob_call (const char *name, const int argc, void **argv) /* LCOV_EXCL_STOP */ unifunc.funcvoid = cob_resolve_cobol (name, 0, 1); pargv = cob_malloc (MAX_CALL_FIELD_PARAMS * sizeof(void *)); - - #ifndef HAVE_JNI - /* Distinguishing lookup from call*/ - if(strncmp("Java.", name, 6) == 0) { - static_java_method = cob_lookup_static_method(s + 6, argv); - cob_call_java_static_method(method); - } - /*HAVE_JNI*/ /* Set number of parameters */ cobglobptr->cob_call_params = argc; cobglobptr->cob_call_from_c = 1; diff --git a/libcob/coblocal.h b/libcob/coblocal.h index 5958d0f80..d6c0ecc69 100644 --- a/libcob/coblocal.h +++ b/libcob/coblocal.h @@ -451,29 +451,6 @@ COB_EXPIMP void cob_field_to_string (const cob_field *, void *, COB_HIDDEN void cob_parameter_check (const char *, const int); COB_HIDDEN char* cob_get_strerror (void); -// COB_HIDDEN JNIEnv* cob_create_vm (); -// COB_HIDDEN void cob_handle_error (JavaVM* jvm, char* methodSig); -// COB_HIDDEN char* cob_gen_method_sig (const char** paramType, int paramCount, const char** returnType); - -#ifdef COB_WITH_JNI -COB_EXPIMP cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) -#endif - -// COB_HIDDEN void cob_lookup_static_method (JNIEnv* env, JavaVM* jvm, const char *className, const char *methodName, -// const char *methodSig, const char *returnType, const char** paramTypes, int paramCount); -// COB_HIDDEN static char* cob_gen_method_sig(JNIEnv *env, jobjectArray paramTypes, const char *className, const char *returnType); - -// COB_HIDDEN jobjectArray cob_get_method_parameter_types(JNIEnv* env, jclass clazz, const char* methodName); - -// COB_HIDDEN void cob_static_method (JNIEnv* env, JavaVM* jvm, jclass cls, jmethodID mid); -COB_HIDDEN void cob_call_java_static_method (JNIEnv *env, JavaVM *jvm, const char *className, const char *methodName, jobject obj, jstring input); - -COB_HIDDEN jobject cob_create_java_object(JNIEnv* env, const char* className, const char* constructorSig, jvalue* args); -COB_HIDDEN void cob_set_java_field(JNIEnv* env, jobject obj, const char* fieldName, const char* fieldSig, jvalue value); - -COB_HIDDEN jvalue cob_get_java_field(JNIEnv* env, jobject obj, const char* fieldName, const char* fieldSig); -COB_HIDDEN jvalue cob_call_java_method(JNIEnv* env, jobject obj, const char* methodName, const char* methodSig, jvalue* args); - enum cob_case_modifier { CCM_NONE, CCM_LOWER, diff --git a/libcob/common.h b/libcob/common.h index 5a199de5b..4a70bd22f 100644 --- a/libcob/common.h +++ b/libcob/common.h @@ -1294,12 +1294,15 @@ struct cob_call_struct { cob_call_union cob_cstr_cancel; /* Cancel entry */ }; -#ifdef COB_HAVE_JNI -COB_EXPIMP cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) +#ifdef HAVE_JNI typedef struct __cob_java_static_method { jclass cls; jmethodID mid; -} cob_java_static_method_handle; +} cob_java_handle; + +COB_EXPIMP cob_java_handle* cob_resolve_java (const char* class_name, const char* method_name, +const char *type_signature); +COB_EXPIMP int cob_call_java (const cob_java_handle* nargs); #endif /* Screen structure */ diff --git a/libcob/java.c b/libcob/java.c index b999ac78e..39a04ba27 100644 --- a/libcob/java.c +++ b/libcob/java.c @@ -24,39 +24,16 @@ #include #include -/* For caching which is an optimization but can we internally implement it as well? */ -typedef struct { - jclass cls; - jmethodID mid; -} MethodCache; +#define HAVE_JNI -MethodCache* cache = NULL; -int cacheSize = 0; +/* For caching which is an optimization but can we internally implement it as well? */ static JavaVM *jvm = NULL; /* pointer to native method interface */ static JNIEnv *env = NULL; -static void -add_to_cache(jclass cls, jmethodID mid) { - cacheSize++; - cache = (MethodCache*)realloc(cache, sizeof(MethodCache) * cacheSize); - cache[cacheSize - 1].cls = cls; - cache[cacheSize - 1].mid = mid; -} - -jmethodID -get_from_cache(jclass cls, const char* methodName, const char* methodSig) { - for (int i = 0; i < cacheSize; i++) { - if (cache[i].cls == cls) { - return cache[i].mid; - } - } - return; -} - -static JNIEnv* -cob_create_vm() { +static void +cob_java_initialize() { /* JDK/JRE 6 VM initialization arguments */ JavaVMInitArgs args; JavaVMOption* options = (JavaVMOption*)cob_malloc(sizeof(JavaVMOption) * 1); @@ -69,189 +46,46 @@ cob_create_vm() { int rv; /* loading and initializing a Java VM, returning as JNI interface */ rv = JNI_CreateJavaVM(jvm, (void**)&env, &args); - if (rv < 0 || !env) - return; - else - return rv; - return env; -} - -void -cob_destroy_jni() { - (*jvm)->DestroyJavaVM(jvm); } -static void -cob_handle_error(char* methodSig) { - if (methodSig != NULL) { - free(methodSig); +static void cob_handle_error(const char* method_sig) { + if (method_sig != NULL) { + free(method_sig); } - if (jvm != NULL) { - cob_destroy_jni(); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionDescribe(env); + (*env)->ExceptionClear(env); } + cob_cleanup(); } -static char* -cob_gen_method_sig(const char** paramType, int paramCount, const char** returnType) { - /* (param_list) + return_type */ - int length = 2 + strlen(returnType); - for(int i = 0; i < paramCount; i++) { - length += strlen(paramType[i]); - } - - /* internal malloc */ - char* sig = (char*)cob_malloc(length + 1); - sig[0] = '('; - int pos = 1; - for(int i = 0; i < paramCount; i++) { - strcpy(sig + pos, paramType[i]); - pos += strlen(paramType[i]); +void cob_delete_java_object(jobject obj) { + if (obj != NULL) { + (*env)->DeleteGlobalRef(env, obj); } - sig[pos++] = ')'; - strcpy(sig + pos, returnType); - return sig; } -static char* -cob_gen_method_sig(jobjectArray paramTypes, const char *className, const char *returnType) { - int paramCount = (*env)->GetArrayLength(env, paramTypes); - const char **paramTypeStrings = (const char **) malloc(paramCount * sizeof(const char *)); - if (paramTypeStrings == NULL) { - return NULL; - } - for (int i = 0; i < paramCount; i++) { - jobject paramType = (*env)->GetObjectArrayElement(env, paramTypes, i); - paramTypeStrings[i] = className; - (*env)->DeleteLocalRef(env, paramType); +cob_java_handle* +cob_resolve_java(const char *class_name, const char* method_name, const char *return_type, const char *type_signature) { + if(jvm == NULL) { + cob_java_initialize(); } - - return cob_gen_method_sig(paramTypeStrings, paramCount, returnType); -} - -static void -cob_call_java_static_method(const char *className, const char* methodName, const char *returnType, const char** paramTypes, int paramCount, jvalue *args) { - jclass cls = (*env)->FindClass(env, className); + jclass cls = (*env)->FindClass(env, class_name); if (cls == NULL) { - cob_destroy_jni(); - return; - } - - char* methodSig = cob_gen_method_sig(paramTypes, paramCount, returnType); - if (methodSig == NULL) { - cob_destroy_jni(); - return; - } - - jmethodID mid = get_from_cache(cls, methodName, methodSig); - if (mid == NULL) { - mid = (*env)->GetStaticMethodID(env, cls, methodName, methodSig); - if (mid == NULL) { - free(methodSig); - cob_destroy_jni(); - return; - } - add_to_cache(cls, mid); - } - - jvalue result; - memset(&result, 0, sizeof(result)); - - switch (methodSig[strlen(methodSig) - 1]) { - case 'V': // void - (*env)->CallStaticVoidMethodA(env, cls, mid, args); - break; - case 'Z': // jboolean - result.z = (*env)->CallStaticBooleanMethodA(env, cls, mid, args); - break; - case 'B': // jbyte - result.b = (*env)->CallStaticByteMethodA(env, cls, mid, args); - break; - case 'C': // jchar - result.c = (*env)->CallStaticCharMethodA(env, cls, mid, args); - break; - case 'S': // jshort - result.s = (*env)->CallStaticShortMethodA(env, cls, mid, args); - break; - case 'I': // jint - result.i = (*env)->CallStaticIntMethodA(env, cls, mid, args); - break; - case 'J': // jlong - result.j = (*env)->CallStaticLongMethodA(env, cls, mid, args); - break; - case 'F': // jfloat - result.f = (*env)->CallStaticFloatMethodA(env, cls, mid, args); - break; - case 'D': // jdouble - result.d = (*env)->CallStaticDoubleMethodA(env, cls, mid, args); - break; - case 'L': // jobject - result.l = (*env)->CallStaticObjectMethodA(env, cls, mid, args); - break; - default: - break; + return NULL; } - free(methodSig); -} - -static void -cob_lookup_static_method(const char *className, const char *methodName, -const char *methodSig, const char *returnType, const char** paramTypes, int paramCount) { - jclass cls = (*env)->FindClass(env, className); - if (cls == NULL) { - (*jvm)->DestroyJavaVM(jvm); - return; - } - - jmethodID mid = get_from_cache(cls, methodName, methodSig); + jmethodID mid = get_from_cache(cls, method_name, type_signature); if (mid == NULL) { - char* signature = cob_gen_method_sig(paramTypes, paramCount, returnType); - mid = (*env)->GetStaticMethodID(env, cls, methodName, signature); + mid = (*env)->GetStaticMethodID(env, cls, method_name, type_signature); if (mid == NULL) { - free(signature); - (*jvm)->DestroyJavaVM(jvm); - return; - } - add_to_cache(cls, mid); - free(signature); - } - - cob_static_method(env, jvm, cls, mid); -} - -jobjectArray -cob_get_method_parameter_types(jclass clazz, const char* methodName) { - jmethodID methodId = (*env)->GetMethodID(env, clazz, methodName, NULL); - if (methodId == NULL) { - return NULL; - } - - jint argCount = (*env)->GetArrayLength(env, methodId); - if (argCount <= 0) { - return NULL; - } - - jclass classClass = (*env)->FindClass(env, "java/lang/Class"); - if (classClass == NULL) { - return NULL; - } - - jobjectArray paramTypes = (*env)->NewObjectArray(env, argCount, classClass, NULL); - if (paramTypes == NULL) { - (*env)->DeleteLocalRef(env, classClass); - return NULL; - } - - for (int i = 0; i < argCount; ++i) { - jclass paramType = (*env)->GetObjectArrayElement(env, paramTypes, i); - if (paramType == NULL) { - (*env)->DeleteLocalRef(env, classClass); - (*env)->DeleteLocalRef(env, paramTypes); return NULL; } - (*env)->SetObjectArrayElement(env, paramTypes, i, paramType); } - return paramTypes; + // run autoconf + // allocate structure that represents the method to be called + cob_java_handle* h = (cob_java_handle*)cob_malloc(sizeof(cob_java_handle)); + return h; } static void @@ -260,191 +94,77 @@ cob_static_method(jclass cls, jmethodID mid) { } static void -JNICALL cob_call_java_static_method(jclass cls, char *className, const char* methodName, const char *returnType, jobject obj, jstring input) { - char* paramTypes = cob_get_method_parameter_types(env, cls, methodName); - char* methodSig = cob_gen_method_sig(paramTypes, 1, returnType); +JNICALL cob_call_java_static_method(jclass cls, char *class_name, const char* method_name, const char *return_type, jobject obj, jstring input) { + char* paramTypes = cob_get_method_parameter_types(env, cls, method_name); + char* methodSig = cob_gen_method_sig(paramTypes, 1, return_type); - jclass cls = (*env)->FindClass(env, className); + jclass cls = (*env)->FindClass(env, class_name); if (cls == NULL) { - cob_handle_error(jvm, methodSig); + cob_handle_error(methodSig); return; } - jmethodID mid = (*env)->GetStaticMethodID(env, cls, methodName, methodSig); + jmethodID mid = (*env)->GetStaticMethodID(env, cls, method_name, methodSig); if (mid == NULL) { - cob_handle_error(jvm, methodSig); + cob_handle_error(methodSig); return; } const char *nativeInput = (*env)->GetStringUTFChars(env, input, NULL); + if (nativeInput == NULL) { + cob_handle_error(methodSig); + return; + } jstring result = (jstring)(*env)->CallStaticObjectMethod(env, cls, mid, (*env)->NewStringUTF(env, nativeInput)); const char *nativeResult = (*env)->GetStringUTFChars(env, result, 0); + if (nativeResult == NULL) { + cob_handle_error(NULL); + return; + } (*env)->ReleaseStringUTFChars(env, input, nativeInput); (*env)->ReleaseStringUTFChars(env, result, nativeResult); + if ((*env)->ExceptionCheck(env)) { + cob_handle_error(NULL); + return; + } + free(methodSig); } jobject -cob_create_java_object(const char *className, const char *constructorSig, jvalue *args) { - jclass cls = (*env)->FindClass(env, className); +cob_create_java_object(const char *class_name, const char *constructor_sig, jvalue *args) { + jclass cls = (*env)->FindClass(env, class_name); if (cls == NULL) { + cob_handle_error(NULL); return NULL; } - jmethodID constructor = (*env)->GetMethodID(env, cls, "", constructorSig); + jmethodID constructor = (*env)->GetMethodID(env, cls, "", constructor_sig); if (constructor == NULL) { + cob_handle_error(NULL); return NULL; } jobject obj = (*env)->NewObjectA(env, cls, constructor, args); - return obj; -} - -void -cob_set_java_field(jobject obj, const char *fieldName, const char *fieldSig, jvalue value) { - jclass cls = (*env)->GetObjectClass(env, obj); - jfieldID fieldID = (*env)->GetFieldID(env, cls, fieldName, fieldSig); - if (fieldID == NULL) { - return; - } - - switch (fieldSig[0]) { - case 'Z': // jboolean - (*env)->SetBooleanField(env, obj, fieldID, value.z); - break; - case 'B': // jbyte - (*env)->SetByteField(env, obj, fieldID, value.b); - break; - case 'C': // jchar - (*env)->SetCharField(env, obj, fieldID, value.c); - break; - case 'S': // jshort - (*env)->SetShortField(env, obj, fieldID, value.s); - break; - case 'I': // jint - (*env)->SetIntField(env, obj, fieldID, value.i); - break; - case 'J': // jlong - (*env)->SetLongField(env, obj, fieldID, value.j); - break; - case 'F': // jfloat - (*env)->SetFloatField(env, obj, fieldID, value.f); - break; - case 'D': // jdouble - (*env)->SetDoubleField(env, obj, fieldID, value.d); - break; - case 'L': // jobject - (*env)->SetObjectField(env, obj, fieldID, value.l); - break; - default: - break; - } -} - -jvalue -cob_get_java_field(jobject obj, const char *fieldName, const char *fieldSig) { - jvalue result; - memset(&result, 0, sizeof(result)); - - jclass cls = (*env)->GetObjectClass(env, obj); - jfieldID fieldID = (*env)->GetFieldID(env, cls, fieldName, fieldSig); - if (fieldID == NULL) { - return result; - } - - switch (fieldSig[0]) { - case 'Z': // jboolean - result.z = (*env)->GetBooleanField(env, obj, fieldID); - break; - case 'B': // jbyte - result.b = (*env)->GetByteField(env, obj, fieldID); - break; - case 'C': // jchar - result.c = (*env)->GetCharField(env, obj, fieldID); - break; - case 'S': // jshort - result.s = (*env)->GetShortField(env, obj, fieldID); - break; - case 'I': // jint - result.i = (*env)->GetIntField(env, obj, fieldID); - break; - case 'J': // jlong - result.j = (*env)->GetLongField(env, obj, fieldID); - break; - case 'F': // jfloat - result.f = (*env)->GetFloatField(env, obj, fieldID); - break; - case 'D': // jdouble - result.d = (*env)->GetDoubleField(env, obj, fieldID); - break; - case 'L': // jobject - result.l = (*env)->GetObjectField(env, obj, fieldID); - break; - default: - break; - } - return result; -} - -jvalue -cob_call_java_method(jobject obj, const char *methodName, const char *methodSig, jvalue *args) { - jvalue result; - memset(&result, 0, sizeof(result)); - - jclass cls = (*env)->GetObjectClass(env, obj); - jmethodID methodID = (*env)->GetMethodID(env, cls, methodName, methodSig); - if (methodID == NULL) { - return result; - } - - switch (methodSig[strlen(methodSig) - 1]) { - case 'V': // void - (*env)->CallVoidMethodA(env, obj, methodID, args); - break; - case 'Z': // jboolean - result.z = (*env)->CallBooleanMethodA(env, obj, methodID, args); - break; - case 'B': // jbyte - result.b = (*env)->CallByteMethodA(env, obj, methodID, args); - break; - case 'C': // jchar - result.c = (*env)->CallCharMethodA(env, obj, methodID, args); - break; - case 'S': // jshort - result.s = (*env)->CallShortMethodA(env, obj, methodID, args); - break; - case 'I': // jint - result.i = (*env)->CallIntMethodA(env, obj, methodID, args); - break; - case 'J': // jlong - result.j = (*env)->CallLongMethodA(env, obj, methodID, args); - break; - case 'F': // jfloat - result.f = (*env)->CallFloatMethodA(env, obj, methodID, args); - break; - case 'D': // jdouble - result.d = (*env)->CallDoubleMethodA(env, obj, methodID, args); - break; - case 'L': // jobject - result.l = (*env)->CallObjectMethodA(env, obj, methodID, args); - break; - default: - break; + if (obj == NULL) { + cob_handle_error(NULL); + return NULL; } - return result; + jobject global_obj = (*env)->NewGlobalRef(env, obj); + (*env)->DeleteLocalRef(env, obj); + return global_obj; } int -cob_call_java(const cob_java_static_method_handle *method_handle) { +cob_call_java(const cob_java_handle *method_handle) { JNIEnv *env; va_list args; jobject result; if (method_handle == NULL) { - cob_set_exception(COB_EC_INVALID_ARGUMENT); return -1; } @@ -460,34 +180,41 @@ cob_call_java(const cob_java_static_method_handle *method_handle) { if ((*env)->ExceptionCheck(env)) { (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); - cob_set_exception(COB_EC_JAVA_EXCEPTION); + (*env)->ExceptionClear(env);; return -1; } return (result != NULL) ? 0 : -1; } -/* -extern "C" -JNIEXPORT jstring JNICALL Java_callJavaMemberFunction(jobject obj, jobject javaObject, jstring input) { - jclass cls = (*env)->GetObjectClass(env, javaObject); - if (cls == NULL) { +cob_java_handle* cob_resolve_java(const char *class_name, const char* method_name, const char *type_signature) { + if (jvm == NULL) { + cob_java_initialize(); + } + + jclass cls = (*env)->FindClass(env, class_name); + if (!cls) { + cob_handle_error("Class not found"); return NULL; } - const char* paramTypes[] = {"Ljava/lang/String;"}; - char* methodSig = cob_gen_method_sig(paramTypes, 1, "Ljava/lang/String;"); + jmethodID mid = (*env)->GetStaticMethodID(env, cls, method_name, type_signature); + if (!mid) { + (*env)->DeleteLocalRef(env, cls); + cob_handle_error("Method not found"); + return NULL; + } - jmethodID mid = (*env)->GetMethodID(env, cls, "greet", methodSig); - if (mid == NULL) { - free(methodSig); + cob_java_handle *handle = (cob_java_handle*)malloc(sizeof(cob_java_handle)); + if (!handle) { + (*env)->DeleteLocalRef(env, cls); + cob_handle_error("Memory allocation failed"); return NULL; } - jstring result = (jstring)(*env)->CallObjectMethod(env, javaObject, mid, input); + handle->cls = (*env)->NewGlobalRef(env, cls); + handle->mid = mid; + (*env)->DeleteLocalRef(env, cls); - free(methodSig); - return result; -} -*/ \ No newline at end of file + return handle; +} \ No newline at end of file From 52c90d6edc1be3417ef2c7630134209c69493830 Mon Sep 17 00:00:00 2001 From: Vtewari2311 Date: Fri, 5 Jul 2024 07:20:34 -0500 Subject: [PATCH 9/9] Duplicate Methods --- cobc/codegen.c | 18 ++++++++++++++++++ libcob/java.c | 46 ++++++++++++++++++++++------------------------ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/cobc/codegen.c b/cobc/codegen.c index 4617821eb..d79676065 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -436,6 +436,24 @@ lookup_func_call (const char *p) func_call_cache = clp; } +static void +lookup_java_call (const char *p) +{ + struct static_call_list *sclp; + + for (sclp = static_call_cache; sclp; sclp = sclp->next) { + if (strcmp (p, sclp->call_name) == 0) { + return; + } + } + sclp = cobc_parse_malloc (sizeof (struct static_call_list)); + sclp->call_name = p; + sclp->convention = convention; + sclp->return_type = return_type; + sclp->next = static_call_cache; + static_call_cache = sclp; +} + static void lookup_static_call (const char *p, int convention, int return_type) { diff --git a/libcob/java.c b/libcob/java.c index 39a04ba27..e35b6f97a 100644 --- a/libcob/java.c +++ b/libcob/java.c @@ -65,29 +65,6 @@ void cob_delete_java_object(jobject obj) { } } -cob_java_handle* -cob_resolve_java(const char *class_name, const char* method_name, const char *return_type, const char *type_signature) { - if(jvm == NULL) { - cob_java_initialize(); - } - jclass cls = (*env)->FindClass(env, class_name); - if (cls == NULL) { - return NULL; - } - - jmethodID mid = get_from_cache(cls, method_name, type_signature); - if (mid == NULL) { - mid = (*env)->GetStaticMethodID(env, cls, method_name, type_signature); - if (mid == NULL) { - return NULL; - } - } - // run autoconf - // allocate structure that represents the method to be called - cob_java_handle* h = (cob_java_handle*)cob_malloc(sizeof(cob_java_handle)); - return h; -} - static void cob_static_method(jclass cls, jmethodID mid) { (*env)->CallStaticVoidMethod(env, cls, mid, NULL); @@ -189,6 +166,8 @@ cob_call_java(const cob_java_handle *method_handle) { cob_java_handle* cob_resolve_java(const char *class_name, const char* method_name, const char *type_signature) { if (jvm == NULL) { + // Initializes JVM variables and env variables + // TODO: check return status; if error, return NULL cob_java_initialize(); } @@ -217,4 +196,23 @@ cob_java_handle* cob_resolve_java(const char *class_name, const char* method_nam (*env)->DeleteLocalRef(env, cls); return handle; -} \ No newline at end of file +} + +static void +cob_lookup_static_method(const char *className, const char *methodName, +const char *methodSig, const char *returnType, const char** paramTypes, int paramCount) { + jclass cls = (*env)->FindClass(env, className); + jmethodID mid = get_from_cache(cls, methodName, methodSig); + if (mid == NULL) { + char* signature = cob_gen_method_sig(paramTypes, paramCount, returnType); + mid = (*env)->GetStaticMethodID(env, cls, methodName, signature); + if (mid == NULL) { + free(signature); + (*jvm)->DestroyJavaVM(jvm); + return; + } + free(signature); + } + + cob_static_method(env, jvm, cls, mid); +}