Skip to content

Commit

Permalink
* Move sizeof() and offsetof() data to global variables to preve…
Browse files Browse the repository at this point in the history
…nt `StackOverflowError` in `JNI_OnLoad()` (issue bytedeco/javacpp-presets#331)

 * Propagate within `Parser` type information from macros to other macros referencing them

Also fix a few more issues with `Parser`
  • Loading branch information
saudet committed Nov 27, 2017
1 parent 251c5be commit 7968093
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 72 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

* Move `sizeof()` and `offsetof()` data to global variables to prevent `StackOverflowError` in `JNI_OnLoad()` ([issue bytedeco/javacpp-presets#331](https://github.com/bytedeco/javacpp-presets/issues/331))
* Propagate within `Parser` type information from macros to other macros referencing them
* Add support for `JNI_OnLoad_libname()` naming scheme for iOS via new `platform.library.static=true` property
* Improve the clarity of error messages on `Parser` failures
* Fix `Parser` issues with multiple `typedef` declarations in a single statement
Expand Down
101 changes: 51 additions & 50 deletions src/main/java/org/bytedeco/javacpp/tools/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1162,52 +1162,10 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
out.println("static void " + name + "_deallocateArray(void* p) { delete[] (" + typeName[0] + typeName[1] + ")p; }");
}
out.println();
out.println("extern \"C\" {");
if (out2 != null) {
out2.println();
out2.println("#ifdef __cplusplus");
out2.println("extern \"C\" {");
out2.println("#endif");
out2.println("JNIIMPORT int JavaCPP_init" + loadSuffix + "(int argc, const char *argv[]);");
out.println();
out.println("JNIEXPORT int JavaCPP_init" + loadSuffix + "(int argc, const char *argv[]) {");
out.println("#if defined(__ANDROID__) || TARGET_OS_IPHONE");
out.println(" return JNI_OK;");
out.println("#else");
out.println(" if (JavaCPP_vm != NULL) {");
out.println(" return JNI_OK;");
out.println(" }");
out.println(" int err;");
out.println(" JavaVM *vm;");
out.println(" JNIEnv *env;");
out.println(" int nOptions = 1 + (argc > 255 ? 255 : argc);");
out.println(" JavaVMOption options[256] = { { NULL } };");
out.println(" options[0].optionString = (char*)\"-Djava.class.path=" + classPath.replace('\\', '/') + "\";");
out.println(" for (int i = 1; i < nOptions && argv != NULL; i++) {");
out.println(" options[i].optionString = (char*)argv[i - 1];");
out.println(" }");
out.println(" JavaVMInitArgs vm_args = { " + JNI_VERSION + ", nOptions, options };");
out.println(" return (err = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args)) == JNI_OK && vm != NULL && (err = JNI_OnLoad" + loadSuffix + "(vm, NULL)) >= 0 ? JNI_OK : err;");
out.println("#endif");
out.println("}");
}
out.println(); // XXX: JNI_OnLoad() should ideally be protected by some mutex
out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + loadSuffix + "(JavaVM* vm, void* reserved) {");
out.println(" JNIEnv* env;");
out.println(" if (vm->GetEnv((void**)&env, " + JNI_VERSION + ") != JNI_OK) {");
out.println(" JavaCPP_log(\"Could not get JNIEnv for " + JNI_VERSION + " inside JNI_OnLoad" + loadSuffix + "().\");");
out.println(" return JNI_ERR;");
out.println(" }");
out.println(" if (JavaCPP_vm == vm) {");
out.println(" return env->GetVersion();");
out.println(" }");
out.println(" JavaCPP_vm = vm;");
out.println(" JavaCPP_haveAllocObject = env->functions->AllocObject != NULL;");
out.println(" JavaCPP_haveNonvirtual = env->functions->CallNonvirtualVoidMethodA != NULL;");
out.println(" const char* members[" + jclasses.size() + "][" + maxMemberSize + "] = {");
out.println("static const char* JavaCPP_members[" + jclasses.size() + "][" + maxMemberSize + "] = {");
classIterator = jclasses.iterator();
while (classIterator.hasNext()) {
out.print(" { ");
out.print(" { ");
Set<String> m = members.get(classIterator.next());
Iterator<String> memberIterator = m == null ? null : m.iterator();
if (memberIterator == null || !memberIterator.hasNext()) {
Expand All @@ -1224,10 +1182,10 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
}
}
out.println(" };");
out.println(" int offsets[" + jclasses.size() + "][" + maxMemberSize + "] = {");
out.println("static int JavaCPP_offsets[" + jclasses.size() + "][" + maxMemberSize + "] = {");
classIterator = jclasses.iterator();
while (classIterator.hasNext()) {
out.print(" { ");
out.print(" { ");
Class c = classIterator.next();
Set<String> m = members.get(c);
Iterator<String> memberIterator = m == null ? null : m.iterator();
Expand Down Expand Up @@ -1255,7 +1213,7 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
}
}
out.println(" };");
out.print(" int memberOffsetSizes[" + jclasses.size() + "] = { ");
out.print("static int JavaCPP_memberOffsetSizes[" + jclasses.size() + "] = { ");
classIterator = jclasses.iterator();
while (classIterator.hasNext()) {
Set<String> m = members.get(classIterator.next());
Expand All @@ -1265,18 +1223,61 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
}
}
out.println(" };");
out.println();
out.println("extern \"C\" {");
if (out2 != null) {
out2.println();
out2.println("#ifdef __cplusplus");
out2.println("extern \"C\" {");
out2.println("#endif");
out2.println("JNIIMPORT int JavaCPP_init" + loadSuffix + "(int argc, const char *argv[]);");
out.println();
out.println("JNIEXPORT int JavaCPP_init" + loadSuffix + "(int argc, const char *argv[]) {");
out.println("#if defined(__ANDROID__) || TARGET_OS_IPHONE");
out.println(" return JNI_OK;");
out.println("#else");
out.println(" if (JavaCPP_vm != NULL) {");
out.println(" return JNI_OK;");
out.println(" }");
out.println(" int err;");
out.println(" JavaVM *vm;");
out.println(" JNIEnv *env;");
out.println(" int nOptions = 1 + (argc > 255 ? 255 : argc);");
out.println(" JavaVMOption options[256] = { { NULL } };");
out.println(" options[0].optionString = (char*)\"-Djava.class.path=" + classPath.replace('\\', '/') + "\";");
out.println(" for (int i = 1; i < nOptions && argv != NULL; i++) {");
out.println(" options[i].optionString = (char*)argv[i - 1];");
out.println(" }");
out.println(" JavaVMInitArgs vm_args = { " + JNI_VERSION + ", nOptions, options };");
out.println(" return (err = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args)) == JNI_OK && vm != NULL && (err = JNI_OnLoad" + loadSuffix + "(vm, NULL)) >= 0 ? JNI_OK : err;");
out.println("#endif");
out.println("}");
}
out.println(); // XXX: JNI_OnLoad() should ideally be protected by some mutex
out.println("JNIEXPORT jint JNICALL JNI_OnLoad" + loadSuffix + "(JavaVM* vm, void* reserved) {");
out.println(" JNIEnv* env;");
out.println(" if (vm->GetEnv((void**)&env, " + JNI_VERSION + ") != JNI_OK) {");
out.println(" JavaCPP_log(\"Could not get JNIEnv for " + JNI_VERSION + " inside JNI_OnLoad" + loadSuffix + "().\");");
out.println(" return JNI_ERR;");
out.println(" }");
out.println(" if (JavaCPP_vm == vm) {");
out.println(" return env->GetVersion();");
out.println(" }");
out.println(" JavaCPP_vm = vm;");
out.println(" JavaCPP_haveAllocObject = env->functions->AllocObject != NULL;");
out.println(" JavaCPP_haveNonvirtual = env->functions->CallNonvirtualVoidMethodA != NULL;");
out.println(" jmethodID putMemberOffsetMID = JavaCPP_getStaticMethodID(env, " +
jclasses.index(Loader.class) + ", \"putMemberOffset\", \"(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/Class;\");");
out.println(" if (putMemberOffsetMID == NULL) {");
out.println(" return JNI_ERR;");
out.println(" }");
out.println(" for (int i = 0; i < " + jclasses.size() + " && !env->ExceptionCheck(); i++) {");
out.println(" for (int j = 0; j < memberOffsetSizes[i] && !env->ExceptionCheck(); j++) {");
out.println(" for (int j = 0; j < JavaCPP_memberOffsetSizes[i] && !env->ExceptionCheck(); j++) {");
out.println(" if (env->PushLocalFrame(3) == 0) {");
out.println(" jvalue args[3];");
out.println(" args[0].l = env->NewStringUTF(JavaCPP_classNames[i]);");
out.println(" args[1].l = members[i][j] == NULL ? NULL : env->NewStringUTF(members[i][j]);");
out.println(" args[2].i = offsets[i][j];");
out.println(" args[1].l = JavaCPP_members[i][j] == NULL ? NULL : env->NewStringUTF(JavaCPP_members[i][j]);");
out.println(" args[2].i = JavaCPP_offsets[i][j];");
out.println(" jclass cls = (jclass)env->CallStaticObjectMethodA(JavaCPP_getClass(env, " +
jclasses.index(Loader.class) + "), putMemberOffsetMID, args);");
out.println(" if (cls == NULL || env->ExceptionCheck()) {");
Expand Down
Loading

0 comments on commit 7968093

Please sign in to comment.