Conversation
cobc/codegen.c
Outdated
| } | ||
| output ("cob_resolve_java ();"); | ||
| output_newline (); | ||
| output_block_close (); |
There was a problem hiding this comment.
Right here you need to generate a call to cob_call_java(…) with the appropriate handle name call_java_%s. Arguments will come in a subsequent PR.
cobc/ppparse.output
Outdated
There was a problem hiding this comment.
This file should not be committed.
po/en@boldquot.insert-header
Outdated
There was a problem hiding this comment.
Everything under po should not be committed either.
8df9f29 to
9164ac8
Compare
GitMensch
left a comment
There was a problem hiding this comment.
the real next change that should be done is an actual test for calling a static java method that has no parameters, to verify that java.c indeed works
cobc/codegen.c
Outdated
| static struct field_list *field_cache = NULL; | ||
| static struct field_list *local_field_cache = NULL; | ||
| static struct call_list *call_cache = NULL; | ||
| static struct java_call_list *call_java_cache = NULL; |
There was a problem hiding this comment.
minor formatting: use a tab before the *
cobc/codegen.c
Outdated
| lookup_java_call(const char *p) { | ||
| struct java_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 java_call_list)); |
There was a problem hiding this comment.
minor formatting: a space before the (, see lookup_call below (and sorry for not providing an automated formatting rule via gnu indent yet)
| lookup_call (const char *p) | ||
| { | ||
| struct call_list *clp; | ||
|
|
There was a problem hiding this comment.
minor formatting: please keep this nl here, reduces the diff :-)
cobc/codegen.c
Outdated
| if( | ||
| #ifdef HAVE_JNI | ||
| strncmp("Java.", s, 6) == 0 | ||
| #else | ||
| 0 | ||
| #endif | ||
| ) { |
There was a problem hiding this comment.
It is possible that the compiler isn't build with JNI, but the runtime is - and we don't call into JNI here either, so please use the code unconditional; in any case this whole block should be moved, either to the start of lookup_func_call, or (if there aren't too much places) in the caller with having this code be placed completely in a different function.
Mind the formatting = space before ( in that.
cobc/codegen.c
Outdated
| #endif | ||
| ) { | ||
| lookup_java_call(s + 6); | ||
| output_line ("if (call_java_%s == NULL || cob_glob_ptr->cob_physical_cancel)", name_str); |
There was a problem hiding this comment.
Is there a way to CANCEL a java class (and if yes to really unload it without jni teardown)?
I guess not - and in this case the check for physical cancel should be dropped.
cobc/codegen.c
Outdated
| output_block_open(); | ||
| output_prefix(); | ||
| output ("call_java_%s = ", name_str); | ||
| char *first_dot = strchr(s + 6, '.'); |
There was a problem hiding this comment.
To be able to compile that with C89 (still a requirement for 4.x, may be dropped later), move this line to the start of the block.
configure.ac
Outdated
| AC_ARG_ENABLE([java], | ||
| [AC_HELP_STRING([--disable-java], | ||
| [disable Java Interoperability])]) | ||
| AS_IF([test X$enable_java != Xno], [ |
There was a problem hiding this comment.
ARC_ARG_ENABLE is more about optional features (like the debug log) and less about external packages where AC_ARG_WITH is preferable (and would also match what configure has for example for libxml2).
See https://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.72/html_node/External-Software.html and adjust (you may postpone that part until you have actual running tests, though).
In any case please move the JNI block directly before the libxml2 part.
libcob/common.h
Outdated
| // #ifdef HAVE_JNI | ||
| // #include "jni.h" |
There was a problem hiding this comment.
these commented line and the one above should be dropped
|
I hope my commit to java.c did not break anything... (I just felt that the explanations would take much longer and those are more related to libcob in general than the changes of this project itself). And yes, once there is a running simple test, we should update the branch from gcos4 which will then also include the CI. for further commits. |
Update: Fixed warnings |
cobc/codegen.c
Outdated
| char *method_name; | ||
| const char *class_name; | ||
|
|
||
| lookup_java_call(p + 5); |
There was a problem hiding this comment.
Here you need to do some mangling: at the moment maybe substitute .s into some other character like _.
cobc/codegen.c
Outdated
| struct java_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 java_call_list)); | ||
| clp->call_name = p; | ||
| clp->next = call_java_cache; | ||
| call_java_cache = clp; |
There was a problem hiding this comment.
please indent on the left with tab
cobc/codegen.c
Outdated
| for (clp = func_call_cache; clp; clp = clp->next) { | ||
| if (strcmp (p, clp->call_name) == 0) { | ||
| return; | ||
| } | ||
| } | ||
| clp = cobc_parse_malloc (sizeof (struct call_list)); | ||
| clp->call_name = p; | ||
| clp->next = func_call_cache; | ||
| func_call_cache = clp; | ||
| for (clp = func_call_cache; clp; clp = clp->next) { | ||
| if (strcmp(p, clp->call_name) == 0) { | ||
| return; | ||
| } | ||
| } | ||
| clp = cobc_parse_malloc(sizeof(struct call_list)); | ||
| clp->call_name = p; | ||
| clp->next = func_call_cache; | ||
| func_call_cache = clp; |
There was a problem hiding this comment.
indentation got wrong, please clean up, which will also lead to a smaller diff
GitMensch
left a comment
There was a problem hiding this comment.
Requesting mostly formatting changes (and the variable name pointed out by Nicolas) for now - we really would need a testcase that showcase a call to a static, preferably parameterless, jre internal function works fine.
The one "real" change is to move the check for the java call into the parser - see review comments for the details.
And even if it doesn't work it should still be added to a new testcase at the end of run_extensions.at
cobc/codegen.c
Outdated
| if(strncasecmp("Java.", s, 5) == 0) { | ||
| output_java_call(s + 5); | ||
| return; | ||
| } else { |
There was a problem hiding this comment.
drop that else and the closing brace as you have a return already and don't need the additional scope (and create smaller diffs that way)
ChangeLog
Outdated
| * ax_prog_java.m4: Added macro for jni check | ||
| * ax_jni_include_dir.m4: Added macro for jni check | ||
| * configure.ac: added support for Java interoperability through JNI |
There was a problem hiding this comment.
space indent here, leave an empty line before and after the name, please
cobc/codegen.c
Outdated
| /* Dynamic link */ | ||
| if (name_is_literal_or_prototype) { | ||
| s = get_program_id_str (p->name); | ||
| if(strncasecmp("Java.", s, 5) == 0) { |
There was a problem hiding this comment.
this comparision should go into parser.y
Lines 12529 to 12530 in 00f6832
I suggest that after we found out if this is a java call or not, we set the call_convention to a new value matching a define JAVA_CALL. This has the benefit that we can then also check the parameter conformance later (codegen is too later for that) and output a warning if the current environment does not support Java interop.
In this function here we can then directly at the start or even in the caller get to output_call_java().
There was a problem hiding this comment.
@xevor11 To help with that, I've just rebased java-interop on top of master (which is trunk on the upstream). Now you can rebase your jni-config branch on top of that so you'll have access to the piece of code that's linked above.
After that you can define CB_CONV_JAVA in tree.h, and then do the check for the "Java." prefix in parser.y (I think right before the call to cb_check_conformance, but I'm not sure what that latter function does exactly).
There was a problem hiding this comment.
yes right before that function, which checks that something is according to a known prototype - in the case of Java that should check that only "java interop compatible" arguments are passed.
|
Addressing this specific system call:
I wrote a simple method call: however internally it must be create the VM and retrieve the methods from the JNI Function Table? |
|
There is another PR #174 which includes the non-void method handling as well |
GitMensch
left a comment
There was a problem hiding this comment.
The overall state is quite good!
Biggest issues:
- from glancing at the code I think
CALL...[NOT] ON EXCEPTIONis broken (adjust the tests as requested and we'll see) - the build system need some changes
- @nberth has a bit to do on the delay-load part (incl. ChangeLog entries)
- if possible I'd like to see the parameter check already, but we can leave this for later as well
DEPENDENCIES.md
Outdated
| 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. No newline at end of file |
There was a problem hiding this comment.
please word-wrap as for SCREEN SECTION
NEWS
Outdated
|
|
||
| * New GnuCOBOL features | ||
|
|
||
| ** Initial support for Java interoperability through JNI (new optional dependency JDK) |
There was a problem hiding this comment.
please adjust as for "JSON GENERATE" (just check in the same file searching for "json"):
- what is available now
- what is needed for support (I guess this will only be a dependency for runtime support, e. g. all checks in cobc work identical without that)
- add the related configure option / flags
- word-wrap your new content to col80
ChangeLog
Outdated
| * ax_prog_java.m4: Added macro for jni check | ||
| * ax_jni_include_dir.m4: Added macro for jni check |
There was a problem hiding this comment.
- combine both m4 entries to one entry (comma separate filename, include their "m4/" prefix)
- make the configure entry more specific, like the 2020-07-19 one
- add something like
NEWS, DEPENDENCIES: updated for JNI
There was a problem hiding this comment.
This file and most others in cobc miss a ChangeLog entry
libcob/java.c
Outdated
| if ((*env)->ExceptionCheck(env)) { | ||
| (*env)->ExceptionDescribe(env); |
There was a problem hiding this comment.
instead of ExceptionDescribe which puts the message unconditionally to stderr and implicit frees the exception, the message should be extracted and setup into last error - see call.c for the later;
no idea if there's a cleaner way (please give it a short check), but ChatGPT said we need to use JNI to get the details, giving the following example (which at least needs to be converted to C89 compat [vars+comments]:
// Find the Throwable class
jclass throwableClass = (*env)->FindClass(env, "java/lang/Throwable");
// Get the getMessage() method from Throwable class
jmethodID getMessageMethod = (*env)->GetMethodID(env, throwableClass, "getMessage", "()Ljava/lang/String;");
if (getMessageMethod != NULL) {
// Call getMessage() on the exception object
jstring message = (jstring)(*env)->CallObjectMethod(env, exception, getMessageMethod);
// Convert the Java String (jstring) to a C string (char*)
const char *messageChars = (*env)->GetStringUTFChars(env, message, NULL);
printf("Exception message: %s\n", messageChars);
(*env)->ReleaseStringUTFChars(env, message, messageChars); // Clean up
}
// Find java.io.StringWriter and java.io.PrintWriter classes
jclass stringWriterClass = (*env)->FindClass(env, "java/io/StringWriter");
jclass printWriterClass = (*env)->FindClass(env, "java/io/PrintWriter");
// Create a new StringWriter object
jobject stringWriter = (*env)->NewObject(env, stringWriterClass, (*env)->GetMethodID(env, stringWriterClass, "<init>", "()V"));
// Create a new PrintWriter object that wraps the StringWriter
jobject printWriter = (*env)->NewObject(env, printWriterClass,
(*env)->GetMethodID(env, printWriterClass, "<init>", "(Ljava/io/Writer;)V"),
stringWriter);
// Call exception.printStackTrace(printWriter) to write the stack trace to the StringWriter
jclass throwableClass = (*env)->GetObjectClassinstead of the convenience function ExceptionCheck use ExceptionOccurred which returns either NULL or the jthrowable we need for the code above
libcob/call.c
Outdated
| #else | ||
| static int first_java = 1; | ||
|
|
||
| COB_UNUSED (method_handle); |
There was a problem hiding this comment.
instead of the unused: check if it is empty (before the #if WITH_JNI) and set the relevant exceptions then; scoping the complete#else in a separate block {}
| output_line("cob_call_java(call_java_%s);\n", mangled); | ||
| output_newline(); | ||
| output_block_close(); | ||
| } |
There was a problem hiding this comment.
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.
tests/testsuite.src/run_java.at
Outdated
| AT_SETUP([CALL Java static void (void) (missing class)]) | ||
| AT_KEYWORDS([extensions jni]) | ||
|
|
||
| AT_SKIP_IF([test "$COB_HAS_JNI" = "no"]) | ||
|
|
||
| AT_DATA([prog.cob], [ | ||
| IDENTIFICATION DIVISION. | ||
| PROGRAM-ID. prog. | ||
| PROCEDURE DIVISION. | ||
| CALL "Java.Test.isAMissingClass" | ||
| STOP RUN. | ||
| ]) | ||
|
|
||
| AT_CHECK([$COMPILE prog.cob], [0], [], []) | ||
| AT_CHECK([$COBCRUN_DIRECT ./prog], [1], [], | ||
| [libcob: prog.cob:5: error: Java class 'Test' not found | ||
| ]) | ||
| AT_CLEANUP |
There was a problem hiding this comment.
duplicate this test with ON EXCEPTION and DISPLAY "java call not successful" in there; this duplicated test also doesn't need to be skipped if we don't have JNI as it should run in the same exception
| PROGRAM-ID. prog. | ||
| PROCEDURE DIVISION. | ||
| CALL "Java.Test.printHelloWorld" | ||
| STOP RUN. |
There was a problem hiding this comment.
add NOT ON EXCEPTION DISPLAY "Java call worked" to this call
|
I've got word from the original author of the java related macros used and that's (part of) his answer:
I'm likely to adjust the part configure for that (but that likely takes some days until I get to this), @nberth can you please check the review related to the delay-load part and @xevor11 could you please check on the rest? |
45956df to
5aaa4a9
Compare
cobc/codegen.c
Outdated
| const char *class_name, *method_name; | ||
| char mangled[COB_NORMAL_BUFF]; | ||
|
|
||
| /* TODO: move that back into cb_check_conformance (*) */ |
There was a problem hiding this comment.
@xevor11 I think you have started moving this check and the one below back into cb_check_conformance; so I'll stop pushing changes to this branch to let you advance with that.

Cleaned up java.c, added the requested changes from PR#150, ready for feedback and comments