# HG changeset patch # User redestad # Date 1484085379 -3600 # Tue Jan 10 22:56:19 2017 +0100 # Node ID 81111f1f87f44ffe963a7c4446aa8e9e928e97ec # Parent 44454471f7e7673258a5f05a4306359f53e993ab 8171855: Move package name transformations during module bootstrap into native code Reviewed-by: alanb, acorn, lfoltan, mchung, plevart, hseigel, sspitsyn diff --git a/src/java.base/share/classes/java/lang/reflect/Module.java b/src/java.base/share/classes/java/lang/reflect/Module.java --- a/src/java.base/share/classes/java/lang/reflect/Module.java +++ b/src/java.base/share/classes/java/lang/reflect/Module.java @@ -128,14 +128,8 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ } } else { // unqualified opens - addExportsToAll0(m, sourceInternalForm); + addExportsToAll0(m, source); openPackages.put(source, EVERYONE_SET); } } @@ -1218,7 +1209,6 @@ // 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 @@ 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 @@ } else { // unqualified exports - addExportsToAll0(m, sourceInternalForm); + addExportsToAll0(m, source); exportedPackages.put(source, EVERYONE_SET); } } diff --git a/src/java.base/share/native/include/jvm.h b/src/java.base/share/native/include/jvm.h --- a/src/java.base/share/native/include/jvm.h +++ b/src/java.base/share/native/include/jvm.h @@ -401,30 +401,67 @@ * 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/src/java.base/share/native/libjava/Module.c b/src/java.base/share/native/libjava/Module.c --- a/src/java.base/share/native/libjava/Module.c +++ b/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 @@ 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); + } + } }