Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial JNI configuration #157

Open
wants to merge 20 commits into
base: java-interop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@

2024-07-12 Vedant Tewari <[email protected]>

2023-02-25 Ron Norman <[email protected]>
* m4/ax_prog_java.m4, m4/ax_jni_include_dir.m4: Added macros for JNI checks
* configure.ac: Added support for Java interoperability through JNI, extending GnuCOBOL ability to interact with external Java libraries
* NEWS, DEPENDENCIES: Updated to reflect support for JNI

2023-02-25 Ron Norman <[email protected]>

* configure.ac: Add check for sys/time.h

Expand Down
15 changes: 15 additions & 0 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ 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.

Java Development Kit (JDK) 8 or later

https://openjdk.org/

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
Expand Down
10 changes: 10 additions & 0 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,13 @@ 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.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ NEWS - user visible changes -*- outline -*-


* New GnuCOBOL features
** Initial support for Java interoperability through JNI (optional dependency JDK): Java Interoperability: Added initial support for calling
Java methods from COBOL programs via the Java Native Interface (JNI). This feature currently supports static Java methods with no parameters, while handling parameters and return values will be introduced in future updates. The system detects missing Java classes and malformed method names and provides proper error handling. COBOL developers can now use ON EXCEPTION and NOT ON EXCEPTION clauses with Java calls. JNI support is an optional feature that requires the Java Development Kit (JDK) to be installed on the system. Use the --with-java configure option to enable it, and ensure that the JAVA_HOME environment variable is set at runtime to locate the JDK. Without JNI, the runtime will function as usual but Java-related COBOL calls (e.g., CALL "Java.<Class>.<Method>") will not be available

** file handling: added backends for ODBC (so far PostgrSQL, MySQL, SQLite,
MSSQL) and OCI, along with new directory COB_SCHEMA_DIR containing the
Expand Down
6 changes: 6 additions & 0 deletions cobc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@

2024-08-14 Nicolas Berthier <[email protected]>

* cobc.c (cobc_print_info): added note for Java interoperability
* typeck.c, tree.h (cb_check_conformance): pass call convention to deal
with calls of Java methods

2024-08-04 David Declerck <[email protected]>

Adjustments to merge 2022-12-21:
Expand Down
6 changes: 6 additions & 0 deletions cobc/cobc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,12 @@ cobc_print_info (void)

cobc_var_print (_("JSON library"), _(WITH_JSON), 0);

#ifdef WITH_JNI
cobc_var_print (_("Java interoperability"), _("enabled"), 0);
#else
cobc_var_print (_("Java interoperability"), _("disabled"), 0);
#endif
nberth marked this conversation as resolved.
Show resolved Hide resolved

#ifdef COB_DEBUG_LOG
cobc_var_print ("DEBUG_LOG", _("enabled"), 0);
#endif
Expand Down
85 changes: 84 additions & 1 deletion cobc/codegen.c
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file and most others in cobc miss a ChangeLog entry

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
Copyright (C) 2003-2024 Free Software Foundation, Inc.
Written by Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch,
Edward Hart
Edward Hart, Vedant Tewari

This file is part of GnuCOBOL.

Expand Down Expand Up @@ -147,6 +147,7 @@ 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;
static struct call_list *call_java_cache = NULL;
static struct call_list *func_call_cache = NULL;
static struct static_call_list *static_call_cache = NULL;
static struct base_list *base_cache = NULL;
Expand Down Expand Up @@ -395,6 +396,22 @@ lookup_source (const char *p)
return source_id++;
}

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

for (clp = call_java_cache; clp; clp = clp->next) {
if (strcmp (p, clp->call_name) == 0) {
return;
}
}
clp = cobc_parse_malloc (sizeof (struct call_list));
clp->call_name = cobc_parse_strdup (p);
clp->next = call_java_cache;
call_java_cache = clp;
}

static void
lookup_call (const char *p)
{
Expand Down Expand Up @@ -1978,6 +1995,11 @@ output_call_cache (void)
output_local ("static cob_call_union\tcall_%s;\n",
call->call_name);
}
call_java_cache = call_list_reverse (call_java_cache);
for (call = call_java_cache; call; call = call->next) {
output_local ("static cob_java_handle*\tcall_java_%s;\n",
call->call_name);
}
func_call_cache = call_list_reverse (func_call_cache);
for (call = func_call_cache; call; call = call->next) {
output_local ("static cob_call_union\tfunc_%s;\n",
Expand Down Expand Up @@ -7068,6 +7090,61 @@ output_field_constant (cb_tree x, int n, const char *flagname)
output_newline ();
}

static void
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;");
}

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);
}
output_block_close ();
output_line ("COB_RESET_EXCEPTION(0);");
}

static void
output_java_call (struct cb_call *p)
{
char *class_and_method_name, *class_name, *method_name, *last_dot, *c;
char mangled[COB_NORMAL_BUFF];

/* Assume "Java." prefix (enforced in `parser.y`, rule `call_body`) */
class_and_method_name = (char*)CB_LITERAL(p->name)->data + 5;

strncpy (mangled, class_and_method_name, COB_NORMAL_MAX);
for (c = mangled; *c; c++) {
if (*c == '.') *c = '_';
}
lookup_java_call (mangled);

last_dot = strrchr (class_and_method_name, '.');
*last_dot = '\0';
method_name = last_dot + 1;
class_name = class_and_method_name;
for (c = class_name; *c; c++) {
if (*c == '.') *c = '/';
}

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_exception_handling (p);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do an exception check afterwards, as done for normal calls; also add the ON EXCEPTION/ NOT ON EXCEPTION codegen; possibly by moving those parts out of output_call() and executing them also in the 'CB_CONV_JAVA` part.


static void
output_call (struct cb_call *p)
{
Expand Down Expand Up @@ -7097,6 +7174,12 @@ output_call (struct cb_call *p)
}
system_call = NULL;

if (p->convention & CB_CONV_JAVA) {
output_java_call(p);
output_exception_handling(p);
return;
}

#ifdef _WIN32
if (p->convention & CB_CONV_STDCALL) {
convention = "_std";
Expand Down
8 changes: 6 additions & 2 deletions cobc/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -12253,13 +12253,17 @@ call_body:

/* Check parameter conformance, if we can work out what is being called. */
if (CB_LITERAL_P ($3)) {
cb_check_conformance ($3, $7, $8);
/* Check for "Java." prefix and set call convention */
if (strncasecmp("Java.", (char *)CB_LITERAL ($3)->data, 5) == 0) {
call_conv = CB_CONV_JAVA;
}
cb_check_conformance ($3, $7, $8, call_conv);
} else if (CB_REFERENCE_P ($3)) {
cb_tree ref = cb_ref ($3);
if ((CB_FIELD_P (ref) && CB_FIELD (ref)->flag_item_78)
|| CB_PROGRAM_P (ref)
|| CB_PROTOTYPE_P (ref)) {
cb_check_conformance ($3, $7, $8);
cb_check_conformance ($3, $7, $8, call_conv);
}
}

Expand Down
3 changes: 2 additions & 1 deletion cobc/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ enum cb_tag {
#define CB_CONV_THUNK_16 (1 << 5)
#define CB_CONV_STDCALL (1 << 6)
#define CB_CONV_COBOL (1 << 15)
#define CB_CONV_JAVA (1 << 16)
#define CB_CONV_C (0)
#define CB_CONV_PASCAL (CB_CONV_L_TO_R | CB_CONV_CALLEE_STACK)

Expand Down Expand Up @@ -2591,7 +2592,7 @@ extern cb_tree cb_build_write_advancing_lines (cb_tree, cb_tree);
extern cb_tree cb_build_write_advancing_mnemonic (cb_tree, cb_tree);
extern cb_tree cb_build_write_advancing_page (cb_tree);
extern cb_tree cb_check_sum_field (cb_tree x);
extern void cb_check_conformance (cb_tree, cb_tree, cb_tree);
extern void cb_check_conformance (cb_tree, cb_tree, cb_tree, int);
extern void cb_emit_initiate (cb_tree rep);
extern void cb_emit_terminate (cb_tree rep);
extern void cb_emit_generate (cb_tree rep);
Expand Down
20 changes: 19 additions & 1 deletion cobc/typeck.c
Original file line number Diff line number Diff line change
Expand Up @@ -3921,7 +3921,7 @@ check_argument_conformance (struct cb_program *program, cb_tree argument_tripple

void
cb_check_conformance (cb_tree prog_ref, cb_tree using_list,
cb_tree returning)
cb_tree returning, int call_conv)
{
struct cb_program *program = NULL;
cb_tree l;
Expand All @@ -3932,6 +3932,24 @@ cb_check_conformance (cb_tree prog_ref, cb_tree using_list,
const struct cb_field *prog_returning_field;
const struct cb_field *call_returning_field;

if (call_conv == CB_CONV_JAVA && CB_LITERAL_P (prog_ref)) {
char *full_name, *class_and_method_name, *dot;
full_name = (char *)CB_LITERAL(prog_ref)->data;
class_and_method_name = full_name + 5;
dot = strchr (class_and_method_name, '.');
if (dot == NULL) {
cb_error_x (prog_ref, _("malformed Java method name '%s', "
"expected format 'Java.ClassName.methodName'"),
full_name);
return;
}
if (using_list != NULL || returning != NULL) {
CB_PENDING ("Java method call with parameters or return values");
COBC_ABORT ();
}
return;
}

/* Try to get the program referred to by prog_ref. */
program = try_get_program (prog_ref);
if (!program) {
Expand Down
Loading
Loading