Skip to content

Commit

Permalink
Try and fix loading of libjvm for older JREs, and JNI code
Browse files Browse the repository at this point in the history
  • Loading branch information
nberth committed Nov 6, 2024
1 parent 456faeb commit 45956df
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 107 deletions.
103 changes: 50 additions & 53 deletions cobc/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ lookup_source (const char *p)
}

static void
lookup_java_call(const char *p)
lookup_java_call (const char *p)
{
struct call_list *clp;

Expand All @@ -407,7 +407,7 @@ lookup_java_call(const char *p)
}
}
clp = cobc_parse_malloc (sizeof (struct call_list));
clp->call_name = p;
clp->call_name = cobc_parse_strdup (p);
clp->next = call_java_cache;
call_java_cache = clp;
}
Expand Down Expand Up @@ -7091,73 +7091,70 @@ output_field_constant (cb_tree x, int n, const char *flagname)
}

static void
output_exception_handling(struct cb_call *p)
output_exception_handling (struct cb_call *p)
{
if (p->stmt1) {
output_line("cob_glob_ptr->cob_stmt_exception = 1;");
output_line("COB_RESET_EXCEPTION(0);");
} else {
output_line("cob_glob_ptr->cob_stmt_exception = 0;");
}
if (p->stmt1) {
output_line ("cob_glob_ptr->cob_stmt_exception = 1;");
output_line ("COB_RESET_EXCEPTION(0);");
} else {
output_line ("cob_glob_ptr->cob_stmt_exception = 0;");
}

output_line("if ((cob_glob_ptr->cob_exception_code & 0xff00) != 0) ");
output_block_open();
output_line ("if ((cob_glob_ptr->cob_exception_code & 0xff00) != 0) ");
output_block_open ();

if (p->stmt1) {
output_stmt(p->stmt1);
} else if (p->stmt2) {
output_stmt(p->stmt2);
if (p->stmt1) {
output_stmt (p->stmt1);
} else if (p->stmt2) {
output_stmt (p->stmt2);
}
output_block_close();
output_line("COB_RESET_EXCEPTION(0);");
output_block_close ();
output_line ("COB_RESET_EXCEPTION(0);");
}

static void
output_java_call(struct cb_call *p)
output_java_call (struct cb_call *p)
{
if (p->args != NULL || p->call_returning != NULL) {
CB_PENDING("Java method call with parameters or return values");
COBC_ABORT();
}
char *full_name, *class_and_method_name, *last_dot;
const char *class_name, *method_name;
char mangled[COB_NORMAL_BUFF];

char* full_name = (char*)CB_LITERAL(p->name)->data; /* Assume java.prefix (enforced in `parser.y`, rule `call_body`) */
char* class_and_method_name = full_name + 5;
char *last_dot;
char *method_name;
const char *class_name;
char* mangled;
/* TODO: move that back into cb_check_conformance (*) */
if (p->args != NULL || p->call_returning != NULL) {
CB_PENDING("Java method call with parameters or return values");
COBC_ABORT();
}

// Directly duplicate the class_and_method_name
mangled = strdup(class_and_method_name);
if (!mangled) {
cobc_err_msg(_("Memory allocation failed for mangled name"));
COBC_ABORT();
}
full_name = (char*)CB_LITERAL(p->name)->data;

last_dot = strrchr (mangled, '.');
*last_dot = '_';
lookup_java_call(mangled);
/* Assume "Java." prefix (enforced in `parser.y`, rule `call_body`) */
class_and_method_name = full_name + 5;

last_dot = strrchr(class_and_method_name, '.');
strncpy (mangled, class_and_method_name, COB_NORMAL_MAX);
last_dot = strrchr (mangled, '.');
*last_dot = '_';
lookup_java_call (mangled);

if (last_dot == NULL) {
cobc_err_msg(_("malformed call '%s' to a Java method"), class_and_method_name);
cobc_free(mangled);
return;
}
last_dot = strrchr (class_and_method_name, '.');
/* TODO: same as (*) above */
if (last_dot == NULL) {
cobc_err_msg(_("malformed call '%s' to a Java method"), class_and_method_name);
cobc_free(mangled);
return;
}

*last_dot = '\0';
method_name = last_dot + 1;
class_name = class_and_method_name;
*last_dot = '\0';
method_name = last_dot + 1;
class_name = class_and_method_name;

output_line("if (call_java_%s == NULL)", mangled);
output_block_open();
output_line ("if (call_java_%s == NULL)", mangled);
output_block_open ();
output_line ("call_java_%s = cob_resolve_java (\"%s\", \"%s\", \"()V\");",
mangled, class_name, method_name);
output_line ("cob_call_java (call_java_%s);", mangled);
output_block_close ();

output_line("call_java_%s = cob_resolve_java(\"%s\", \"%s\", \"()V\");",
mangled, class_name, method_name);
output_line("cob_call_java(call_java_%s);", mangled);
output_block_close();
output_exception_handling(p);
output_exception_handling (p);
}

static void
Expand Down
24 changes: 17 additions & 7 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ dnl done via AC_CHECK_FUNCS: AH_TEMPLATE([HAVE_RAISE], [Has raise function])
AH_TEMPLATE([HAVE_FINITE_IEEEFP_H],
[Declaration of finite function in ieeefp.h instead of math.h])

AH_TEMPLATE([COB_JAVA_ARCH], [Java platform architecture])

dnl preparation for cross-compilation
AC_ARG_PROGRAM

Expand Down Expand Up @@ -951,6 +953,11 @@ AS_IF([test "x$with_java" != "xno"], [
AC_MSG_NOTICE([Given Java home: ${JAVA_HOME}])
fi
dnl Note: One more hack needed to properly locate libjvm with
dnl early versions of openjdk (1.8 at least).
JAVA_ARCH="$( $JAVA -XshowSettings:properties -version 2>&1 >/dev/null | \
$SED -e '/^[ ]*os.arch/!d' -e 's/.*=[ ]*//' )"
dnl Note: AX_PROG_JAVAC might find a `javac` binary that does
dnl not match the version of `$JAVA` found above, so we set
dnl its path manually.
Expand All @@ -962,15 +969,17 @@ AS_IF([test "x$with_java" != "xno"], [
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
JNI_CPPFLAGS="$JNI_CPPFLAGS -I$JNI_INCLUDE_DIR"
done
for _dir in "${JAVA_HOME}/jre/lib" "${JAVA_HOME}/lib"; do
for _dir in "${JAVA_HOME}/jre/lib" \
"${JAVA_HOME}/jre/lib/${JAVA_ARCH}" \
"${JAVA_HOME}/lib"; do
if test -d "$_dir"; then
JNI_LIBS="$JNI_LIBS -L$_dir"
fi
if test -d "$_dir/server"; then
JNI_LIBS="$JNI_LIBS -L$_dir/server"
fi
if test -d "$_dir/client"; then
JNI_LIBS="$JNI_LIBS -L$_dir/client"
if test -d "$_dir/server"; then
JNI_LIBS="$JNI_LIBS -L$_dir/server"
fi
if test -d "$_dir/client"; then
JNI_LIBS="$JNI_LIBS -L$_dir/client"
fi
fi
done
curr_LIBS="$LIBS"
Expand All @@ -988,6 +997,7 @@ AS_IF([test "x$with_java" != "xno"], [
], [
AC_MSG_RESULT([yes])
AC_DEFINE([WITH_JNI], [1])
AC_DEFINE_UNQUOTED([COB_JAVA_ARCH], ["$JAVA_ARCH"])
JNI_LDFLAGS="$JNI_LIBS"
JNI_LIBS="-ljvm"
cob_has_jni=yes
Expand Down
14 changes: 11 additions & 3 deletions libcob/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ lt_dlerror (void)
static lt_dlhandle jvm_handle = NULL;
#else
/* Using libltdl, no need to preload. */
# define JVM_PRELOAD 0
#endif

#include "sysdefines.h"
Expand Down Expand Up @@ -1855,7 +1854,7 @@ cob_exit_call (void)
}
base_dynload_ptr = NULL;

#if JVM_PRELOAD
#ifdef JVM_PRELOAD
if (jvm_handle) {
lt_dlclose (jvm_handle);
jvm_handle = NULL;
Expand Down Expand Up @@ -1993,6 +1992,8 @@ cob_init_call (cob_global *lptr, cob_settings* sptr, const int check_mainhandle)

/* Java API handling */

#ifdef WITH_JNI

/* "Standard" path suffixes to the dynamically loadable JVM library, from
"typical" JAVA_HOME. */
const char* const path_to_jvm[] = {
Expand All @@ -2003,7 +2004,11 @@ const char* const path_to_jvm[] = {
#else
# define JVM_FILE "libjvm." COB_MODULE_EXT
"/lib/server",
"/jre/lib/server",
"/jre/lib/" COB_JAVA_ARCH "/server",
"/lib/client",
"/jre/lib/client",
"/jre/lib/" COB_JAVA_ARCH "/client",
#endif
NULL,
};
Expand Down Expand Up @@ -2040,13 +2045,14 @@ init_jvm_search_dirs (void) {
break;
#else
/* Append to search path. */
int success;
# warning On some systems, JAVA_HOME-based lookup via `libltdl` does not work
if (snprintf (jvm_path, (size_t)COB_FILE_MAX, "%s%s",
java_home, path_suffix) == 0) {
continue;
}
DEBUG_LOG ("call", ("appending '%s' to load path: ", jvm_path));
int success = lt_dladdsearchdir (jvm_path);
success = lt_dladdsearchdir (jvm_path);
DEBUG_LOG ("call", ("%s\n", success == 0 ? "success" : "failed"));
#endif
}
Expand Down Expand Up @@ -2092,6 +2098,8 @@ cob_init_java (void) {
return 0;
}

#endif /* WITH_JNI */

cob_java_handle*
cob_resolve_java (const char *class_name,
const char *method_name,
Expand Down
2 changes: 0 additions & 2 deletions libcob/coblocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,8 +480,6 @@ COB_HIDDEN void cob_runtime_warning_ss (const char *, const char *);
COB_EXPIMP int cob_ncase_cmp (char *, const char *, unsigned );
COB_EXPIMP char * cob_str_case_str (char *, const char *);

COB_EXPIMP int cob_jni_init (cob_java_api *api);

/* static inline of smaller helpers */

static COB_INLINE int
Expand Down
39 changes: 18 additions & 21 deletions libcob/java.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@

/* Force symbol exports */
#define COB_LIB_EXPIMP
#include "config.h"
#include "common.h"
#include "libcob.h"
#include "coblocal.h"

/* Declarations */
Expand All @@ -38,32 +38,29 @@ typedef struct __cob_java_static_method {
jmethodID mid;
} cob_java_handle;

/* Only exported symbol: */
int cob_jni_init (cob_java_api *api);

static int /* non-zero means there's an error */
jvm_load (void) {
/* JDK/JRE 6 VM initialization arguments */
JavaVMInitArgs args;
JavaVMOption* options = { 0, };
const char *classpath;
size_t option_len;
char option_buffer[COB_NORMAL_BUFF];
JavaVMInitArgs args;
JavaVMOption options[1];
const char *classpath;
char cp_buffer[COB_MEDIUM_BUFF];

args.version = JNI_VERSION_1_6;
classpath = getenv ("CLASSPATH");
if (classpath == NULL) {
classpath = "";
}
args.nOptions = 1;
option_len = strlen("-Djava.class.path=") + strlen(classpath) + 1;
if (option_len > sizeof(option_buffer)) {
return -1;
}
strcpy(option_buffer, "-Djava.class.path=");
strcat(option_buffer, classpath);
options[0].optionString = option_buffer;
args.options = options;
args.ignoreUnrecognized = 1;
/* loading and initializing a Java VM, returning as JNI interface */
return JNI_CreateJavaVM(&jvm, (void**)&env, &args);
args.nOptions = 0;
args.ignoreUnrecognized = JNI_FALSE;

if ((classpath = getenv ("CLASSPATH")) != NULL) {
snprintf (cp_buffer, COB_MEDIUM_MAX,
"-Djava.class.path=%s", classpath);
options[args.nOptions++].optionString = cp_buffer;
}

return JNI_CreateJavaVM (&jvm, (void**)&env, &args);
}

static
Expand Down
27 changes: 6 additions & 21 deletions tests/testsuite.src/run_java.at
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class Test {
}
}
])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
Expand All @@ -47,25 +48,7 @@ AT_CHECK([$JAVAC Test.java], [0], [], [])
AT_CHECK([$COMPILE prog.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./prog], [0],
[Hello world!
])
AT_CLEANUP


AT_SETUP([CALL Java with malformed method name])
AT_KEYWORDS([extensions jni malformed])

AT_SKIP_IF([test "$COB_HAS_JNI" = "no"])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
PROCEDURE DIVISION.
CALL "Java.InvalidName"
STOP RUN.
])

AT_CHECK([$COMPILE prog.cob], [1], [],
[prog.cob:5: error: malformed Java method name 'Java.InvalidName', expected format 'Java.ClassName.methodName'
Java call worked
])
AT_CLEANUP

Expand Down Expand Up @@ -114,6 +97,7 @@ AT_CHECK([$COBCRUN_DIRECT ./prog], [1], [],
])
AT_CLEANUP


AT_SETUP([CALL Java static void (void) (missing class with ON EXCEPTION)])
AT_KEYWORDS([extensions jni exception])

Expand All @@ -133,11 +117,13 @@ AT_CHECK([$COBCRUN_DIRECT ./prog], [0], [], [java call not successful
])
AT_CLEANUP


AT_SETUP([CALL Java static void (void) in a package])
AT_KEYWORDS([extensions jni package])

AT_SKIP_IF([test "$COB_HAS_JNI" = "no"])

AT_CHECK([mkdir -p testpackage])
AT_DATA([testpackage/Test.java], [
package testpackage;
public class Test {
Expand All @@ -158,12 +144,11 @@ AT_DATA([prog.cob], [
STOP RUN.
])

AT_CHECK([mkdir -p testpackage])
AT_CHECK([$JAVAC testpackage/Test.java], [0], [], [])
AT_CHECK([$COMPILE prog.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./prog], [0],
[Hello from package!
Java call to package class worked
])

AT_CLEANUP
AT_CLEANUP
Loading

0 comments on commit 45956df

Please sign in to comment.