From ea8d3e109a708f05e46ea5b0eb68ba301f425d40 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 19 Jan 2017 11:27:03 +0100 Subject: [PATCH] 8171855: Move package name transformations during module bootstrap into native code Reviewed-by: alanb, acorn, lfoltan, mchung, plevart, hseigel, sspitsyn --- .../classes/java/lang/reflect/Module.java | 32 ++--- jdk/src/java.base/share/native/include/jvm.h | 55 +++++-- .../java.base/share/native/libjava/Module.c | 136 +++++++++++++++++- 3 files changed, 188 insertions(+), 35 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java index a71b4b320ab..5134b64caf8 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java @@ -128,14 +128,8 @@ public final class Module implements AnnotatedElement { Version version = descriptor.version().orElse(null); String vs = Objects.toString(version, null); String loc = Objects.toString(uri, null); - Set packages = descriptor.packages(); - int n = packages.size(); - String[] array = new String[n]; - int i = 0; - for (String pn : packages) { - array[i++] = pn.replace('.', '/'); - } - defineModule0(this, isOpen, vs, loc, array); + String[] packages = descriptor.packages().toArray(new String[0]); + defineModule0(this, isOpen, vs, loc, packages); } @@ -789,13 +783,12 @@ public final class Module implements AnnotatedElement { // update VM first, just in case it fails if (syncVM) { - String pkgInternalForm = pn.replace('.', '/'); if (other == EVERYONE_MODULE) { - addExportsToAll0(this, pkgInternalForm); + addExportsToAll0(this, pn); } else if (other == ALL_UNNAMED_MODULE) { - addExportsToAllUnnamed0(this, pkgInternalForm); + addExportsToAllUnnamed0(this, pn); } else { - addExports0(this, pkgInternalForm, other); + addExports0(this, pn, other); } } @@ -1021,7 +1014,7 @@ public final class Module implements AnnotatedElement { // update VM first, just in case it fails if (syncVM) - addPackage0(this, pn.replace('.', '/')); + addPackage0(this, pn); // replace with new set this.extraPackages = extraPackages; // volatile write @@ -1180,8 +1173,7 @@ public final class Module implements AnnotatedElement { if (descriptor.isOpen()) { assert descriptor.opens().isEmpty(); for (String source : descriptor.packages()) { - String sourceInternalForm = source.replace('.', '/'); - addExportsToAll0(m, sourceInternalForm); + addExportsToAll0(m, source); } return; } @@ -1192,7 +1184,6 @@ public final class Module implements AnnotatedElement { // process the open packages first for (Opens opens : descriptor.opens()) { String source = opens.source(); - String sourceInternalForm = source.replace('.', '/'); if (opens.isQualified()) { // qualified opens @@ -1201,7 +1192,7 @@ public final class Module implements AnnotatedElement { // only open to modules that are in this configuration Module m2 = nameToModule.get(target); if (m2 != null) { - addExports0(m, sourceInternalForm, m2); + addExports0(m, source, m2); targets.add(m2); } } @@ -1210,7 +1201,7 @@ public final class Module implements AnnotatedElement { } } else { // unqualified opens - addExportsToAll0(m, sourceInternalForm); + addExportsToAll0(m, source); openPackages.put(source, EVERYONE_SET); } } @@ -1218,7 +1209,6 @@ public final class Module implements AnnotatedElement { // next the exports, skipping exports when the package is open for (Exports exports : descriptor.exports()) { String source = exports.source(); - String sourceInternalForm = source.replace('.', '/'); // skip export if package is already open to everyone Set openToTargets = openPackages.get(source); @@ -1234,7 +1224,7 @@ public final class Module implements AnnotatedElement { if (m2 != null) { // skip qualified export if already open to m2 if (openToTargets == null || !openToTargets.contains(m2)) { - addExports0(m, sourceInternalForm, m2); + addExports0(m, source, m2); targets.add(m2); } } @@ -1245,7 +1235,7 @@ public final class Module implements AnnotatedElement { } else { // unqualified exports - addExportsToAll0(m, sourceInternalForm); + addExportsToAll0(m, source); exportedPackages.put(source, EVERYONE_SET); } } diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 848fe83d240..c90a557de8b 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -401,30 +401,67 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, * Module support funcions */ +/* + * Define a module with the specified packages and bind the module to the + * given class loader. + * module: module to define + * is_open: specifies if module is open (currently ignored) + * version: the module version + * location: the module location + * packages: list of packages in the module + * num_packages: number of packages in the module + */ JNIEXPORT void JNICALL JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version, - jstring location, jobjectArray packages); + jstring location, const char* const* packages, jsize num_packages); +/* + * Set the boot loader's unnamed module. + * module: boot loader's unnamed module + */ JNIEXPORT void JNICALL JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); +/* + * Do a qualified export of a package. + * from_module: module containing the package to export + * package: name of the package to export + * to_module: module to export the package to + */ JNIEXPORT void JNICALL -JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject to_module); +JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module); +/* + * Do an export of a package to all unnamed modules. + * from_module: module containing the package to export + * package: name of the package to export to all unnamed modules + */ JNIEXPORT void JNICALL -JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); +JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package); +/* + * Do an unqualified export of a package. + * from_module: module containing the package to export + * package: name of the package to export + */ JNIEXPORT void JNICALL -JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); +JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package); +/* + * Add a module to the list of modules that a given module can read. + * from_module: module requesting read access + * source_module: module that from_module wants to read + */ JNIEXPORT void JNICALL -JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); +JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module); +/* + * Add a package to a module. + * module: module that will contain the package + * package: package to add to the module + */ JNIEXPORT void JNICALL -JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); - -JNIEXPORT jobject JNICALL -JVM_GetModuleByPackageName(JNIEnv *env, jobject cl, jstring pkg); +JVM_AddModulePackage(JNIEnv* env, jobject module, const char* package); /* * Reflection support functions diff --git a/jdk/src/java.base/share/native/libjava/Module.c b/jdk/src/java.base/share/native/libjava/Module.c index cb6057a5f86..26067555a33 100644 --- a/jdk/src/java.base/share/native/libjava/Module.c +++ b/jdk/src/java.base/share/native/libjava/Module.c @@ -22,18 +22,88 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +#include +#include #include "jni.h" +#include "jni_util.h" #include "jvm.h" #include "java_lang_reflect_Module.h" +/* + * Gets the UTF-8 chars for the string and translates '.' to '/'. Does no + * further validation, assumption being that both calling code in + * java.lang.reflect.Module and VM will do deeper validation. + */ +static char* +GetInternalPackageName(JNIEnv *env, jstring pkg, char* buf, jsize buf_size) +{ + jsize len; + jsize unicode_len; + char* p; + char* utf_str; + + len = (*env)->GetStringUTFLength(env, pkg); + unicode_len = (*env)->GetStringLength(env, pkg); + if (len >= buf_size) { + utf_str = malloc(len + 1); + if (utf_str == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + return NULL; + } + } else { + utf_str = buf; + } + (*env)->GetStringUTFRegion(env, pkg, 0, unicode_len, utf_str); + + p = utf_str; + while (*p != '\0') { + if (*p == '.') { + *p = '/'; + } + p++; + } + return utf_str; +} + JNIEXPORT void JNICALL Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module, jboolean is_open, jstring version, jstring location, jobjectArray packages) { - JVM_DefineModule(env, module, is_open, version, location, packages); + char** pkgs = NULL; + jsize idx; + jsize num_packages = (*env)->GetArrayLength(env, packages); + + if (num_packages != 0 && (pkgs = calloc(num_packages, sizeof(char*))) == NULL) { + JNU_ThrowOutOfMemoryError(env, NULL); + return; + } else { + int valid = 1; + for (idx = 0; idx < num_packages; idx++) { + jstring pkg = (*env)->GetObjectArrayElement(env, packages, idx); + pkgs[idx] = GetInternalPackageName(env, pkg, NULL, 0); + if (pkgs[idx] == NULL) { + valid = 0; + break; + } + } + + if (valid != 0) { + JVM_DefineModule(env, module, is_open, version, location, + (const char* const*)pkgs, num_packages); + } + } + + if (num_packages > 0) { + for (idx = 0; idx < num_packages; idx++) { + if (pkgs[idx] != NULL) { + free(pkgs[idx]); + } + } + free(pkgs); + } } JNIEXPORT void JNICALL @@ -46,25 +116,81 @@ JNIEXPORT void JNICALL Java_java_lang_reflect_Module_addExports0(JNIEnv *env, jclass cls, jobject from, jstring pkg, jobject to) { - JVM_AddModuleExports(env, from, pkg, to); + char buf[128]; + char* pkg_name; + + if (pkg == NULL) { + JNU_ThrowNullPointerException(env, "package is null"); + return; + } + + pkg_name = GetInternalPackageName(env, pkg, buf, (jsize)sizeof(buf)); + if (pkg_name != NULL) { + JVM_AddModuleExports(env, from, pkg_name, to); + if (pkg_name != buf) { + free(pkg_name); + } + } } JNIEXPORT void JNICALL Java_java_lang_reflect_Module_addExportsToAll0(JNIEnv *env, jclass cls, jobject from, jstring pkg) { - JVM_AddModuleExportsToAll(env, from, pkg); + char buf[128]; + char* pkg_name; + + if (pkg == NULL) { + JNU_ThrowNullPointerException(env, "package is null"); + return; + } + + pkg_name = GetInternalPackageName(env, pkg, buf, (jsize)sizeof(buf)); + if (pkg_name != NULL) { + JVM_AddModuleExportsToAll(env, from, pkg_name); + if (pkg_name != buf) { + free(pkg_name); + } + } } JNIEXPORT void JNICALL Java_java_lang_reflect_Module_addExportsToAllUnnamed0(JNIEnv *env, jclass cls, jobject from, jstring pkg) { - JVM_AddModuleExportsToAllUnnamed(env, from, pkg); + char buf[128]; + char* pkg_name; + + if (pkg == NULL) { + JNU_ThrowNullPointerException(env, "package is null"); + return; + } + + pkg_name = GetInternalPackageName(env, pkg, buf, (jsize)sizeof(buf)); + if (pkg_name != NULL) { + JVM_AddModuleExportsToAllUnnamed(env, from, pkg_name); + if (pkg_name != buf) { + free(pkg_name); + } + } } JNIEXPORT void JNICALL Java_java_lang_reflect_Module_addPackage0(JNIEnv *env, jclass cls, jobject m, jstring pkg) { - JVM_AddModulePackage(env, m, pkg); + char buf[128]; + char* pkg_name; + + if (pkg == NULL) { + JNU_ThrowNullPointerException(env, "package is null"); + return; + } + + pkg_name = GetInternalPackageName(env, pkg, buf, (jsize)sizeof(buf)); + if (pkg_name != NULL) { + JVM_AddModulePackage(env, m, pkg_name); + if (pkg_name != buf) { + free(pkg_name); + } + } }