OpenJDK / jigsaw / jake / hotspot
changeset 9739:94ae06d1ae14
Merge
line wrap: on
line diff
--- a/.jcheck/conf Sun Nov 29 11:00:00 2015 -0800 +++ b/.jcheck/conf Mon Nov 30 14:57:39 2015 -0800 @@ -1,1 +1,4 @@ project=jdk9 +comments=lax +tags=lax +bugids=dup
--- a/make/bsd/makefiles/mapfile-vers-darwin-debug Sun Nov 29 11:00:00 2015 -0800 +++ b/make/bsd/makefiles/mapfile-vers-darwin-debug Mon Nov 30 14:57:39 2015 -0800 @@ -26,7 +26,6 @@ # Define public interface. _JVM_handle_bsd_signal - # miscellaneous functions _jio_fprintf _jio_printf _jio_snprintf
--- a/make/gensrc/Gensrc-jdk.vm.ci.gmk Sun Nov 29 11:00:00 2015 -0800 +++ b/make/gensrc/Gensrc-jdk.vm.ci.gmk Mon Nov 30 14:57:39 2015 -0800 @@ -77,6 +77,7 @@ $(MKDIR) -p $(@D) $(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files)) $(JAVA_SMALL) $(NEW_JAVAC) \ + $(BOOT_JDK_SOURCETARGET) \ -XDignore.symbol.file \ -sourcepath $(SOURCEPATH) \ -implicit:none \
--- a/make/share/makefiles/mapfile-vers Sun Nov 29 11:00:00 2015 -0800 +++ b/make/share/makefiles/mapfile-vers Mon Nov 30 14:57:39 2015 -0800 @@ -160,3 +160,14 @@ JVM_TotalMemory; JVM_UnloadLibrary; JVM_Yield; + + # Module related API's + JVM_AddModuleExports; + JVM_AddModuleExportsToAll; + JVM_AddModuleExportsToAllUnnamed; + JVM_AddModulePackage; + JVM_AddReadsModule; + JVM_CanReadModule; + JVM_DefineModule; + JVM_IsExportedToModule; + JVM_SetBootLoaderUnnamedModule;
--- a/make/solaris/makefiles/mapfile-vers Sun Nov 29 11:00:00 2015 -0800 +++ b/make/solaris/makefiles/mapfile-vers Mon Nov 30 14:57:39 2015 -0800 @@ -35,6 +35,7 @@ jio_vfprintf; jio_vsnprintf; + # Needed because there is no JVM interface for this. sysThreadAvailableStackWithSlack;
--- a/make/test/JtregNative.gmk Sun Nov 29 11:00:00 2015 -0800 +++ b/make/test/JtregNative.gmk Mon Nov 30 14:57:39 2015 -0800 @@ -45,6 +45,7 @@ $(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ + $(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ #
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.vm.ci/share/classes/module-info.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module jdk.vm.ci { + uses jdk.vm.ci.options.OptionDescriptors; + uses jdk.vm.ci.hotspot.HotSpotVMEventListener; + uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; + uses jdk.vm.ci.runtime.JVMCICompilerFactory; + + provides jdk.vm.ci.options.OptionDescriptors with + jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider_OptionDescriptors; + provides jdk.vm.ci.options.OptionDescriptors with + jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod_OptionDescriptors; + provides jdk.vm.ci.options.OptionDescriptors with + jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl_OptionDescriptors; + + + provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory; + provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory; +} +
--- a/src/os/posix/dtrace/hotspot_jni.d Sun Nov 29 11:00:00 2015 -0800 +++ b/src/os/posix/dtrace/hotspot_jni.d Mon Nov 30 14:57:39 2015 -0800 @@ -300,6 +300,8 @@ probe GetLongField__return(uintptr_t); probe GetMethodID__entry(void*, void*, const char*, const char*); probe GetMethodID__return(uintptr_t); + probe GetModule__entry(void*, void*); + probe GetModule__return(void*); probe GetObjectArrayElement__entry(void*, void*, uintptr_t); probe GetObjectArrayElement__return(void*); probe GetObjectClass__entry(void*, void*);
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -3083,7 +3083,7 @@ LIR_Opr klass = new_pointer_register(); __ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), klass_pointer_type), klass, info); LIR_Opr id = new_register(T_LONG); - ByteSize offset = TRACE_ID_OFFSET; + ByteSize offset = TRACE_KLASS_TRACE_ID_OFFSET; LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG); __ move(trace_id_addr, id); __ logical_or(id, LIR_OprFact::longConst(0x01l), id);
--- a/src/share/vm/c1/c1_Runtime1.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/c1/c1_Runtime1.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -655,7 +655,7 @@ NOT_PRODUCT(_throw_class_cast_exception_count++;) ResourceMark rm(thread); char* message = SharedRuntime::generate_class_cast_message( - thread, object->klass()->external_name()); + thread, object->klass()); SharedRuntime::throw_and_post_jvmti_exception( thread, vmSymbols::java_lang_ClassCastException(), message); JRT_END
--- a/src/share/vm/ci/ciEnv.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/ci/ciEnv.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -371,9 +371,9 @@ resolved_klass = ObjArrayKlass::cast(resolved_klass)->bottom_klass(); } if (resolved_klass->is_instance_klass()) { - return Reflection::verify_class_access(accessing_klass->get_Klass(), - resolved_klass, - true); + return (Reflection::verify_class_access(accessing_klass->get_Klass(), + resolved_klass, + true) == Reflection::ACCESS_OK); } return true; }
--- a/src/share/vm/classfile/classFileParser.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classFileParser.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -28,6 +28,7 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/defaultMethods.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verificationType.hpp" @@ -3758,6 +3759,7 @@ // Timing assert(THREAD->is_Java_thread(), "must be a JavaThread"); JavaThread* jt = (JavaThread*) THREAD; + bool cf_changed_in_CFLH = false; PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(), ClassLoader::perf_class_parse_selftime(), @@ -3797,6 +3799,7 @@ // class file data. cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source()); set_stream(cfs); + cf_changed_in_CFLH = true; } } @@ -4148,6 +4151,17 @@ this_klass->set_host_klass(host_klass()); } + // After the majority of the set up for this_klass has occurred, + // set its PackageEntry. Critical to be done after set_name + // and set_host_klass in order to handle anonymous classes + // properly. + oop cl = this_klass->is_anonymous() ? this_klass->host_klass()->class_loader() : + this_klass->class_loader(); + + Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl)); + ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh()); + this_klass->set_package(this_klass->name(), cld, CHECK_NULL); + // Set up Method*::intrinsic_id as soon as we know the names of methods. // (We used to do this lazily, but now we query it in Rewriter, // which is eagerly done for every method, so we might as well do it now, @@ -4285,8 +4299,20 @@ } } + // Obtain this_klass' module entry + ModuleEntry* module_entry = this_klass->module(); + assert(module_entry != NULL, "module_entry should always be set"); + + // Obtain j.l.r.Module + oop module_jlrM = (oop)NULL; + if (module_entry->is_named() && + module_entry->jlrM_module() != NULL) { + module_jlrM = JNIHandles::resolve(module_entry->jlrM_module()); + } + Handle jlrM_handle(THREAD, module_jlrM); + // Allocate mirror and initialize static fields - java_lang_Class::create_mirror(this_klass, class_loader, protection_domain, + java_lang_Class::create_mirror(this_klass, class_loader, jlrM_handle, protection_domain, CHECK_(nullHandle)); // Generate any default methods - default methods are interface methods @@ -4296,6 +4322,11 @@ this_klass(), &all_mirandas, CHECK_(nullHandle)); } + // Add read edges to the unnamed modules of the bootstrap and app class loaders. + if (cf_changed_in_CFLH && !jlrM_handle.is_null() && module_entry->is_named()) { + JvmtiExport::add_default_read_edges(jlrM_handle, THREAD); + } + // Update the loader_data graph. record_defined_class_dependencies(this_klass, CHECK_NULL); @@ -4306,8 +4337,18 @@ ResourceMark rm; // print in a single call to reduce interleaving of output if (cfs->source() != NULL) { - tty->print("[Loaded %s from %s]\n", this_klass->external_name(), - cfs->source()); + static const size_t boot_image_name_len = strlen(BOOT_IMAGE_NAME); + size_t cfs_len = strlen(cfs->source()); + // See if cfs->source() ends in "bootmodules.jimage" + if (module_entry->is_named() && boot_image_name_len < cfs_len && + (strncmp(cfs->source() + cfs_len - boot_image_name_len, + BOOT_IMAGE_NAME, boot_image_name_len) == 0)) { + tty->print_cr("[Loaded %s from jrt:/%s]", this_klass->external_name(), + module_entry->name()->as_C_string()); + } else { + tty->print("[Loaded %s from %s]\n", this_klass->external_name(), + cfs->source()); + } } else if (class_loader.is_null()) { Klass* caller = THREAD->is_Java_thread() @@ -4680,17 +4721,29 @@ void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) { Klass* super = this_klass->super(); - if ((super != NULL) && - (!Reflection::verify_class_access(this_klass(), super, false))) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s cannot access its superclass %s", - this_klass->external_name(), - super->external_name() - ); - return; + if (super != NULL) { + Reflection::VerifyClassAccessResults vca_result = + Reflection::verify_class_access(this_klass(), super, false); + if (vca_result != Reflection::ACCESS_OK) { + ResourceMark rm(THREAD); + char* msg = Reflection::verify_class_access_msg(this_klass(), super, vca_result); + if (msg == NULL) { + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "class %s cannot access its superclass %s", + this_klass->external_name(), + InstanceKlass::cast(super)->external_name()); + } else { + // Add additional message content. + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "superclass access check failed: %s", + msg); + } + return; + } } } @@ -4701,15 +4754,26 @@ for (int i = lng - 1; i >= 0; i--) { Klass* k = local_interfaces->at(i); assert (k != NULL && k->is_interface(), "invalid interface"); - if (!Reflection::verify_class_access(this_klass(), k, false)) { + Reflection::VerifyClassAccessResults vca_result = + Reflection::verify_class_access(this_klass(), k, false); + if (vca_result != Reflection::ACCESS_OK) { ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s cannot access its superinterface %s", - this_klass->external_name(), - k->external_name() - ); + char* msg = Reflection::verify_class_access_msg(this_klass(), k, vca_result); + if (msg == NULL) { + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "class %s cannot access its superinterface %s", + this_klass->external_name(), + k->external_name()); + } else { + // Add additional message content. + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "superinterface check failed: %s", + msg); + } return; } } @@ -4808,12 +4872,13 @@ const bool is_super = (flags & JVM_ACC_SUPER) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; + const bool is_module_info= (flags & JVM_ACC_MODULE) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; if ((is_abstract && is_final) || (is_interface && !is_abstract) || (is_interface && major_gte_15 && (is_super || is_enum)) || - (!is_interface && major_gte_15 && is_annotation)) { + (!is_interface && major_gte_15 && is_annotation) || is_module_info) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, @@ -4964,65 +5029,9 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) { assert(_need_verify, "only called when _need_verify is true"); - int i = 0; - int count = length >> 2; - for (int k=0; k<count; k++) { - unsigned char b0 = buffer[i]; - unsigned char b1 = buffer[i+1]; - unsigned char b2 = buffer[i+2]; - unsigned char b3 = buffer[i+3]; - // For an unsigned char v, - // (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128; - // (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128. - unsigned char res = b0 | b0 - 1 | - b1 | b1 - 1 | - b2 | b2 - 1 | - b3 | b3 - 1; - if (res >= 128) break; - i += 4; + if (!UTF8::is_legal_utf8(buffer, length, _major_version <= 47)) { + classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); } - for(; i < length; i++) { - unsigned short c; - // no embedded zeros - guarantee_property((buffer[i] != 0), "Illegal UTF8 string in constant pool in class file %s", CHECK); - if(buffer[i] < 128) { - continue; - } - if ((i + 5) < length) { // see if it's legal supplementary character - if (UTF8::is_supplementary_character(&buffer[i])) { - c = UTF8::get_supplementary_character(&buffer[i]); - i += 5; - continue; - } - } - switch (buffer[i] >> 4) { - default: break; - case 0x8: case 0x9: case 0xA: case 0xB: case 0xF: - classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); - case 0xC: case 0xD: // 110xxxxx 10xxxxxx - c = (buffer[i] & 0x1F) << 6; - i++; - if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) { - c += buffer[i] & 0x3F; - if (_major_version <= 47 || c == 0 || c >= 0x80) { - // for classes with major > 47, c must a null or a character in its shortest form - break; - } - } - classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); - case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx - c = (buffer[i] & 0xF) << 12; - i += 2; - if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) { - c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F); - if (_major_version <= 47 || c >= 0x800) { - // for classes with major > 47, c must be in its shortest form - break; - } - } - classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); - } // end of switch - } // end of for } // Checks if name is a legal class name. @@ -5214,6 +5223,8 @@ // or <clinit>. Note that method names may not be <init> or <clinit> in this // method. Because these names have been checked as special cases before // calling this method in verify_legal_method_name. +// +// This method is also called from jvm.cpp. Be careful about changing it. bool ClassFileParser::verify_unqualified_name( char* name, unsigned int length, int type) { jchar ch; @@ -5221,8 +5232,15 @@ for (char* p = name; p != name + length; ) { ch = *p; if (ch < 128) { - p++; - if (ch == '.' || ch == ';' || ch == '[' ) { + if (ch == '.') { + // permit '.' in module names unless it's the first char, or + // preceding char is also a '.', or last char is a '.'. + if ((type != LegalModule) || (p == name) || (*(p-1) == '.') || + (p == name + length - 1)) { + return false; + } + } + if (ch == ';' || ch == '[' ) { return false; // do not permit '.', ';', or '[' } if (type != LegalClass && ch == '/') { @@ -5231,6 +5249,7 @@ if (type == LegalMethod && (ch == '<' || ch == '>')) { return false; // do not permit '<' or '>' in method names } + p++; } else { char* tmp_p = UTF8::next(p, &ch); p = tmp_p;
--- a/src/share/vm/classfile/classFileParser.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classFileParser.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -206,8 +206,10 @@ ClassFileStream* _stream; // Actual input stream - enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names + public: + enum { LegalClass, LegalField, LegalMethod, LegalModule }; // used to verify unqualified names + private: // Accessors ClassFileStream* stream() { return _stream; } void set_stream(ClassFileStream* st) { _stream = st; } @@ -380,7 +382,7 @@ void verify_legal_class_modifiers(jint flags, TRAPS); void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS); void verify_legal_method_modifiers(jint flags, bool is_interface, Symbol* name, TRAPS); - bool verify_unqualified_name(char* name, unsigned int length, int type); + char* skip_over_field_name(char* name, bool slash_ok, unsigned int length); char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS); @@ -484,6 +486,7 @@ static void check_super_interface_access(instanceKlassHandle this_klass, TRAPS); static void check_final_method_override(instanceKlassHandle this_klass, TRAPS); static void check_illegal_static_method(instanceKlassHandle this_klass, TRAPS); + static bool verify_unqualified_name(char* name, unsigned int length, int type); }; #endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
--- a/src/share/vm/classfile/classLoader.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classLoader.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,9 @@ #include "classfile/classLoaderExt.hpp" #include "classfile/javaClasses.hpp" #include "classfile/jimage.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "compiler/compileBroker.hpp" @@ -133,12 +136,19 @@ PerfCounter* ClassLoader::_isUnsyncloadClass = NULL; PerfCounter* ClassLoader::_load_instance_class_failCounter = NULL; -ClassPathEntry* ClassLoader::_first_entry = NULL; -ClassPathEntry* ClassLoader::_last_entry = NULL; -int ClassLoader::_num_entries = 0; +ClassPathEntry* ClassLoader::_first_entry = NULL; +ClassPathEntry* ClassLoader::_last_entry = NULL; +int ClassLoader::_num_entries = 0; +ClassPathEntry* ClassLoader::_first_append_entry = NULL; PackageHashtable* ClassLoader::_package_hash_table = NULL; +bool ClassLoader::_has_bootmodules_jimage = false; +GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL; +GrowableArray<char*>* ClassLoader::_ext_modules_array = NULL; #if INCLUDE_CDS +// The _last_append_entry is only set when DumpSharedSpaces is true and there are +// append path entries. +ClassPathEntry* ClassLoader::_last_append_entry = NULL; SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; #endif // helper routines @@ -160,7 +170,7 @@ return (const char*)version_string; } -bool string_ends_with(const char* str, const char* str_to_find) { +bool ClassLoader::string_ends_with(const char* str, const char* str_to_find) { size_t str_len = strlen(str); size_t str_to_find_len = strlen(str_to_find); if (str_to_find_len > str_len) { @@ -169,7 +179,6 @@ return (strncmp(str + (str_len - str_to_find_len), str_to_find, str_to_find_len) == 0); } - ClassPathEntry::ClassPathEntry() { set_next(NULL); } @@ -351,12 +360,47 @@ if (location == 0) { char package[JIMAGE_MAX_PATH]; name_to_package(name, package, JIMAGE_MAX_PATH); + +#if INCLUDE_CDS + if (package[0] == '\0' && DumpSharedSpaces) { + return NULL; + } +#endif if (package[0] != '\0') { - const char* module = (*JImagePackageToModule)(_jimage, package); - if (module == NULL) { - module = "java.base"; + if (!Universe::is_module_initialized()) { + location = (*JImageFindResource)(_jimage, "java.base", get_jimage_version_string(), name, &size); +#if INCLUDE_CDS + // CDS uses the boot class loader to load classes whose packages are in + // modules defined for other class loaders. So, for now, get their module + // names from the .jimage file. + if (DumpSharedSpaces && location == 0) { + const char* module_name = (*JImagePackageToModule)(_jimage, package); + if (module_name != NULL) { + location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size); + } } - location = (*JImageFindResource)(_jimage, module, get_jimage_version_string(), name, &size); +#endif + + } else { + // Get boot class loader's package entry table + PackageEntryTable* pkgEntryTable = + ClassLoaderData::the_null_class_loader_data()->packages(); + // Get package's package entry + TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package, CHECK_NULL); + PackageEntry* package_entry = pkgEntryTable->lookup_only(pkg_symbol); + + if (package_entry != NULL) { + ResourceMark rm; + // Get the module name + ModuleEntry* module = package_entry->module(); + assert(module != NULL, "Boot classLoader package missing module"); + assert(module->is_named(), "Boot classLoader package is in unnamed module"); + const char* module_name = module->name()->as_C_string(); + if (module_name != NULL) { + location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size); + } + } + } } } @@ -400,11 +444,11 @@ } } } +#endif bool ClassPathImageEntry::is_jrt() { - return string_ends_with(name(), BOOT_IMAGE_NAME); + return ClassLoader::is_jrt(name()); } -#endif #if INCLUDE_CDS void ClassLoader::exit_with_path_failure(const char* error, const char* message) { @@ -473,7 +517,7 @@ _shared_paths_misc_info->add_boot_classpath(sys_class_path); } #endif - setup_search_path(sys_class_path); + setup_search_path(sys_class_path, true); } #if INCLUDE_CDS @@ -493,10 +537,11 @@ } #endif -void ClassLoader::setup_search_path(const char *class_path) { +void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_search) { int offset = 0; int len = (int)strlen(class_path); int end = 0; + bool mark_append_entry = false; // Iterate over class path entries for (int start = 0; start < len; start = end) { @@ -505,10 +550,24 @@ } EXCEPTION_MARK; ResourceMark rm(THREAD); + mark_append_entry = (mark_append_entry || + (bootstrap_search && (start == Arguments::bootclassloader_append_index()))); + char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); strncpy(path, &class_path[start], end - start); path[end - start] = '\0'; - update_class_path_entry_list(path, false); + update_class_path_entry_list(path, false, mark_append_entry, false); + + // Check on the state of the boot loader's append path + if (mark_append_entry && (_first_append_entry == NULL)) { + // Failure to mark the first append entry, most likely + // due to a non-existent path. Record the next entry + // as the first boot loader append entry. + mark_append_entry = true; + } else { + mark_append_entry = false; + } + #if INCLUDE_CDS if (DumpSharedSpaces) { check_shared_classpath(path); @@ -518,6 +577,16 @@ end++; } } + +#if INCLUDE_CDS + // Mark the last entry corresponding to the -Xbootclasspath/a + if (DumpSharedSpaces) { + if (_first_append_entry != NULL && bootstrap_search) { + assert(_last_append_entry == NULL, "The _last_append_entry is already set"); + _last_append_entry = _last_entry; + } + } +#endif } ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st, @@ -612,6 +681,18 @@ return NULL; } +// The boot class loader must adhere to specfic visibility rules. +// Prior to loading a class in a named package, the package is checked +// to see if it is in a module defined to the boot loader. If the +// package is not in a module defined to the boot loader, the class +// must be loaded only in the boot loader's append path, which +// consists of [-Xbootclasspath/a]; [jvmti appended entries] +void ClassLoader::set_first_append_entry(ClassPathEntry *new_entry) { + if (_first_append_entry == NULL) { + _first_append_entry = new_entry; + } +} + // returns true if entry already on class path bool ClassLoader::contains_entry(ClassPathEntry *entry) { ClassPathEntry* e = _first_entry; @@ -637,25 +718,57 @@ _num_entries ++; } +void ClassLoader::prepend_to_list(ClassPathEntry *new_entry) { + if (new_entry != NULL) { + if (_last_entry == NULL) { + _first_entry = _last_entry = new_entry; + } else { + new_entry->set_next(_first_entry); + _first_entry = new_entry; + } + } + _num_entries ++; +} + +void ClassLoader::add_to_list(const char *apath) { + update_class_path_entry_list((char*)apath, false, false, false); +} + +void ClassLoader::prepend_to_list(const char *apath) { + update_class_path_entry_list((char*)apath, false, false, true); +} + // Returns true IFF the file/dir exists and the entry was successfully created. bool ClassLoader::update_class_path_entry_list(const char *path, bool check_for_duplicates, + bool mark_append_entry, + bool prepend_entry, bool throw_exception) { struct stat st; if (os::stat(path, &st) == 0) { // File or directory found ClassPathEntry* new_entry = NULL; Thread* THREAD = Thread::current(); + new_entry = create_class_path_entry(path, &st, throw_exception, CHECK_(false)); if (new_entry == NULL) { return false; } + + // Ensure that the first boot loader append entry will always be set correctly. + assert((!mark_append_entry || + (mark_append_entry && (!check_for_duplicates || !contains_entry(new_entry)))), + "failed to mark boot loader's first append boundary"); + // The kernel VM adds dynamically to the end of the classloader path and // doesn't reorder the bootclasspath which would break java.lang.Package // (see PackageInfo). // Add new entry to linked list if (!check_for_duplicates || !contains_entry(new_entry)) { - ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry); + ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry, prepend_entry); + if (mark_append_entry) { + set_first_append_entry(new_entry); + } } return true; } else { @@ -756,6 +869,76 @@ return (*Crc32)(crc, (const jbyte*)buf, len); } +void ClassLoader::initialize_module_loader_map(JImageFile* jimage) { + jlong size; + JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", get_jimage_version_string(), MODULE_LOADER_MAP, &size); + if (location == 0) { + vm_exit_during_initialization( + "Cannot find ModuleLoaderMap location from bootmodules.jimage.", NULL); + } + char* buffer = NEW_RESOURCE_ARRAY(char, size); + jlong read = (*JImageGetResource)(jimage, location, buffer, size); + if (read != size) { + vm_exit_during_initialization( + "Cannot find ModuleLoaderMap resource from bootmodules.jimage.", NULL); + } + char* char_buf = (char*)buffer; + int buflen = (int)strlen(char_buf); + char* begin_ptr = char_buf; + char* end_ptr = strchr(begin_ptr, '\n'); + bool process_boot_modules = false; + _boot_modules_array = new (ResourceObj::C_HEAP, mtInternal) + GrowableArray<char*>(INITIAL_BOOT_MODULES_ARRAY_SIZE, true); + _ext_modules_array = new (ResourceObj::C_HEAP, mtInternal) + GrowableArray<char*>(INITIAL_EXT_MODULES_ARRAY_SIZE, true); + while (end_ptr != NULL && (end_ptr - char_buf) < buflen) { + // Allocate a buffer from the C heap to be appended to the _boot_modules_array + // or the _ext_modules_array. + char* temp_name = NEW_C_HEAP_ARRAY(char, (size_t)(end_ptr - begin_ptr + 1), mtInternal); + strncpy(temp_name, begin_ptr, end_ptr - begin_ptr); + temp_name[end_ptr - begin_ptr] = '\0'; + if (strncmp(temp_name, "BOOT", 4) == 0) { + process_boot_modules = true; + FREE_C_HEAP_ARRAY(char, temp_name); + } else if (strncmp(temp_name, "EXT", 3) == 0) { + process_boot_modules = false; + FREE_C_HEAP_ARRAY(char, temp_name); + } else { + // module name + if (process_boot_modules) { + _boot_modules_array->append(temp_name); + } else { + _ext_modules_array->append(temp_name); + } + } + begin_ptr = ++end_ptr; + end_ptr = strchr(begin_ptr, '\n'); + } + FREE_RESOURCE_ARRAY(u1, buffer, size); +} + +jshort ClassLoader::module_to_classloader(const char* module_name) { + + assert(_boot_modules_array != NULL, "_boot_modules_array is NULL"); + assert(_ext_modules_array != NULL, "_ext_modules_array is NULL"); + + int array_size = _boot_modules_array->length(); + for (int i = 0; i < array_size; i++) { + if (strcmp(module_name, _boot_modules_array->at(i)) == 0) { + return BOOT; + } + } + + array_size = _ext_modules_array->length(); + for (int i = 0; i < array_size; i++) { + if (strcmp(module_name, _ext_modules_array->at(i)) == 0) { + return EXT; + } + } + + return APP; +} + // PackageInfo data exists in order to support the java.lang.Package // class. A Package object provides information about a java package // (version, vendor, etc.) which originates in the manifest of the jar @@ -782,6 +965,7 @@ public: const char* _pkgname; // Package name int _classpath_index; // Index of directory or JAR file loaded from + Symbol* _module_location; // Location of module containing the package PackageInfo* next() { return (PackageInfo*)BasicHashtableEntry<mtClass>::next(); @@ -794,9 +978,14 @@ return ClassLoader::classpath_entry(_classpath_index)->name(); } - void set_index(int index) { + void set_location_and_index(Symbol* mod_loc, int index) { + _module_location = mod_loc; + if (_module_location != NULL) + _module_location->increment_refcount(); _classpath_index = index; } + + Symbol* module_location() { return _module_location; } }; @@ -908,12 +1097,20 @@ } #endif -PackageInfo* ClassLoader::lookup_package(const char *pkgname) { - const char *cp = strrchr(pkgname, '/'); - if (cp != NULL) { - // Package prefix found - int n = cp - pkgname + 1; - return _package_hash_table->get_entry(pkgname, n); +PackageInfo* ClassLoader::lookup_package(const char *pkgname, int len) { + return _package_hash_table->get_entry(pkgname, len); +} + +// If a class's package is in a module defined by the boot loader then +// return the module location, else return NULL. +static Symbol* boot_module_location(const char* pkg_name, int len, TRAPS) { + PackageEntryTable* pkg_entry_tbl = + ClassLoaderData::the_null_class_loader_data()->packages(); + TempNewSymbol pkg_symbol = SymbolTable::new_symbol(pkg_name, len, CHECK_NULL); + PackageEntry* pkg_entry = pkg_entry_tbl->lookup_only(pkg_symbol); + + if (pkg_entry != NULL && !pkg_entry->in_unnamed_module()) { + return pkg_entry->module()->location(); } return NULL; } @@ -926,47 +1123,61 @@ { MutexLocker ml(PackageTable_lock, THREAD); // First check for previously loaded entry - PackageInfo* pp = lookup_package(pkgname); - if (pp != NULL) { - // Existing entry found, check source of package - pp->set_index(classpath_index); - return true; - } - const char *cp = strrchr(pkgname, '/'); if (cp != NULL) { // Package prefix found - int n = cp - pkgname + 1; + int len = cp - pkgname + 1; + PackageInfo* pp = lookup_package(pkgname, len); + if (pp != NULL) { + // Existing entry found, check source of package (remove trailing '/') + Symbol* module_location = boot_module_location(pkgname, len - 1, CHECK_false); + pp->set_location_and_index(module_location, classpath_index); + return true; + } - char* new_pkgname = NEW_C_HEAP_ARRAY(char, n + 1, mtClass); + char* new_pkgname = NEW_C_HEAP_ARRAY(char, len + 1, mtClass); if (new_pkgname == NULL) { return false; } - memcpy(new_pkgname, pkgname, n); - new_pkgname[n] = '\0'; - pp = _package_hash_table->new_entry(new_pkgname, n); - pp->set_index(classpath_index); + memcpy(new_pkgname, pkgname, len); + new_pkgname[len] = '\0'; + pp = _package_hash_table->new_entry(new_pkgname, len); + Symbol* module_location = boot_module_location(new_pkgname, len - 1, CHECK_false); + pp->set_location_and_index(module_location, classpath_index); // Insert into hash table _package_hash_table->add_entry(pp); } - return true; } + return true; } oop ClassLoader::get_system_package(const char* name, TRAPS) { - PackageInfo* pp; + PackageInfo* pp = NULL; { MutexLocker ml(PackageTable_lock, THREAD); - pp = lookup_package(name); + const char *cp = strrchr(name, '/'); + if (cp != NULL) { + pp = lookup_package(name, cp - name + 1); + } } if (pp == NULL) { return NULL; } else { - Handle p = java_lang_String::create_from_str(pp->filename(), THREAD); - return p(); + // If the module_location field of the PackageInfo record is not null then + // return the module location. Otherwise, use boot class path index. + Symbol* module_location = pp->module_location(); + if (module_location != NULL) { + ResourceMark rm(THREAD); + Handle ml = java_lang_String::create_from_str( + module_location->as_C_string(), THREAD); + return ml(); + } else { + Handle p = java_lang_String::create_from_str(pp->filename(), THREAD); + return p(); + } } } @@ -996,8 +1207,21 @@ return result(); } +#if INCLUDE_CDS +bool ClassLoader::class_in_append_entries(const char* file_name, TRAPS) { + ClassPathEntry* tmp_e = _first_append_entry; + while ((tmp_e != NULL) && (tmp_e != _last_append_entry->next())) { + ClassFileStream* stream = tmp_e->open_stream(file_name, CHECK_false); + if (stream != NULL) { + return true; + } + tmp_e = tmp_e->next(); + } + return false; +} +#endif -instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) { +instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, bool search_append_only, TRAPS) { ResourceMark rm(THREAD); const char* class_name = h_name->as_C_string(); EventMark m("loading class %s", class_name); @@ -1011,17 +1235,59 @@ const char* file_name = st.as_string(); ClassLoaderExt::Context context(class_name, file_name, THREAD); + instanceKlassHandle h; + + PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), + ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), + PerfClassTraceTime::CLASS_LOAD); +#if INCLUDE_CDS + // Don't archive any class that exists in the append path entries. + if (DumpSharedSpaces && class_in_append_entries(file_name, THREAD)) { + tty->print_cr("Preload Warning: skipping class from -Xbootclasspath/a %s", + class_name); + return h; // NULL + } +#endif + // Lookup stream for parsing .class file ClassFileStream* stream = NULL; int classpath_index = 0; - ClassPathEntry* e = NULL; - instanceKlassHandle h; + + // If DumpSharedSpaces is true, boot loader visibility boundaries are set + // to be _first_entry to the end (all path entries). + // + // If search_append_only is true, boot loader visibility boundaries are + // set to be _fist_append_entry to the end. This includes: + // [-Xbootclasspath/a]; [jvmti appended entries] + // + // If both DumpSharedSpaces and search_append_only are false, boot loader + // visibility boundaries are set to be _first_entry to the entry before + // the _first_append_entry. This would include: + // [-Xpatch:<dirs>]; [exploded build | bootmodules.jimage] + // + // DumpSharedSpaces and search_append_only are mutually exclusive and cannot + // be true at the same time. + ClassPathEntry* e = (search_append_only ? _first_append_entry : _first_entry); + ClassPathEntry* last_e = + (search_append_only || DumpSharedSpaces ? NULL : _first_append_entry); + { - PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), - ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(), - PerfClassTraceTime::CLASS_LOAD); - e = _first_entry; - while (e != NULL) { + if (search_append_only) { + // For the boot loader append path search, must calculate + // the starting classpath_index prior to attempting to + // load the classfile. + ClassPathEntry *tmp_e = _first_entry; + while ((tmp_e != NULL) && (tmp_e != _first_append_entry)) { + tmp_e = tmp_e->next(); + ++classpath_index; + } + } + + // Attempt to load the classfile from either: + // - [-Xpatch:dir]; exploded build | bootmodules.jimage + // or + // - [-Xbootclasspath/a]; [jvmti appended entries] + while ((e != NULL) && (e != last_e)) { stream = e->open_stream(file_name, CHECK_NULL); if (!context.check(stream, classpath_index)) { return h; // NULL @@ -1053,7 +1319,38 @@ } return h; } - h = context.record_result(classpath_index, e, result, THREAD); + + // obtain the classloader type based on the class name. + // First obtain the package name based on the class name. Then obtain + // the classloader type based on the package name from the jimage using + // a jimage API. If the classloader type cannot be found from the + // jimage, it is default to the app classloader type. + jshort classloader_type = ClassLoader::APP; + int length; + const jbyte* pkg_string = InstanceKlass::package_from_name(h_name, length); + TempNewSymbol pkg_name = NULL; + if (pkg_string != NULL) { + ResourceMark rm; + pkg_name = SymbolTable::new_symbol((const char*)pkg_string, length, CHECK_NULL); + const char* pkg_name_C_string = (const char*)(pkg_name->as_C_string()); + ClassPathEntry *cpe = ClassLoader::classpath_entry(0); + while (cpe != NULL) { + ClassPathImageEntry* cpie = (ClassPathImageEntry*)cpe; + char* module_name; + // the cpe == e check is to ensure we are inspecting the correct ClassPathEntry + // from which the class was found + if (cpie->is_jrt() && cpe == e) { + JImageFile* jimage = cpie->jimage(); + module_name = (char*)(*JImagePackageToModule)(jimage, pkg_name_C_string); + if (module_name != NULL) { + classloader_type = ClassLoader::module_to_classloader(module_name); + break; + } + } + cpe = cpe->next(); + } + } + h = context.record_result(classpath_index, classloader_type, e, result, THREAD); } else { if (DumpSharedSpaces) { tty->print_cr("Preload Warning: Cannot find %s", class_name); @@ -1234,6 +1531,46 @@ return true; } + +void ClassLoader::create_javabase() { + Thread* THREAD = Thread::current(); + + // Create java.base's module entry for the boot + // class loader prior to loading j.l.Ojbect. + ClassLoaderData* null_cld = ClassLoaderData::the_null_class_loader_data(); + + // Get module entry table + ModuleEntryTable* null_cld_modules = null_cld->modules(); + if (null_cld_modules == NULL) { + vm_exit_during_initialization("No ModuleEntryTable for the boot class loader"); + } + + { + MutexLocker ml(Module_lock, THREAD); + ModuleEntry* jb_module = null_cld_modules->locked_create_entry_or_null(Handle(NULL), vmSymbols::java_base(), NULL, NULL, null_cld); + if (jb_module == NULL) { + vm_exit_during_initialization("Unable to create ModuleEntry for java.base"); + } + ModuleEntryTable::set_javabase_module(jb_module); + } + + // When looking for the jimage file, only + // search the boot loader's module path which + // can consist of [-Xpatch]; exploded build | bootmodules.jimage + // Do not search the boot loader's append path. + ClassPathEntry* e = _first_entry; + ClassPathEntry* last_e = _first_append_entry; + while ((e != NULL) && (e != last_e)) { + JImageFile *jimage = e->jimage(); + if (jimage != NULL && e->is_jrt()) { + set_has_bootmodules_jimage(true); + ClassLoader::initialize_module_loader_map(jimage); + return; + } + e = e->next(); + } +} + #ifndef PRODUCT void ClassLoader::verify() { @@ -1301,10 +1638,6 @@ tty->cr(); } -bool ClassPathDirEntry::is_jrt() { - return false; -} - void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) { real_jzfile* zip = (real_jzfile*) _zip; tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name); @@ -1326,10 +1659,6 @@ } } -bool ClassPathZipEntry::is_jrt() { - return false; -} - void ClassLoader::compile_the_world() { EXCEPTION_MARK; HandleMark hm(THREAD);
--- a/src/share/vm/classfile/classLoader.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classLoader.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -35,6 +35,13 @@ // Name of boot module image #define BOOT_IMAGE_NAME "bootmodules.jimage" +// Name of the resource containing mapping from module names to defining class loader type +#define MODULE_LOADER_MAP "jdk/internal/module/ModuleLoaderMap.dat" + +// Initial sizes of the following arrays are based on the generated ModuleLoaderMap.dat +#define INITIAL_BOOT_MODULES_ARRAY_SIZE 30 +#define INITIAL_EXT_MODULES_ARRAY_SIZE 15 + // Class path entry (directory or zip file) class JImageFile; @@ -50,6 +57,7 @@ OrderAccess::release_store_ptr(&_next, next); } virtual bool is_jar_file() = 0; + virtual bool is_jrt() = 0; virtual const char* name() = 0; virtual JImageFile* jimage() = 0; // Constructor @@ -59,7 +67,6 @@ virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0; // Debugging NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;) - NOT_PRODUCT(virtual bool is_jrt() = 0;) }; @@ -68,13 +75,13 @@ const char* _dir; // Name of directory public: bool is_jar_file() { return false; } + bool is_jrt() { return false; } const char* name() { return _dir; } JImageFile* jimage() { return NULL; } ClassPathDirEntry(const char* dir); ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_jrt();) }; @@ -98,6 +105,7 @@ const char* _zip_name; // Name of zip archive public: bool is_jar_file() { return true; } + bool is_jrt() { return false; } const char* name() { return _zip_name; } JImageFile* jimage() { return NULL; } ClassPathZipEntry(jzfile* zip, const char* zip_name); @@ -107,7 +115,6 @@ void contents_do(void f(const char* name, void* context), void* context); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_jrt();) }; @@ -118,17 +125,17 @@ const char* _name; public: bool is_jar_file() { return false; } + bool is_jrt(); bool is_open() { return _jimage != NULL; } const char* name() { return _name == NULL ? "" : _name; } JImageFile* jimage() { return _jimage; } ClassPathImageEntry(JImageFile* jimage, const char* name); ~ClassPathImageEntry(); - static void name_to_package(const char* name, char* buffer, int length); + void name_to_package(const char* name, char* package, int length); ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_jrt();) }; class PackageHashtable; @@ -141,6 +148,11 @@ enum SomeConstants { package_hash_table_size = 31 // Number of buckets }; + enum ClassLoaderType { + BOOT = 1, + EXT = 2, + APP = 3 + }; protected: // Performance counters @@ -178,45 +190,69 @@ static PerfCounter* _isUnsyncloadClass; static PerfCounter* _load_instance_class_failCounter; - // First entry in linked list of ClassPathEntry instances + // First entry in linked list of ClassPathEntry instances. + // This consists of entries made up by: + // - boot loader modules + // [-Xpatch]; exploded build | bootmodules.jimage; + // - boot loader append path + // [-Xbootclasspath/a]; [jvmti appended entries] static ClassPathEntry* _first_entry; // Last entry in linked list of ClassPathEntry instances static ClassPathEntry* _last_entry; static int _num_entries; + // Pointer into the linked list of ClassPathEntry instances. + // Marks the start of: + // - the boot loader's append path + // [-Xbootclasspath/a]; [jvmti appended entries] + static ClassPathEntry* _first_append_entry; + // Hash table used to keep track of loaded packages static PackageHashtable* _package_hash_table; static const char* _shared_archive; + // True if the boot path has a bootmodules.jimage + static bool _has_bootmodules_jimage; + + // Array of module names associated with the boot class loader + static GrowableArray<char*>* _boot_modules_array; + + // Array of module names associated with the ext class loader + static GrowableArray<char*>* _ext_modules_array; + // Info used by CDS + CDS_ONLY(static ClassPathEntry* _last_append_entry;) CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;) // Hash function static unsigned int hash(const char *s, int n); // Returns the package file name corresponding to the specified package // or class name, or null if not found. - static PackageInfo* lookup_package(const char *pkgname); + static PackageInfo* lookup_package(const char *pkgname, int len); // Adds a new package entry for the specified class or package name and // corresponding directory or jar file name. static bool add_package(const char *pkgname, int classpath_index, TRAPS); // Initialization static void setup_bootstrap_search_path(); - static void setup_search_path(const char *class_path); + static void setup_search_path(const char *class_path, bool setting_bootstrap); static void load_zip_library(); static void load_jimage_library(); static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, bool throw_exception, TRAPS); + public: // Canonicalizes path names, so strcmp will work properly. This is mainly // to avoid confusing the zip library static bool get_canonical_path(const char* orig, char* out, int len); - public: + static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg); static int crc32(int crc, const char* buf, int len); static bool update_class_path_entry_list(const char *path, bool check_for_duplicates, + bool mark_append_entry, + bool prepend_entry, bool throw_exception=true); static void print_bootclasspath(); @@ -281,8 +317,18 @@ return _load_instance_class_failCounter; } + // Sets _has_bootmodules_jimage to TRUE if bootmodules.jimage file exists + static void set_has_bootmodules_jimage(bool val) { + _has_bootmodules_jimage = val; + } + + static bool has_bootmodules_jimage() { return _has_bootmodules_jimage; } + + // Create the ModuleEntry for java.base + static void create_javabase(); + // Load individual .class file - static instanceKlassHandle load_classfile(Symbol* h_name, TRAPS); + static instanceKlassHandle load_classfile(Symbol* h_name, bool search_append_only, TRAPS); // If the specified package has been loaded by the system, then returns // the name of the directory or ZIP file that the package was loaded from. @@ -326,6 +372,8 @@ static void* get_shared_paths_misc_info(); static bool check_shared_paths_misc_info(void* info, int size); static void exit_with_path_failure(const char* error, const char* message); + + static bool class_in_append_entries(const char* file_name, TRAPS); #endif static void trace_class_path(const char* msg, const char* name = NULL); @@ -339,15 +387,33 @@ static jlong class_link_count(); static jlong class_link_time_ms(); + static void set_first_append_entry(ClassPathEntry* entry); + // indicates if class path already contains a entry (exact match by name) static bool contains_entry(ClassPathEntry* entry); // adds a class path list static void add_to_list(ClassPathEntry* new_entry); + // prepends a class path list + static void prepend_to_list(ClassPathEntry* new_entry); + // creates a class path zip entry (returns NULL if JAR file cannot be opened) static ClassPathZipEntry* create_class_path_zip_entry(const char *apath); + // add a path to class path list + static void add_to_list(const char* apath); + + // prepend a path to class path list + static void prepend_to_list(const char* apath); + + static bool string_ends_with(const char* str, const char* str_to_find); + + static bool is_jrt(const char* name) { return string_ends_with(name, BOOT_IMAGE_NAME); } + + static void initialize_module_loader_map(JImageFile* jimage); + + static jshort module_to_classloader(const char* module_name); // Debugging static void verify() PRODUCT_RETURN;
--- a/src/share/vm/classfile/classLoaderData.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classLoaderData.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -51,6 +51,8 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.hpp" #include "classfile/metadataOnStackMark.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/shared/gcLocker.hpp" @@ -81,6 +83,7 @@ // The null-class-loader should always be kept alive. _keep_alive(is_anonymous || h_class_loader.is_null()), _metaspace(NULL), _unloading(false), _klasses(NULL), + _modules(NULL), _packages(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, @@ -166,6 +169,30 @@ } } +void ClassLoaderData::modules_do(void f(ModuleEntry*)) { + if (_modules != NULL) { + for (int i = 0; i < _modules->table_size(); i++) { + for (ModuleEntry* entry = _modules->bucket(i); + entry != NULL; + entry = entry->next()) { + f(entry); + } + } + } +} + +void ClassLoaderData::packages_do(void f(PackageEntry*)) { + if (_packages != NULL) { + for (int i = 0; i < _packages->table_size(); i++) { + for (PackageEntry* entry = _packages->bucket(i); + entry != NULL; + entry = entry->next()) { + f(entry); + } + } + } +} + void ClassLoaderData::record_dependency(Klass* k, TRAPS) { ClassLoaderData * const from_cld = this; ClassLoaderData * const to_cld = k->class_loader_data(); @@ -334,6 +361,46 @@ } } +PackageEntryTable* ClassLoaderData::packages() { + // Lazily create the package entry table at first request. + if (_packages == NULL) { + MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); + // Check again if _packages has been allocated while we were getting this lock. + if (_packages != NULL) { + return _packages; + } + // Ensure _packages is stable, since it is examined without a lock + OrderAccess::storestore(); + _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); + } + return _packages; +} + +ModuleEntryTable* ClassLoaderData::modules() { + // Lazily create the module entry table at first request. + if (_modules == NULL) { + MutexLocker m1(Module_lock); + // Check again if _modules has been allocated while we were getting this lock. + if (_modules != NULL) { + return _modules; + } + + ModuleEntryTable* temp_table = new ModuleEntryTable(ModuleEntryTable::_moduletable_entry_size); + // Each loader has one unnamed module entry. Create it before + // any classes, loaded by this loader, are defined in case + // they end up being defined in loader's unnamed module. + temp_table->create_unnamed_module(this); + + { + MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); + // Ensure _modules is stable, since it is examined without a lock + OrderAccess::storestore(); + _modules = temp_table; + } + } + return _modules; +} + oop ClassLoaderData::keep_alive_object() const { assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); return is_anonymous() ? _klasses->java_mirror() : class_loader(); @@ -351,6 +418,20 @@ // Release C heap structures for all the classes. classes_do(InstanceKlass::release_C_heap_structures); + // Release C heap allocated hashtable for all the packages. + if (_packages != NULL) { + // Destroy the table itself + delete _packages; + _packages = NULL; + } + + // Release C heap allocated hashtable for all the modules. + if (_modules != NULL) { + // Destroy the table itself + delete _modules; + _modules = NULL; + } + Metaspace *m = _metaspace; if (m != NULL) { _metaspace = NULL; @@ -431,6 +512,10 @@ return handles()->allocate_handle(h()); } +void ClassLoaderData::remove_handle(jobject h) { + _handles->release_handle(h); +} + // Add this metadata pointer to be freed when it's safe. This is only during // class unloading because Handles might point to this metadata field. void ClassLoaderData::add_to_deallocate_list(Metadata* m) { @@ -679,6 +764,40 @@ } } +void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) { + assert_locked_or_safepoint(Module_lock); + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->modules_do(f); + } +} + +void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->modules_do(f); + } +} + +void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { + assert_locked_or_safepoint(Module_lock); + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->packages_do(f); + } +} + +void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->packages_do(f); + } +} + void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->loaded_classes_do(klass_closure); @@ -690,6 +809,7 @@ // Only walk the head until any clds not purged from prior unloading // (CMS doesn't purge right away). for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); cld->classes_do(f); } } @@ -766,6 +886,12 @@ data = _head; while (data != NULL) { if (data->is_alive(is_alive_closure)) { + if (!data->packageTable_is_null()) { + data->packages()->purge_all_package_exports(); + } + if (!data->moduleTable_is_null()) { + data->modules()->purge_all_module_reads(); + } // clean metaspace if (walk_all_metadata) { data->classes_do(InstanceKlass::purge_previous_versions); @@ -812,7 +938,7 @@ classes_unloaded = true; } if (classes_unloaded) { - Metaspace::purge(); + Metaspace::purge(); set_metaspace_oom(false); } } @@ -958,6 +1084,7 @@ Ticks ClassLoaderDataGraph::_class_unload_time; void ClassLoaderDataGraph::class_unload_event(Klass* const k) { + assert(k != NULL, "invariant"); // post class unload event EventClassUnload event(UNTIMED);
--- a/src/share/vm/classfile/classLoaderData.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classLoaderData.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -53,6 +53,10 @@ class JNIMethodBlock; class JNIHandleBlock; class Metadebug; +class ModuleEntry; +class PackageEntry; +class ModuleEntryTable; +class PackageEntryTable; // GC root for walking class loader data created @@ -92,6 +96,10 @@ static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); static void methods_do(void f(Method*)); + static void modules_do(void f(ModuleEntry*)); + static void modules_unloading_do(void f(ModuleEntry*)); + static void packages_do(void f(PackageEntry*)); + static void packages_unloading_do(void f(PackageEntry*)); static void loaded_classes_do(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions); @@ -171,9 +179,12 @@ volatile int _claimed; // true if claimed, for example during GC traces. // To avoid applying oop closure more than once. // Has to be an int because we cas it. + JNIHandleBlock* _handles; // Handles to constant pool arrays, Modules, etc, which + // have the same life cycle of the corresponding ClassLoader. + Klass* _klasses; // The classes defined by the class loader. - - JNIHandleBlock* _handles; // Handles to constant pool arrays + PackageEntryTable* _packages; // The packages defined by the class loader. + ModuleEntryTable* _modules; // The modules defined by the class loader. // These method IDs are created for the class loader and set to NULL when the // class loader is unloaded. They are rarely freed, only for redefine classes @@ -214,6 +225,8 @@ void loaded_classes_do(KlassClosure* klass_closure); void classes_do(void f(InstanceKlass*)); void methods_do(void f(Method*)); + void modules_do(void f(ModuleEntry*)); + void packages_do(void f(PackageEntry*)); // Deallocate free list during class unloading. void free_deallocate_list(); @@ -291,11 +304,16 @@ const char* loader_name(); jobject add_handle(Handle h); + void remove_handle(jobject h); void add_class(Klass* k); void remove_class(Klass* k); bool contains_klass(Klass* k); void record_dependency(Klass* to, TRAPS); void init_dependencies(TRAPS); + PackageEntryTable* packages(); + bool packageTable_is_null() { return (_packages == NULL); } + ModuleEntryTable* modules(); + bool moduleTable_is_null() { return (_modules == NULL); } void add_to_deallocate_list(Metadata* m);
--- a/src/share/vm/classfile/classLoaderExt.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/classLoaderExt.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,10 +48,12 @@ } instanceKlassHandle record_result(const int classpath_index, + const jshort classloader_type, ClassPathEntry* e, instanceKlassHandle result, TRAPS) { if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) { if (DumpSharedSpaces) { result->set_shared_classpath_index(classpath_index); + result->set_class_loader_type(classloader_type); } return result; } else { @@ -62,11 +64,22 @@ static void add_class_path_entry(const char* path, bool check_for_duplicates, - ClassPathEntry* new_entry) { - ClassLoader::add_to_list(new_entry); + ClassPathEntry* new_entry, bool prepend_entry) { + if (prepend_entry) { + ClassLoader::prepend_to_list(new_entry); + } else { + ClassLoader::add_to_list(new_entry); + } } static void append_boot_classpath(ClassPathEntry* new_entry) { ClassLoader::add_to_list(new_entry); + // During jvmti live phase an entry can be appended to the boot + // loader's ClassPathEntry instances. Need to mark the start + // of the boot loader's append path in case there was no reason + // to mark it initially in setup_bootstrap_search_path. + if (ClassLoader::_first_append_entry == NULL) { + ClassLoader::set_first_append_entry(new_entry); + } } static void setup_search_paths() {} };
--- a/src/share/vm/classfile/javaClasses.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/javaClasses.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -24,7 +24,9 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/stringTable.hpp" #include "classfile/vmSymbols.hpp" #include "code/debugInfo.hpp" @@ -767,7 +769,7 @@ } } } - create_mirror(k, Handle(NULL), Handle(NULL), CHECK); + create_mirror(k, Handle(NULL), Handle(NULL), Handle(NULL), CHECK); } void java_lang_Class::initialize_mirror_fields(KlassHandle k, @@ -788,7 +790,7 @@ } void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, - Handle protection_domain, TRAPS) { + Handle module, Handle protection_domain, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); // Use this moment of initialization to cache modifier_flags also, // to support Class.getModifiers(). Instance classes recalculate @@ -848,6 +850,10 @@ assert(class_loader() == k->class_loader(), "should be same"); set_class_loader(mirror(), class_loader()); + // set the module field in the java_lang_Class instance + // This may be null during bootstrap but will get fixed up later on. + set_module(mirror(), module()); + // Setup indirection from klass->mirror last // after any exceptions can happen during allocations. if (!k.is_null()) { @@ -861,8 +867,26 @@ } fixup_mirror_list()->push(k()); } -} - + // Keep list of classes needing java.base module fixup. + if (!ModuleEntryTable::javabase_defined()) { + if (fixup_jlrM_list() == NULL) { + GrowableArray<Klass*>* list = + new (ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(500, true); + set_fixup_jlrM_list(list); + } + if (k->is_instance_klass()) { + fixup_jlrM_list()->push(k()); + } else if (k->is_objArray_klass()) { + ObjArrayKlass* obj_arr_klass = ObjArrayKlass::cast(k()); + fixup_jlrM_list()->push(obj_arr_klass->bottom_klass()); + } + } +} + +void java_lang_Class::fixup_jlrM(KlassHandle k, Handle module, TRAPS) { + assert(_module_offset != 0, "must have been computed already"); + java_lang_Class::set_module(k->java_mirror(), module()); +} int java_lang_Class::oop_size(oop java_class) { assert(_oop_size_offset != 0, "must be set"); @@ -930,6 +954,16 @@ return java_class->obj_field(_class_loader_offset); } +oop java_lang_Class::module(oop java_class) { + assert(_module_offset != 0, "must be set"); + return java_class->obj_field(_module_offset); +} + +void java_lang_Class::set_module(oop java_class, oop md) { + assert(_module_offset != 0, "must be set"); + java_class->obj_field_put(_module_offset, md); +} + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) @@ -1115,6 +1149,10 @@ k, vmSymbols::componentType_name(), vmSymbols::class_signature()); + compute_offset(_module_offset, + k, vmSymbols::module_name(), + vmSymbols::module_signature()); + // Init lock is a C union with component_mirror. Only instanceKlass mirrors have // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops // GC treats them the same. @@ -1724,28 +1762,48 @@ buf_len += (int)strlen(source_file_name); } + char *module_name = NULL, *module_version = NULL; + ModuleEntry* module = holder->module(); + if (module->is_named()) { + module_name = module->name()->as_C_string(); + buf_len += (int)strlen(module_name); + if (module->version() != NULL) { + module_version = module->version()->as_C_string(); + buf_len += (int)strlen(module_version); + } + } + // Allocate temporary buffer with extra space for formatting and line number char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); // Print stack trace line in buffer - sprintf(buf, "\tat %s.%s", klass_name, method_name); + sprintf(buf, "\tat %s.%s(", klass_name, method_name); + + // Print module information + if (module_name != NULL) { + if (module_version != NULL) { + sprintf(buf + (int)strlen(buf), "%s@%s/", module_name, module_version); + } else { + sprintf(buf + (int)strlen(buf), "%s/", module_name); + } + } if (!version_matches(method, version)) { - strcat(buf, "(Redefined)"); + strcat(buf, "Redefined)"); } else { int line_number = get_line_number(method, bci); if (line_number == -2) { - strcat(buf, "(Native Method)"); + strcat(buf, "Native Method)"); } else { if (source_file_name != NULL && (line_number != -1)) { // Sourcename and linenumber - sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); + sprintf(buf + (int)strlen(buf), "%s:%d)", source_file_name, line_number); } else if (source_file_name != NULL) { // Just sourcename - sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); + sprintf(buf + (int)strlen(buf), "%s)", source_file_name); } else { // Neither sourcename nor linenumber - sprintf(buf + (int)strlen(buf), "(Unknown Source)"); + sprintf(buf + (int)strlen(buf), "Unknown Source)"); } nmethod* nm = method->code(); if (WizardMode && nm != NULL) { @@ -2130,6 +2188,20 @@ oop methodname = StringTable::intern(sym, CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); + // Fill in module name and version + ModuleEntry* module = holder->module(); + if (module->is_named()) { + oop module_name = StringTable::intern(module->name()->as_utf8(), CHECK_0); + java_lang_StackTraceElement::set_moduleName(element(), module_name); + oop module_version; + if (module->version() != NULL) { + module_version = StringTable::intern(module->version()->as_utf8(), CHECK_0); + } else { + module_version = NULL; + } + java_lang_StackTraceElement::set_moduleVersion(element(), module_version); + } + if (!version_matches(method, version)) { // The method was redefined, accurate line number information isn't available java_lang_StackTraceElement::set_fileName(element(), NULL); @@ -2687,6 +2759,80 @@ } +int java_lang_reflect_Module::loader_offset; +int java_lang_reflect_Module::name_offset; +int java_lang_reflect_Module::_module_entry_offset = -1; + +Handle java_lang_reflect_Module::create(Handle loader, Handle module_name, TRAPS) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + + Symbol* name = vmSymbols::java_lang_reflect_Module(); + Klass* k = SystemDictionary::resolve_or_fail(name, true, CHECK_NH); + instanceKlassHandle klass (THREAD, k); + + Handle jlrmh = klass->allocate_instance_handle(CHECK_NH); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, jlrmh, KlassHandle(THREAD, klass()), + vmSymbols::object_initializer_name(), + vmSymbols::java_lang_reflect_module_init_signature(), + loader, module_name, CHECK_NH); + return jlrmh; +} + +void java_lang_reflect_Module::compute_offsets() { + Klass* k = SystemDictionary::reflect_Module_klass(); + if(NULL != k) { + compute_offset(loader_offset, k, vmSymbols::loader_name(), vmSymbols::classloader_signature()); + compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); + MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); + } +} + + +oop java_lang_reflect_Module::loader(oop module) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + return module->obj_field(loader_offset); +} + +void java_lang_reflect_Module::set_loader(oop module, oop value) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + module->obj_field_put(loader_offset, value); +} + +oop java_lang_reflect_Module::name(oop module) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + return module->obj_field(name_offset); +} + +void java_lang_reflect_Module::set_name(oop module, oop value) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + module->obj_field_put(name_offset, value); +} + +ModuleEntry* java_lang_reflect_Module::module_entry(oop module, TRAPS) { + assert(_module_entry_offset != -1, "Uninitialized module_entry_offset"); + assert(module != NULL, "module can't be null"); + assert(module->is_oop(), "module must be oop"); + + ModuleEntry* module_entry = (ModuleEntry*)module->address_field(_module_entry_offset); + if (module_entry == NULL) { + // If the inject field containing the ModuleEntry* is null then return the + // class loader's unnamed module. + oop loader = java_lang_reflect_Module::loader(module); + Handle h_loader = Handle(THREAD, loader); + ClassLoaderData* loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); + return loader_cld->modules()->unnamed_module(); + } + return module_entry; +} + +void java_lang_reflect_Module::set_module_entry(oop module, ModuleEntry* module_entry) { + assert(_module_entry_offset != -1, "Uninitialized module_entry_offset"); + assert(module != NULL, "module can't be null"); + assert(module->is_oop(), "module must be oop"); + module->address_field_put(_module_entry_offset, (address)module_entry); +} + Handle sun_reflect_ConstantPool::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); Klass* k = SystemDictionary::reflect_ConstantPool_klass(); @@ -3289,6 +3435,7 @@ bool java_lang_ClassLoader::offsets_computed = false; int java_lang_ClassLoader::_loader_data_offset = -1; int java_lang_ClassLoader::parallelCapable_offset = -1; +int java_lang_ClassLoader::unnamedModule_offset = -1; ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) { assert(loader != NULL && loader->is_oop(), "loader must be oop"); @@ -3308,6 +3455,9 @@ compute_optional_offset(parallelCapable_offset, k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature()); + compute_offset(unnamedModule_offset, + k1, vmSymbols::unnamedModule_name(), vmSymbols::module_signature()); + CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } @@ -3375,6 +3525,10 @@ return loader; } +oop java_lang_ClassLoader::unnamedModule(oop loader) { + assert(is_instance(loader), "loader must be oop"); + return loader->obj_field(unnamedModule_offset); +} // Support for java_lang_System int java_lang_System::in_offset_in_bytes() { @@ -3407,11 +3561,13 @@ int java_lang_Class::_oop_size_offset; int java_lang_Class::_static_oop_field_count_offset; int java_lang_Class::_class_loader_offset; +int java_lang_Class::_module_offset; int java_lang_Class::_protection_domain_offset; int java_lang_Class::_component_mirror_offset; int java_lang_Class::_init_lock_offset; int java_lang_Class::_signers_offset; GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL; +GrowableArray<Klass*>* java_lang_Class::_fixup_jlrM_list = NULL; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset; int java_lang_Throwable::cause_offset; @@ -3471,6 +3627,8 @@ int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; +int java_lang_StackTraceElement::moduleName_offset; +int java_lang_StackTraceElement::moduleVersion_offset; int java_lang_AssertionStatusDirectives::classes_offset; int java_lang_AssertionStatusDirectives::classEnabled_offset; int java_lang_AssertionStatusDirectives::packages_offset; @@ -3500,6 +3658,14 @@ element->int_field_put(lineNumber_offset, value); } +void java_lang_StackTraceElement::set_moduleName(oop element, oop value) { + element->obj_field_put(moduleName_offset, value); +} + +void java_lang_StackTraceElement::set_moduleVersion(oop element, oop value) { + element->obj_field_put(moduleVersion_offset, value); +} + // Support for java Assertions - java_lang_AssertionStatusDirectives. @@ -3594,6 +3760,8 @@ java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x; // java_lang_StackTraceElement + java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header; + java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header; java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset * x + header; java_lang_StackTraceElement::methodName_offset = java_lang_StackTraceElement::hc_methodName_offset * x + header; java_lang_StackTraceElement::fileName_offset = java_lang_StackTraceElement::hc_fileName_offset * x + header; @@ -3633,6 +3801,7 @@ sun_reflect_ConstantPool::compute_offsets(); sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); java_lang_reflect_Parameter::compute_offsets(); + java_lang_reflect_Module::compute_offsets(); // generated interpreter code wants to know about the offsets we just computed: AbstractAssembler::update_delayed_values(); @@ -3778,7 +3947,7 @@ // java.lang.ClassLoader - CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent, "Ljava/lang/ClassLoader;"); + CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent, "Ljava/lang/ClassLoader;"); // java.lang.System
--- a/src/share/vm/classfile/javaClasses.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/javaClasses.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -254,26 +254,32 @@ static int _init_lock_offset; static int _signers_offset; static int _class_loader_offset; + static int _module_offset; static int _component_mirror_offset; static bool offsets_computed; static int classRedefinedCount_offset; static GrowableArray<Klass*>* _fixup_mirror_list; + static GrowableArray<Klass*>* _fixup_jlrM_list; static void set_init_lock(oop java_class, oop init_lock); static void set_protection_domain(oop java_class, oop protection_domain); static void set_class_loader(oop java_class, oop class_loader); + static void set_module(oop java_class, oop module); static void set_component_mirror(oop java_class, oop comp_mirror); static void initialize_mirror_fields(KlassHandle k, Handle mirror, Handle protection_domain, TRAPS); public: static void compute_offsets(); // Instance creation - static void create_mirror(KlassHandle k, Handle class_loader, + static void create_mirror(KlassHandle k, Handle class_loader, Handle module, Handle protection_domain, TRAPS); static void fixup_mirror(KlassHandle k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); + + static void fixup_jlrM(KlassHandle k, Handle module, TRAPS); + // Conversion static Klass* as_Klass(oop java_class); static void set_klass(oop java_class, Klass* klass); @@ -311,18 +317,28 @@ static void set_signers(oop java_class, objArrayOop signers); static oop class_loader(oop java_class); + static oop module(oop java_class); static int oop_size(oop java_class); static void set_oop_size(oop java_class, int size); static int static_oop_field_count(oop java_class); static void set_static_oop_field_count(oop java_class, int size); + static GrowableArray<Klass*>* fixup_mirror_list() { return _fixup_mirror_list; } static void set_fixup_mirror_list(GrowableArray<Klass*>* v) { _fixup_mirror_list = v; } + + static GrowableArray<Klass*>* fixup_jlrM_list() { + return _fixup_jlrM_list; + } + static void set_fixup_jlrM_list(GrowableArray<Klass*>* v) { + _fixup_jlrM_list = v; + } + // Debugging friend class JavaClasses; friend class InstanceKlass; // verification code accesses offsets @@ -802,6 +818,39 @@ friend class JavaClasses; }; +#define MODULE_INJECTED_FIELDS(macro) \ + macro(java_lang_reflect_Module, module_entry, intptr_signature, false) + +class java_lang_reflect_Module { + private: + static int loader_offset; + static int name_offset; + static int _module_entry_offset; + static void compute_offsets(); + + public: + // Allocation + static Handle create(Handle loader, Handle module_name, TRAPS); + + // Testers + static bool is_subclass(Klass* klass) { + return klass->is_subclass_of(SystemDictionary::reflect_Module_klass()); + } + static bool is_instance(oop obj); + + // Accessors + static oop loader(oop module); + static void set_loader(oop module, oop value); + + static oop name(oop module); + static void set_name(oop module, oop value); + + static ModuleEntry* module_entry(oop module, TRAPS); + static void set_module_entry(oop module, ModuleEntry* module_entry); + + friend class JavaClasses; +}; + // Interface to sun.reflect.ConstantPool objects class sun_reflect_ConstantPool { private: @@ -1269,6 +1318,7 @@ static bool offsets_computed; static int parent_offset; static int parallelCapable_offset; + static int unnamedModule_offset; public: static void compute_offsets(); @@ -1293,6 +1343,8 @@ } static bool is_instance(oop obj); + static oop unnamedModule(oop loader); + // Debugging friend class JavaClasses; friend class ClassFileParser; // access to number_of_fake_fields @@ -1332,12 +1384,16 @@ class java_lang_StackTraceElement: AllStatic { private: enum { - hc_declaringClass_offset = 0, - hc_methodName_offset = 1, - hc_fileName_offset = 2, - hc_lineNumber_offset = 3 + hc_moduleName_offset = 0, + hc_moduleVersion_offset = 1, + hc_declaringClass_offset = 2, + hc_methodName_offset = 3, + hc_fileName_offset = 4, + hc_lineNumber_offset = 5 }; + static int moduleName_offset; + static int moduleVersion_offset; static int declaringClass_offset; static int methodName_offset; static int fileName_offset; @@ -1345,6 +1401,8 @@ public: // Setters + static void set_moduleName(oop element, oop value); + static void set_moduleVersion(oop element, oop value); static void set_declaringClass(oop element, oop value); static void set_methodName(oop element, oop value); static void set_fileName(oop element, oop value); @@ -1442,7 +1500,8 @@ CLASS_INJECTED_FIELDS(macro) \ CLASSLOADER_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ - CALLSITECONTEXT_INJECTED_FIELDS(macro) + CALLSITECONTEXT_INJECTED_FIELDS(macro) \ + MODULE_INJECTED_FIELDS(macro) // Interface to hard-coded offset checking
--- a/src/share/vm/classfile/javaClasses.inline.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/javaClasses.inline.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -73,4 +73,8 @@ return obj != NULL && is_subclass(obj->klass()); } +inline bool java_lang_reflect_Module::is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); +} + #endif // SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/moduleEntry.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" +#include "memory/resourceArea.hpp" +#include "oops/symbol.hpp" +#include "prims/jni.h" +#include "runtime/handles.inline.hpp" +#include "runtime/safepoint.hpp" +#include "trace/traceMacros.hpp" +#include "utilities/events.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.inline.hpp" + +ModuleEntry* ModuleEntryTable::_javabase_module = NULL; + +// Returns the shared ProtectionDomain +Handle ModuleEntry::shared_protection_domain() { + return Handle(JNIHandles::resolve(_pd)); +} + +// Set the shared ProtectionDomain atomically +void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data, + Handle pd_h) { + // Create a JNI handle for the shared ProtectionDomain and save it atomically. + // If someone beats us setting the _pd cache, the created JNI handle is destroyed. + jobject obj = loader_data->add_handle(pd_h); + if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) { + loader_data->remove_handle(obj); + } +} + +// Returns true if this module can read module m +bool ModuleEntry::can_read(ModuleEntry* m) const { + assert(m != NULL, "No module to lookup in this module's reads list"); + if (!this->is_named()) return true; // Unnamed modules read everyone. + MutexLocker m1(Module_lock); + if (_reads == NULL) { + return false; + } else { + return _reads->contains(m); + } +} + +// Add a new module to this module's reads list +void ModuleEntry::add_read(ModuleEntry* m) { + MutexLocker m1(Module_lock); + if (m == NULL) { + set_can_read_unnamed(); + } else { + if (_reads == NULL) { + // Lazily create a module's reads list + // Initial size is 101. + _reads = new (ResourceObj::C_HEAP, mtClass) GrowableArray<ModuleEntry*>(101, true); + } + _reads->append_if_missing(m); + } +} + +bool ModuleEntry::has_reads() const { + return _reads != NULL && !_reads->is_empty(); +} + +// Purge dead module entries out of reads list. +void ModuleEntry::purge_reads() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + if (_reads != NULL) { + // Go backwards because this removes entries that are dead. + int len = _reads->length(); + for (int idx = len - 1; idx >= 0; idx--) { + ModuleEntry* module_idx = _reads->at(idx); + ClassLoaderData* cld = module_idx->loader(); + if (cld->is_unloading()) { + _reads->delete_at(idx); + } + } + } +} + +void ModuleEntry::module_reads_do(ModuleClosure* const f) { + assert_locked_or_safepoint(Module_lock); + assert(f != NULL, "invariant"); + + if (_reads != NULL) { + int reads_len = _reads->length(); + for (int i = 0; i < reads_len; ++i) { + f->do_module(_reads->at(i)); + } + } +} + +void ModuleEntry::delete_reads() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + delete _reads; + _reads = NULL; +} + +ModuleEntryTable::ModuleEntryTable(int table_size) + : Hashtable<Symbol*, mtClass>(table_size, sizeof(ModuleEntry)), _unnamed_module(NULL) +{ +} + +ModuleEntryTable::~ModuleEntryTable() { + assert_locked_or_safepoint(Module_lock); + + // Walk through all buckets and all entries in each bucket, + // freeing each entry. + for (int i = 0; i < table_size(); ++i) { + for (ModuleEntry* m = bucket(i); m != NULL;) { + ModuleEntry* to_remove = m; + // read next before freeing. + m = m->next(); + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[ModuleEntryTable: deleting module: %s]", to_remove->name() != NULL ? + to_remove->name()->as_C_string() : UNNAMED_MODULE); + } + + // Clean out the C heap allocated reads list first before freeing the entry + to_remove->delete_reads(); + if (to_remove->name() != NULL) { + to_remove->name()->decrement_refcount(); + } + if (to_remove->version() != NULL) { + to_remove->version()->decrement_refcount(); + } + if (to_remove->location() != NULL) { + to_remove->location()->decrement_refcount(); + } + + // Unlink from the Hashtable prior to freeing + unlink_entry(to_remove); + FREE_C_HEAP_ARRAY(char, to_remove); + } + } + assert(number_of_entries() == 0, "should have removed all entries"); + assert(new_entry_free_list() == NULL, "entry present on ModuleEntryTable's free list"); + free_buckets(); +} + +void ModuleEntryTable::create_unnamed_module(ClassLoaderData* loader_data) { + assert_locked_or_safepoint(Module_lock); + + // Each ModuleEntryTable has exactly one unnamed module + if (loader_data->is_the_null_class_loader_data()) { + // For the boot loader, the java.lang.reflect.Module for the unnamed module + // is not known until a call to JVM_SetBootLoaderUnnamedModule is made. At + // this point initially create the ModuleEntry for the unnamed module. + _unnamed_module = new_entry(0, Handle(NULL), NULL, NULL, NULL, loader_data); + } else { + // For all other class loaders the java.lang.reflect.Module for their + // corresponding unnamed module can be found in the java.lang.ClassLoader object. + oop module = java_lang_ClassLoader::unnamedModule(loader_data->class_loader()); + _unnamed_module = new_entry(0, Handle(module), NULL, NULL, NULL, loader_data); + + // Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module + // object. + java_lang_reflect_Module::set_module_entry(module, _unnamed_module); + } + + // Add to bucket 0, no name to hash on + add_entry(0, _unnamed_module); +} + +ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle jlrM_handle, Symbol* name, + Symbol* version, Symbol* location, + ClassLoaderData* loader_data) { + assert_locked_or_safepoint(Module_lock); + ModuleEntry* entry = (ModuleEntry*) NEW_C_HEAP_ARRAY2(char, entry_size(), mtClass, CURRENT_PC); + + // Initialize everything BasicHashtable would + entry->set_next(NULL); + entry->set_hash(hash); + entry->set_literal(name); + + // Initialize fields specific to a ModuleEntry + entry->init(); + if (name != NULL) { + name->increment_refcount(); + } else { + // Unnamed modules can read all other unnamed modules. + entry->set_can_read_unnamed(); + } + + if (!jlrM_handle.is_null()) { + entry->set_jlrM_module(loader_data->add_handle(jlrM_handle)); + } + + entry->set_loader(loader_data); + + if (version != NULL) { + entry->set_version(version); + version->increment_refcount(); + } + + if (location != NULL) { + entry->set_location(location); + location->increment_refcount(); + } + TRACE_INIT_MODULE_ID(entry); + + return entry; +} + +void ModuleEntryTable::add_entry(int index, ModuleEntry* new_entry) { + assert_locked_or_safepoint(Module_lock); + Hashtable<Symbol*, mtClass>::add_entry(index, (HashtableEntry<Symbol*, mtClass>*)new_entry); +} + +ModuleEntry* ModuleEntryTable::locked_create_entry_or_null(Handle jlrM_handle, + Symbol* module_name, + Symbol* module_version, + Symbol* module_location, + ClassLoaderData* loader_data) { + assert(module_name != NULL, "ModuleEntryTable locked_create_entry_or_null should never be called for unnamed module."); + assert_locked_or_safepoint(Module_lock); + // Check if module already exists. + if (lookup_only(module_name) != NULL) { + return NULL; + } else { + ModuleEntry* entry = new_entry(compute_hash(module_name), jlrM_handle, module_name, + module_version, module_location, loader_data); + add_entry(index_for(module_name), entry); + return entry; + } +} + +// lookup_only by Symbol* to find a ModuleEntry. +ModuleEntry* ModuleEntryTable::lookup_only(Symbol* name) { + if (name == NULL) { + // Return this table's unnamed module + return unnamed_module(); + } + int index = index_for(name); + for (ModuleEntry* m = bucket(index); m != NULL; m = m->next()) { + if (m->name()->fast_compare(name) == 0) { + return m; + } + } + return NULL; +} + +// Remove dead modules from all other alive modules' reads list. +// This should only occur at class unloading. +void ModuleEntryTable::purge_all_module_reads() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + for (int i = 0; i < table_size(); i++) { + for (ModuleEntry* entry = bucket(i); + entry != NULL; + entry = entry->next()) { + entry->purge_reads(); + } + } +} + +void ModuleEntryTable::finalize_javabase(Handle jlrM_module, Symbol* version, Symbol* location) { + assert_locked_or_safepoint(Module_lock); + ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data(); + ModuleEntryTable* module_table = boot_loader_data->modules(); + + assert(module_table != NULL, "boot loader's ModuleEntryTable not defined"); + + if (jlrM_module.is_null()) { + fatal("Unable to finalize module definition for java.base"); + } + + // Set java.lang.reflect.Module, version and location for java.base + ModuleEntry* jb_module = javabase_module(); + assert(jb_module != NULL, "java.base ModuleEntry not defined"); + jb_module->set_jlrM_module(boot_loader_data->add_handle(jlrM_module)); + jb_module->set_version(version); + jb_module->set_location(location); + // Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object. + java_lang_reflect_Module::set_module_entry(jlrM_module(), jb_module); +} + +void ModuleEntryTable::patch_javabase_entries(Handle jlrM_handle, TRAPS) { + if (jlrM_handle.is_null()) { + fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module"); + } + + // Do the fixups for classes that have already been created. + GrowableArray <Klass*>* list = java_lang_Class::fixup_jlrM_list(); + int list_length = list->length(); + for (int i = 0; i < list_length; i++) { + Klass* k = list->at(i); + assert(k->is_klass(), "List should only hold classes"); + EXCEPTION_MARK; + KlassHandle kh(THREAD, k); + java_lang_Class::fixup_jlrM(kh, jlrM_handle, CATCH); + } + + delete java_lang_Class::fixup_jlrM_list(); + java_lang_Class::set_fixup_jlrM_list(NULL); +} + +#ifndef PRODUCT +void ModuleEntryTable::print() { + tty->print_cr("Module Entry Table (table_size=%d, entries=%d)", + table_size(), number_of_entries()); + for (int i = 0; i < table_size(); i++) { + for (ModuleEntry* probe = bucket(i); + probe != NULL; + probe = probe->next()) { + probe->print(); + } + } +} + +void ModuleEntry::print() { + ResourceMark rm; + tty->print_cr("entry "PTR_FORMAT" name %s jlrM "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT, + p2i(this), + name() == NULL ? UNNAMED_MODULE : name()->as_C_string(), + p2i(jlrM_module()), + loader()->loader_name(), + version() != NULL ? version()->as_C_string() : "NULL", + location() != NULL ? location()->as_C_string() : "NULL", + BOOL_TO_STR(!can_read_unnamed()), p2i(next())); +} +#endif + +void ModuleEntryTable::verify() { + int element_count = 0; + for (int i = 0; i < table_size(); i++) { + for (ModuleEntry* probe = bucket(i); + probe != NULL; + probe = probe->next()) { + probe->verify(); + element_count++; + } + } + guarantee(number_of_entries() == element_count, + "Verify of Module Entry Table failed"); + debug_only(verify_lookup_length((double)number_of_entries() / table_size())); +} + +void ModuleEntry::verify() { + guarantee(loader() != NULL, "A module entry must be associated with a loader."); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/moduleEntry.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_MODULEENTRY_HPP +#define SHARE_VM_CLASSFILE_MODULEENTRY_HPP + +#include "classfile/classLoaderData.hpp" +#include "classfile/vmSymbols.hpp" +#include "oops/symbol.hpp" +#include "prims/jni.h" +#include "runtime/mutexLocker.hpp" +#include "trace/traceMacros.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.hpp" + +#define UNNAMED_MODULE "Unnamed Module" + +class ModuleClosure; + +// A ModuleEntry describes a module that has been defined by a call to JVM_DefineModule. +// It contains: +// - Symbol* containing the module's name. +// - pointer to the java.lang.reflect.Module for this module. +// - ClassLoaderData*, class loader of this module. +// - a growable array containg other module entries that this module can read. +// - a flag indicating if this module can read all unnamed modules. +// +class ModuleEntry : public HashtableEntry<Symbol*, mtClass> { +private: + jobject _jlrM; // java.lang.reflect.Module + jobject _pd; // java.security.ProtectionDomain, cached + // for shared classes from this module + ClassLoaderData* _loader; + GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module + Symbol* _version; // module version number + Symbol* _location; // module location + bool _can_read_unnamed; + TRACE_DEFINE_TRACE_ID_FIELD; + +public: + void init() { + _jlrM = NULL; + _loader = NULL; + _pd = NULL; + _reads = NULL; + _version = NULL; + _location = NULL; + _can_read_unnamed = false; + } + + Symbol* name() const { return literal(); } + void set_name(Symbol* n) { set_literal(n); } + + jobject jlrM_module() const { return _jlrM; } + void set_jlrM_module(jobject j) { _jlrM = j; } + + // The shared ProtectionDomain reference is set once the VM loads a shared class + // originated from the current Module. The referenced ProtectionDomain object is + // created by the ClassLoader when loading a class (shared or non-shared) from the + // Module for the first time. This ProtectionDomain object is used for all + // classes from the Module loaded by the same ClassLoader. + Handle shared_protection_domain(); + void set_shared_protection_domain(ClassLoaderData *loader_data, + Handle pd); + + ClassLoaderData* loader() const { return _loader; } + void set_loader(ClassLoaderData* l) { _loader = l; } + + Symbol* version() const { return _version; } + void set_version(Symbol* version) { _version = version; } + + Symbol* location() const { return _location; } + void set_location(Symbol* location) { _location = location; } + + bool can_read(ModuleEntry* m) const; + bool has_reads() const; + void add_read(ModuleEntry* m); + + bool is_named() const { return (literal() != NULL); } + + bool can_read_unnamed() const { + assert(is_named() || _can_read_unnamed == true, + "unnamed modules can always read all unnamed modules"); + return _can_read_unnamed; + } + + // Modules can only go from strict to loose. + void set_can_read_unnamed() { _can_read_unnamed = true; } + + ModuleEntry* next() const { + return (ModuleEntry*)HashtableEntry<Symbol*, mtClass>::next(); + } + ModuleEntry** next_addr() { + return (ModuleEntry**)HashtableEntry<Symbol*, mtClass>::next_addr(); + } + + // iteration support for readability + void module_reads_do(ModuleClosure* const f); + + TRACE_DEFINE_TRACE_ID_METHODS; + + // Purge dead weak references out of reads list when any given class loader is unloaded. + void purge_reads(); + void delete_reads(); + + void print() PRODUCT_RETURN; + void verify(); +}; + +// Iterator interface +class ModuleClosure: public StackObj { + public: + virtual void do_module(ModuleEntry* const module) = 0; +}; + + +// The ModuleEntryTable is a Hashtable containing a list of all modules defined +// by a particular class loader. Each module is represented as a ModuleEntry node. +// +// Each ModuleEntryTable contains a _javabase_module field which allows for the +// creation of java.base's ModuleEntry very early in bootstrapping before the +// corresponding JVM_DefineModule call for java.base occurs during module system +// initialization. Setting up java.base's ModuleEntry early enables classes, +// loaded prior to the module system being initialized to be created with their +// PackageEntry node's correctly pointing at java.base's ModuleEntry. No class +// outside of java.base is allowed to be loaded pre-module system initialization. +// +// The ModuleEntryTable's lookup is lock free. +// +class ModuleEntryTable : public Hashtable<Symbol*, mtClass> { + friend class VMStructs; +public: + enum Constants { + _moduletable_entry_size = 109 // number of entries in module entry table + }; + +private: + static ModuleEntry* _javabase_module; + ModuleEntry* _unnamed_module; + + ModuleEntry* new_entry(unsigned int hash, Handle jlrM_handle, Symbol* name, Symbol* version, + Symbol* location, ClassLoaderData* class_loader); + void add_entry(int index, ModuleEntry* new_entry); + +public: + ModuleEntryTable(int table_size); + ~ModuleEntryTable(); + + int entry_size() const { return BasicHashtable<mtClass>::entry_size(); } + + // Create module in loader's module entry table, if already exists then + // return null. Assume Module_lock has been locked by caller. + ModuleEntry* locked_create_entry_or_null(Handle jlrM_handle, + Symbol* module_name, + Symbol* module_version, + Symbol* module_location, + ClassLoaderData* loader_data); + + // only lookup module within loader's module entry table + ModuleEntry* lookup_only(Symbol* name); + + ModuleEntry* bucket(int i) { + return (ModuleEntry*)Hashtable<Symbol*, mtClass>::bucket(i); + } + ModuleEntry** bucket_addr(int i) { + return (ModuleEntry**)Hashtable<Symbol*, mtClass>::bucket_addr(i); + } + + static unsigned int compute_hash(Symbol* name) { return ((name == NULL) ? 0 : (unsigned int)(name->identity_hash())); } + int index_for(Symbol* name) const { return hash_to_index(compute_hash(name)); } + + // purge dead weak references out of reads list + void purge_all_module_reads(); + + // Special handling for unnamed module, one per class loader's ModuleEntryTable + void create_unnamed_module(ClassLoaderData* loader_data); + ModuleEntry* unnamed_module() { return _unnamed_module; } + + // Special handling for java.base + static ModuleEntry* javabase_module() { return _javabase_module; } + static void set_javabase_module(ModuleEntry* java_base) { _javabase_module = java_base; } + static bool javabase_defined() { return ((_javabase_module != NULL) && + (_javabase_module->jlrM_module() != NULL)); } + static void finalize_javabase(Handle jlrM_module, Symbol* version, Symbol* location); + static void patch_javabase_entries(Handle jlrM_handle, TRAPS); + + void print() PRODUCT_RETURN; + void verify(); +}; + +#endif // SHARE_VM_CLASSFILE_MODULEENTRY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/modules.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,988 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +#include "precompiled.hpp" +#include "classfile/classLoader.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "classfile/javaAssertions.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" +#include "classfile/packageEntry.hpp" +#include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/vmSymbols.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/arguments.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/reflection.hpp" +#include "utilities/utf8.hpp" + +static bool verify_module_name(char *module_name) { + if (module_name == NULL) return false; + int len = (int)strlen(module_name); + return (len > 0 && len <= Symbol::max_length() && + UTF8::is_legal_utf8((unsigned char *)module_name, len, false) && + ClassFileParser::verify_unqualified_name(module_name, len, + ClassFileParser::LegalModule)); +} + +bool Modules::verify_package_name(char *package_name) { + if (package_name == NULL) return false; + int len = (int)strlen(package_name); + return (len > 0 && len <= Symbol::max_length() && + UTF8::is_legal_utf8((unsigned char *)package_name, len, false) && + ClassFileParser::verify_unqualified_name(package_name, len, + ClassFileParser::LegalClass)); +} + +static char* get_module_name(oop module, TRAPS) { + oop name_oop = java_lang_reflect_Module::name(module); + if (name_oop == NULL) { + THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), "Null module name"); + } + char* module_name = java_lang_String::as_utf8_string(name_oop); + if (!verify_module_name(module_name)) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid module name: %s", + module_name != NULL ? module_name : "NULL")); + } + return module_name; +} + +static const char* get_module_version(jstring version) { + if (version == NULL) { + return NULL; + } + return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version)); +} + +static ModuleEntryTable* get_module_entry_table(Handle h_loader, TRAPS) { + // This code can be called during start-up, before the classLoader's classLoader data got + // created. So, call register_loader() to make sure the classLoader data gets created. + ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); + return loader_cld->modules(); +} + +static PackageEntryTable* get_package_entry_table(Handle h_loader, TRAPS) { + // This code can be called during start-up, before the classLoader's classLoader data got + // created. So, call register_loader() to make sure the classLoader data gets created. + ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); + return loader_cld->packages(); +} + +static ModuleEntry* get_module_entry(jobject module, TRAPS) { + Handle module_h(THREAD, JNIHandles::resolve(module)); + if (!java_lang_reflect_Module::is_instance(module_h())) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Bad module object"); + } + return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL); +} + +static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) { + ResourceMark rm; + if (package == NULL) return NULL; + const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); + if (package_name == NULL) return NULL; + TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL); + PackageEntryTable* package_entry_table = module_entry->loader()->packages(); + assert(package_entry_table != NULL, "Unexpected null package entry table"); + return package_entry_table->lookup_only(pkg_symbol); +} + +static PackageEntry* get_package_entry_by_name(Symbol* package, + Handle h_loader, + TRAPS) { + if (package != NULL) { + ResourceMark rm; + if (Modules::verify_package_name(package->as_C_string())) { + PackageEntryTable* const package_entry_table = + get_package_entry_table(h_loader, THREAD); + assert(package_entry_table != NULL, "Unexpected null package entry table"); + return package_entry_table->lookup_only(package); + } + } + return NULL; +} + +// Check if -Xpatch:<dirs> was specified. If so, prepend each <dir>/module_name, +// if it exists, to bootpath so boot loader can find the class files. Also, if +// using exploded modules, append <java.home>/modules/module_name, if it exists, +// to bootpath so that its class files can be found by the boot loader. +static void add_to_boot_loader_list(char *module_name, TRAPS) { + // java.base should be handled by argument parsing. + assert(strcmp(module_name, "java.base") != 0, "Unexpected java.base module name"); + char file_sep = os::file_separator()[0]; + size_t module_len = strlen(module_name); + + // If -Xpatch is set then add <patch-dir>/module_name paths. + char** patch_dirs = Arguments::patch_dirs(); + if (patch_dirs != NULL) { + int dir_count = Arguments::patch_dirs_count(); + for (int x = 0; x < dir_count; x++) { + // Really shouldn't be NULL, but check can't hurt + if (patch_dirs[x] != NULL) { + size_t len = strlen(patch_dirs[x]); + if (len != 0) { // Ignore empty strings. + len = len + module_len + 2; + char* prefix_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); + jio_snprintf(prefix_path, len, "%s%c%s", patch_dirs[x], file_sep, module_name); + + // See if Xpatch module path exists. + struct stat st; + if ((os::stat(prefix_path, &st) != 0)) { + FREE_C_HEAP_ARRAY(char, prefix_path); + } else { + { + HandleMark hm; + Handle loader_lock = Handle(THREAD, SystemDictionary::system_loader_lock()); + ObjectLocker ol(loader_lock, THREAD); + ClassLoader::prepend_to_list(prefix_path); + } + if (TraceClassLoading) tty->print_cr("[Opened -Xpatch %s]", prefix_path); + } + } + } + } + } + + // If bootmodules.jimage does not exist then assume exploded form + // ${java.home}/modules/<module-name> + char* path = NULL; + if (!ClassLoader::has_bootmodules_jimage()) { + const char* home = Arguments::get_java_home(); + size_t len = strlen(home) + module_len + 32; + path = NEW_C_HEAP_ARRAY(char, len, mtInternal); + jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name); + struct stat st; + // See if exploded module path exists. + if ((os::stat(path, &st) != 0)) { + FREE_C_HEAP_ARRAY(char, path); + path = NULL; + } + } + + if (path != NULL) { + HandleMark hm; + Handle loader_lock = Handle(THREAD, SystemDictionary::system_loader_lock()); + ObjectLocker ol(loader_lock, THREAD); + + if (TraceClassLoading) tty->print_cr("[Opened %s]", path); + ClassLoader::add_to_list(path); + } +} + +bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) { + return get_package_entry_by_name(package, h_loader, THREAD) != NULL; +} + +static void define_javabase_module(JNIEnv *env, jobject module, jstring version, + jstring location, jobjectArray packages) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + ResourceMark rm(THREAD); + + Handle jlrM_handle(THREAD, JNIHandles::resolve(module)); + + // Obtain java.base's module version + const char* module_version = get_module_version(version); + TempNewSymbol version_symbol; + if (module_version != NULL) { + version_symbol = SymbolTable::new_symbol(module_version, CHECK); + } else { + version_symbol = NULL; + } + + // Obtain java.base's location + const char* module_location = NULL; + TempNewSymbol location_symbol = NULL; + if (location != NULL) { + module_location = + java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); + if (module_location != NULL) { + location_symbol = SymbolTable::new_symbol(module_location, CHECK); + } + } + + objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages)); + objArrayHandle packages_h(THREAD, packages_oop); + int num_packages = (packages_h == NULL ? 0 : packages_h->length()); + + // Check that the list of packages has no duplicates and that the + // packages are syntactically ok. + GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages); + for (int x = 0; x < num_packages; x++) { + oop string_obj = packages_h->obj_at(x); + + if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Bad package name for module: java.base"); + } + char *package_name = java_lang_String::as_utf8_string(string_obj); + if (!Modules::verify_package_name(package_name)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid package name: %s for module: java.base", package_name)); + } + Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); + // append_if_missing() returns FALSE if entry already exists. + if (!pkg_list->append_if_missing(pkg_symbol)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Duplicate package name: %s for module java.base", + package_name)); + } + } + + // Validate java_base's loader is the boot loader. + oop loader = java_lang_reflect_Module::loader(jlrM_handle()); + if (loader != NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader must be the boot class loader"); + } + Handle h_loader = Handle(THREAD, loader); + + // Ensure the boot loader's PackageEntryTable has been created + PackageEntryTable* package_table = get_package_entry_table(h_loader, CHECK); + assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table"); + + // Ensure java.base's ModuleEntry has been created + assert(ModuleEntryTable::javabase_module() != NULL, "No ModuleEntry for java.base"); + + { + MutexLocker m1(Module_lock, THREAD); + + // Verify that all java.base packages created during bootstrapping are in + // pkg_list. If any are not in pkg_list, than a non-java.base class was + // loaded erroneously pre java.base module definition. + package_table->verify_javabase_packages(pkg_list); + + // loop through and add any new packages for java.base + PackageEntry* pkg; + for (int x = 0; x < pkg_list->length(); x++) { + // Some of java.base's packages were added early in bootstrapping, ignore duplicates. + if (package_table->lookup_only(pkg_list->at(x)) == NULL) { + pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_module()); + assert(pkg != NULL, "Unable to create a java.base package entry"); + } + // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of + // the Symbol* that was created above for each package. The refcount was incremented + // by SymbolTable::new_symbol and as well by the PackageEntry creation. + pkg_list->at(x)->decrement_refcount(); + } + + // Finish defining java.base's ModuleEntry + ModuleEntryTable::finalize_javabase(jlrM_handle, version_symbol, location_symbol); + } + + if (TraceModules) { + tty->print("[define_javabase_module(): Definition of module: java.base, version: %s, location: %s, ", + module_version != NULL ? module_version : "NULL", + module_location != NULL ? module_location : "NULL"); + tty->print_cr("package #: %d]", pkg_list->length()); + + // packages defined to java.base + for (int x = 0; x < pkg_list->length(); x++) { + tty->print_cr("[define_javabase_module(): creation of package %s for module java.base]", + (pkg_list->at(x))->as_C_string()); + } + } + + // Patch any previously loaded classes' module field with java.base's jlr.Module. + ModuleEntryTable::patch_javabase_entries(jlrM_handle, CHECK); +} + +void Modules::define_module(JNIEnv *env, jobject module, jstring version, + jstring location, jobjectArray packages) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + ResourceMark rm(THREAD); + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); + } + Handle jlrM_handle(THREAD, JNIHandles::resolve(module)); + if (!java_lang_reflect_Module::is_subclass(jlrM_handle->klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is not a subclass of java.lang.reflect.Module"); + } + + char* module_name = get_module_name(jlrM_handle(), CHECK); + if (module_name == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Module name cannot be null"); + } + + // Special handling of java.base definition + if (strcmp(module_name, "java.base") == 0) { + define_javabase_module(env, module, version, location, packages); + return; + } + + const char* module_version = get_module_version(version); + + objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages)); + objArrayHandle packages_h(THREAD, packages_oop); + int num_packages = (packages_h == NULL ? 0 : packages_h->length()); + + // Check that the list of packages has no duplicates and that the + // packages are syntactically ok. + GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages); + for (int x = 0; x < num_packages; x++) { + oop string_obj = packages_h->obj_at(x); + + if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Bad package name for module: %s", module_name)); + } + char *package_name = java_lang_String::as_utf8_string(string_obj); + if (!verify_package_name(package_name)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid package name: %s for module: %s", + package_name, module_name)); + } + Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); + // append_if_missing() returns FALSE if entry already exists. + if (!pkg_list->append_if_missing(pkg_symbol)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Duplicate package name: %s for module %s", + package_name, module_name)); + } + } + + oop loader = java_lang_reflect_Module::loader(jlrM_handle()); + // Make sure loader is not the sun.reflect.DelegatingClassLoader. + if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader is an invalid delegating class loader"); + } + Handle h_loader = Handle(THREAD, loader); + + // Check that loader is a subclass of java.lang.ClassLoader. + if (loader != NULL && !java_lang_ClassLoader::is_subclass(h_loader->klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader is not a subclass of java.lang.ClassLoader"); + } + + ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK); + assert(module_table != NULL, "module entry table shouldn't be null"); + + // Create symbol* entry for module name. + TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK); + + int dupl_pkg_index = -1; + bool dupl_modules = false; + + // Create symbol* entry for module version. + TempNewSymbol version_symbol; + if (module_version != NULL) { + version_symbol = SymbolTable::new_symbol(module_version, CHECK); + } else { + version_symbol = NULL; + } + + // Create symbol* entry for module location. + const char* module_location = NULL; + TempNewSymbol location_symbol = NULL; + if (location != NULL) { + module_location = + java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); + if (module_location != NULL) { + location_symbol = SymbolTable::new_symbol(module_location, CHECK); + } + } + + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(h_loader()); + assert(loader_data != NULL, "class loader data shouldn't be null"); + + PackageEntryTable* package_table = NULL; + { + MutexLocker ml(Module_lock, THREAD); + + if (num_packages > 0) { + package_table = get_package_entry_table(h_loader, CHECK); + assert(package_table != NULL, "Missing package_table"); + + // Check that none of the packages exist in the class loader's package table. + for (int x = 0; x < pkg_list->length(); x++) { + if (package_table->lookup_only(pkg_list->at(x)) != NULL) { + // This could be because the module was already defined. If so, + // report that error instead of the package error. + if (module_table->lookup_only(module_symbol) != NULL) { + dupl_modules = true; + } else { + dupl_pkg_index = x; + } + break; + } + } + } // if (num_packages > 0)... + + // Add the module and its packages. + if (!dupl_modules && dupl_pkg_index == -1) { + // Create the entry for this module in the class loader's module entry table. + + ModuleEntry* module_entry = module_table->locked_create_entry_or_null(jlrM_handle, module_symbol, + version_symbol, location_symbol, loader_data); + + if (module_entry == NULL) { + dupl_modules = true; + } else { + if (TraceModules) { + tty->print("[define_module(): Definition of module: %s, version: %s, location: %s, ", + module_name, module_version != NULL ? module_version : "NULL", + module_location != NULL ? module_location : "NULL"); + loader_data->print_value(); + tty->print_cr(", package #: %d]", pkg_list->length()); + } + + // Add the packages. + assert(pkg_list->length() == 0 || package_table != NULL, "Bad package table"); + PackageEntry* pkg; + for (int y = 0; y < pkg_list->length(); y++) { + pkg = package_table->locked_create_entry_or_null(pkg_list->at(y), module_entry); + assert(pkg != NULL, "Unable to create a module's package entry"); + + if (TraceModules) { + tty->print_cr("[define_module(): creation of package %s for module %s]", + (pkg_list->at(y))->as_C_string(), module_name); + } + + // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of + // the Symbol* that was created above for each package. The refcount was incremented + // by SymbolTable::new_symbol and as well by the PackageEntry creation. + pkg_list->at(y)->decrement_refcount(); + } + + // Store pointer to ModuleEntry record in java.lang.reflect.Module object. + java_lang_reflect_Module::set_module_entry(jlrM_handle(), module_entry); + } + } + } // Release the lock + + // any errors ? + if (dupl_modules) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Module %s is already defined", module_name)); + } + if (dupl_pkg_index != -1) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package %s for module %s already exists for class loader", + pkg_list->at(dupl_pkg_index)->as_C_string(), module_name)); + } + + if (loader == NULL && !Universe::is_module_initialized()) { + // Now that the module is defined, if it is in the bootloader, make sure that + // its classes can be found. Check if -Xpatch:<path> was specified. If + // so prepend <path>/module_name, if it exists, to bootpath. Also, if using + // exploded modules, prepend <java.home>/modules/module_name, if it exists, + // to bootpath. + add_to_boot_loader_list(module_name, CHECK); + } +} + +void Modules::set_bootloader_unnamed_module(JNIEnv *env, jobject module) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + ResourceMark rm(THREAD); + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); + } + Handle jlrM_handle(THREAD, JNIHandles::resolve(module)); + if (!java_lang_reflect_Module::is_subclass(jlrM_handle->klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is not a subclass of java.lang.reflect.Module"); + } + + // Ensure that this is an unnamed module + oop name = java_lang_reflect_Module::name(jlrM_handle()); + if (name != NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "boot loader's unnamed module's java.lang.reflect.Module has a name"); + } + + // Validate java_base's loader is the boot loader. + oop loader = java_lang_reflect_Module::loader(jlrM_handle()); + if (loader != NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader must be the boot class loader"); + } + Handle h_loader = Handle(THREAD, loader); + + if (TraceModules) { + tty->print_cr("[set_bootloader_unnamed_module(): recording unnamed module for boot loader]"); + } + + // Ensure the boot loader's PackageEntryTable has been created + ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK); + + // Set java.lang.reflect.Module for the boot loader's unnamed module + ModuleEntry* unnamed_module = module_table->unnamed_module(); + assert(unnamed_module != NULL, "boot loader's unnamed ModuleEntry not defined"); + unnamed_module->set_jlrM_module(ClassLoaderData::the_null_class_loader_data()->add_handle(jlrM_handle)); + // Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module object. + java_lang_reflect_Module::set_module_entry(jlrM_handle(), unnamed_module); +} + +void Modules::add_module_exports(JNIEnv *env, jobject from_module, jstring package, jobject to_module) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + + if (package == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "package is null"); + } + if (from_module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "from_module is null"); + } + ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK); + if (from_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "from_module cannot be found"); + } + + // All packages in unnamed are exported by default. + if (!from_module_entry->is_named()) return; + + ModuleEntry* to_module_entry; + if (to_module == NULL) { + to_module_entry = NULL; // It's an unqualified export. + } else { + to_module_entry = get_module_entry(to_module, CHECK); + if (to_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "to_module is invalid"); + } + } + + PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK); + + if (package_entry == NULL) { + ResourceMark rm; + const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package %s not found in from_module %s", + package_name != NULL ? package_name : "", + from_module_entry->name()->as_C_string())); + } + if (package_entry->module() != from_module_entry) { + ResourceMark rm; + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package: %s found in module %s, not in from_module: %s", + package_entry->name()->as_C_string(), + package_entry->module()->name()->as_C_string(), + from_module_entry->name()->as_C_string())); + } + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[add_module_exports(): package %s in module %s is exported to module %s]", + package_entry->name()->as_C_string(), + from_module_entry->name()->as_C_string(), + to_module_entry == NULL ? "NULL" : + to_module_entry->is_named() ? + to_module_entry->name()->as_C_string() : UNNAMED_MODULE); + } + + // If this is a qualified export, make sure the entry has not already been exported + // unqualifiedly. + if (to_module_entry != NULL && package_entry->is_unqual_exported()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Bad qualifed export, package %s in module %s is already unqualifiedly exported", + package_entry->name()->as_C_string(), + from_module_entry->name()->as_C_string())); + } + + // Do nothing if modules are the same. + if (from_module_entry != to_module_entry) { + package_entry->set_exported(to_module_entry); + } +} + + +void Modules::add_module_exports_qualified(JNIEnv *env, jobject from_module, jstring package, jobject to_module) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + if (to_module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "to_module is null"); + } + add_module_exports(env, from_module, package, to_module); +} + +void Modules::add_reads_module(JNIEnv *env, jobject from_module, jobject to_module) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + + if (from_module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "from_module is null"); + } + + ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK); + if (from_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "from_module is not valid"); + } + + ModuleEntry* to_module_entry; + if (to_module != NULL) { + to_module_entry = get_module_entry(to_module, CHECK); + if (to_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "to_module is invalid"); + } + } else { + to_module_entry = NULL; + } + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[add_reads_module(): Adding read from module %s to module %s]", + from_module_entry->is_named() ? from_module_entry->name()->as_C_string() : UNNAMED_MODULE, + to_module_entry == NULL ? "all unnamed" : + (to_module_entry->is_named() ? to_module_entry->name()->as_C_string() : UNNAMED_MODULE)); + } + + // if modules are the same or if from_module is unnamed then no need to add the read. + if (from_module_entry != to_module_entry && from_module_entry->is_named()) { + from_module_entry->add_read(to_module_entry); + } +} + +jboolean Modules::can_read_module(JNIEnv *env, jobject asking_module, jobject target_module) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + + if (asking_module == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "asking_module is null", JNI_FALSE); + } + + ModuleEntry* asking_module_entry = get_module_entry(asking_module, CHECK_false); + if (asking_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "asking_module is invalid", JNI_FALSE); + } + + // Calling can_read_unnamed() with NULL tests if a module is loose. + if (target_module == NULL) { + return asking_module_entry->can_read_unnamed(); + } + + ModuleEntry* target_module_entry = get_module_entry(target_module, CHECK_false); + if (target_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "target_module is invalid", JNI_FALSE); + } + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[can_read_module(): module %s trying to read module %s, allowed = %s", + asking_module_entry->is_named() ? + asking_module_entry->name()->as_C_string() : UNNAMED_MODULE, + target_module_entry->is_named() ? + target_module_entry->name()->as_C_string() : UNNAMED_MODULE, + BOOL_TO_STR(asking_module_entry == target_module_entry || + (asking_module_entry->can_read_unnamed() && + !target_module_entry->is_named()) || + asking_module_entry->can_read(target_module_entry))); + } + + // Return true if: + // 1. the modules are the same, or + // 2. the asking_module is unnamed (because unnamed modules read everybody), or + // 3. the asking_module is loose and the target module is unnamed, or + // 4. if can_read() returns true. + if (asking_module_entry == target_module_entry || + (asking_module_entry->can_read_unnamed() && !target_module_entry->is_named())) { + return true; + } + return asking_module_entry->can_read(target_module_entry); +} + +jboolean Modules::is_exported_to_module(JNIEnv *env, jobject from_module, jstring package, jobject to_module) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + + if (package == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "package is null", JNI_FALSE); + } + if (from_module == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "from_module is null", JNI_FALSE); + } + ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK_false); + if (from_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "from_module is invalid", JNI_FALSE); + } + ModuleEntry* to_module_entry; + if (to_module == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "to_module is null", JNI_FALSE); + } + to_module_entry = get_module_entry(to_module, CHECK_false); + if (to_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "to_module is invalid", JNI_FALSE); + } + + PackageEntry *package_entry = get_package_entry(from_module_entry, package, + CHECK_false); + if (package_entry == NULL) { + ResourceMark rm; + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package not found in from_module: %s", + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE), + JNI_FALSE); + } + if (package_entry->module() != from_module_entry) { + ResourceMark rm; + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package: %s found in module %s, not in from_module: %s", + package_entry->name()->as_C_string(), + package_entry->module()->is_named() ? + package_entry->module()->name()->as_C_string() : UNNAMED_MODULE, + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE), + JNI_FALSE); + } + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[is_exported_to_module: package %s from module %s checking if exported to module %s, exported? = %s", + package_entry->name()->as_C_string(), + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE, + to_module_entry->is_named() ? + to_module_entry->name()->as_C_string() : UNNAMED_MODULE, + BOOL_TO_STR(!from_module_entry->is_named() || + package_entry->is_unqual_exported() || + from_module_entry == to_module_entry || + package_entry->is_qexported_to(to_module_entry))); + } + + // Return true if: + // 1. from_module is unnamed because unnamed modules export all their packages (by default), or + // 2. if the package is unqualifiedly exported, or + // 3. if the modules are the same, or + // 4. if the package is exported to to_module + return (!from_module_entry->is_named() || + package_entry->is_unqual_exported() || + from_module_entry == to_module_entry || + package_entry->is_qexported_to(to_module_entry)); +} + +// This method is called by JFR and JNI. +jobject Modules::get_module(JNIEnv *env, jclass clazz) { + assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module before java.base is defined"); + + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + if (clazz == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "class is null", JNI_FALSE); + } + oop mirror = JNIHandles::resolve_non_null(clazz); + if (mirror == NULL) { + if (TraceModules) { + tty->print_cr("[get_module(): no mirror, returning NULL]"); + } + return NULL; + } + if (!java_lang_Class::is_instance(mirror)) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Invalid class", JNI_FALSE); + } + + Klass* klass = NULL; + oop module; + if (java_lang_Class::is_primitive(mirror)) { + // Return java.base module + module = JNIHandles::resolve(ModuleEntryTable::javabase_module()->jlrM_module()); + } else { + Klass* klass = java_lang_Class::as_Klass(mirror); + assert(klass != NULL, "Null Klass"); + assert(klass->is_instance_klass() || klass->is_objArray_klass() || + klass->is_typeArray_klass(), "Bad Klass"); + + if (klass->is_objArray_klass()) { + ObjArrayKlass* obj_arr_klass = ObjArrayKlass::cast(klass); + klass = obj_arr_klass->bottom_klass(); + mirror = klass->java_mirror(); + } + if (klass->is_instance_klass()) { + module = java_lang_Class::module(mirror); + assert(module != NULL, "Unexpected NULL module"); + } else { + // Return java.base module + module = JNIHandles::resolve(ModuleEntryTable::javabase_module()->jlrM_module()); + } + } + + if (TraceModules) { + ResourceMark rm; + oop module_name = java_lang_reflect_Module::name(module); + if (module_name != NULL) { + tty->print("[get_module(): module "); + java_lang_String::print(module_name, tty); + } else { + tty->print("[get_module(): Unamed Module"); + } + if (klass != NULL) { + tty->print_cr(" for class %s]", klass->external_name()); + } else { + tty->print_cr(" for primitive class]"); + } + } + + assert(java_lang_reflect_Module::is_subclass(module->klass()), "Module is not a java.lang.reflect.Module"); + return JNIHandles::make_local(env, module); +} + +// This method is called by JFR. +jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) { + const PackageEntry* const pkg_entry = + get_package_entry_by_name(package_name, h_loader, THREAD); + const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL); + + if (module_entry != NULL && + module_entry->is_named() && + module_entry->jlrM_module() != NULL) { + return JNIHandles::make_local(THREAD, JNIHandles::resolve(module_entry->jlrM_module())); + } + + return NULL; +} + +void Modules::add_module_package(JNIEnv *env, jobject module, jstring package) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + ResourceMark rm; + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "module is null"); + } + if (package == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "package is null"); + } + ModuleEntry* module_entry = get_module_entry(module, CHECK); + if (module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is invalid"); + } + if (!module_entry->is_named()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module cannot be an unnamed module"); + } + char *package_name = java_lang_String::as_utf8_string( + JNIHandles::resolve_non_null(package)); + if (package_name == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad package"); + } + if (!verify_package_name(package_name)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid package name: %s", package_name)); + } + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[add_module_package(): Adding package %s to module %s]", + package_name, module_entry->name()->as_C_string()); + } + + TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); + PackageEntryTable* package_table = module_entry->loader()->packages(); + assert(package_table != NULL, "Missing package_table"); + + bool pkg_exists = false; + { + MutexLocker ml(Module_lock, THREAD); + + // Check that the package does not exist in the class loader's package table. + if (!package_table->lookup_only(pkg_symbol)) { + PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry); + assert(pkg != NULL, "Unable to create a module's package entry"); + } else { + pkg_exists = true; + } + } + if (pkg_exists) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package %s already exists for class loader", package_name)); + } +} + +// Export package in module to all unnamed modules. +void Modules::add_module_exports_to_all_unnamed(JNIEnv *env, jobject module, jstring package) { + JavaThread *THREAD = JavaThread::thread_from_jni_environment(env); + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "module is null"); + } + if (package == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "package is null"); + } + ModuleEntry* module_entry = get_module_entry(module, CHECK); + if (module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is invalid"); + } + if (!module_entry->is_named()) { // TBD: Should this be a no-op instead of an IAE ? + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module cannot be unnamed"); + } + + PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK); + if (package_entry == NULL) { + ResourceMark rm; + const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package %s not found in module %s", + package_name != NULL ? package_name : "", + module_entry->name()->as_C_string())); + } + if (package_entry->module() != module_entry) { + ResourceMark rm; + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package: %s found in module %s, not in module: %s", + package_entry->name()->as_C_string(), + package_entry->module()->name()->as_C_string(), + module_entry->name()->as_C_string())); + } + + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[add_module_exports_to_all_unnamed(): package %s in module %s is exported to all unnamed modules]", + package_entry->name()->as_C_string(), + module_entry->name()->as_C_string()); + } + + // Mark package as exported to all unnamed modules, unless already + // unqualifiedly exported. + if (!package_entry->is_unqual_exported()) { + package_entry->set_is_exported_allUnnamed(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/modules.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,143 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +#ifndef SHARE_VM_CLASSFILE_MODULES_HPP +#define SHARE_VM_CLASSFILE_MODULES_HPP + +#include "memory/allocation.hpp" +#include "runtime/handles.hpp" + +class Symbol; + +class Modules : AllStatic { + +public: + // define_module defines a module containing the specified packages. It binds the + // module to its class loader by creating the ModuleEntry record in the + // ClassLoader's ModuleEntry table, and creates PackageEntry records in the class + // loader's PackageEntry table. As in JVM_DefineClass the jstring format for all + // package names must use "/" and not "." + // + // IllegalArgumentExceptions are thrown for the following : + // * Module's Class loader is not a subclass of java.lang.ClassLoader + // * Module's Class loader already has a module with that name + // * Module's Class loader has already defined types for any of the module's packages + // * Module_name is syntactically bad + // * Packages contains an illegal package name + // * Packages contains a duplicate package name + // * A package already exists in another module for this class loader + // * Module is an unnamed module + // NullPointerExceptions are thrown if module is null. + static void define_module(JNIEnv *env, jobject module, jstring version, + jstring location, jobjectArray packages); + + // Provides the java.lang.reflect.Module for the unnamed module defined + // to the boot loader. + // + // IllegalArgumentExceptions are thrown for the following : + // * Module has a name + // * Module is not a subclass of java.lang.reflect.Module + // * Module's class loader is not the boot loader + // NullPointerExceptions are thrown if module is null. + static void set_bootloader_unnamed_module(JNIEnv *env, jobject module); + + // This either does a qualified export of package in module from_module to module + // to_module or, if to_module is null, does an unqualified export of package. + // The format for the package name must use "/' not ".". + // + // Error conditions causing IlegalArgumentException to be throw : + // * Module from_module does not exist + // * Module to_module is not null and does not exist + // * Package is not syntactically correct + // * Package is not defined for from_module's class loader + // * Package is not in module from_module. + static void add_module_exports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + + // This does a qualified export of package in module from_module to module + // to_module. The format for the package name must use "/' not ".". + // + // Error conditions causing IlegalArgumentException to be throw : + // * Module from_module does not exist + // * Module to_module does not exist + // * Package is not syntactically correct + // * Package is not defined for from_module's class loader + // * Package is not in module from_module. + static void add_module_exports_qualified(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + + // add_reads_module adds module to_module to the list of modules that from_module + // can read. If from_module is the same as to_module then this is a no-op. + // If to_module is null then from_module is marked as a loose module (meaning that + // from_module can read all current and future unnamed modules). + // An IllegalArgumentException is thrown if from_module is null or either (non-null) + // module does not exist. + static void add_reads_module(JNIEnv *env, jobject from_module, jobject to_module); + + // can_read_module returns TRUE if module asking_module can read module target_module, + // or if they are the same module, or if the asking_module is loose and target_module + // is null. + // + // Throws IllegalArgumentException if: + // * either asking_module or target_module is not a java.lang.reflect.Module + static jboolean can_read_module(JNIEnv *env, jobject asking_module, jobject target_module); + + // If package is valid then this returns TRUE if module from_module exports + // package to module to_module, if from_module and to_module are the same + // module, or if package is exported without qualification. + // + // IllegalArgumentException is throw if: + // * Either to_module or from_module does not exist + // * package is syntactically incorrect + // * package is not in from_module + static jboolean is_exported_to_module(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + + // Return the java.lang.reflect.Module object for this class object. + static jobject get_module(JNIEnv *env, jclass clazz); + + // If package is defined by loader, return the + // java.lang.reflect.Module object for the module in which the package is defined. + // Returns NULL if package is invalid or not defined by loader. + static jobject get_module(Symbol* package_name, Handle h_loader, TRAPS); + + // This adds package to module. + // It throws IllegalArgumentException if: + // * Module is bad + // * Module is unnamed + // * Package is not syntactically correct + // * Package is already defined for module's class loader. + static void add_module_package(JNIEnv *env, jobject module, jstring package); + + // Marks the specified package as exported to all unnamed modules. + // If either module or package is null then NullPointerException is thrown. + // If module or package is bad, or module is unnamed, or package is not in + // module then IllegalArgumentException is thrown. + static void add_module_exports_to_all_unnamed(JNIEnv *env, jobject module, jstring package); + + // Return TRUE if package_name is syntactically valid, false otherwise. + static bool verify_package_name(char *package_name); + + // Return TRUE iff package is defined by loader + static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS); +}; + +#endif // SHARE_VM_CLASSFILE_MODULES_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/packageEntry.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" +#include "memory/resourceArea.hpp" +#include "oops/symbol.hpp" +#include "runtime/handles.inline.hpp" +#include "trace/traceMacros.hpp" +#include "utilities/events.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.inline.hpp" + +// Return true if this package is exported to m. +bool PackageEntry::is_qexported_to(ModuleEntry* m) const { + assert(m != NULL, "No module to lookup in this package's qualified exports list"); + MutexLocker m1(Module_lock); + if (!_is_exported) { + return false; + } else if (_is_exported_allUnnamed && !m->is_named()) { + return true; + } else if (_qualified_exports == NULL) { + return false; + } else { + return _qualified_exports->contains(m); + } +} + +// Add a module to the package's qualified export list. +void PackageEntry::add_qexport(ModuleEntry* m) { + assert_locked_or_safepoint(Module_lock); + assert(_is_exported == true, "Adding a qualified export to a package that is not exported"); + if (_qualified_exports == NULL) { + // Lazily create a package's qualified exports list. + // Initial size is 43, do not anticipate export lists to be large. + _qualified_exports = new (ResourceObj::C_HEAP, mtClass) GrowableArray<ModuleEntry*>(43, true); + } + _qualified_exports->append_if_missing(m); +} + +// Set the package's exported state based on the value of the ModuleEntry. +void PackageEntry::set_exported(ModuleEntry* m) { + MutexLocker m1(Module_lock); + if (is_unqual_exported()) { + // An exception could be thrown, but choose to simply ignore. + // Illegal to convert an unqualified exported package to be qualifiedly exported + return; + } + + if (m == NULL) { + // NULL indicates the package is being unqualifiedly exported + if (_is_exported && _qualified_exports != NULL) { + // Legit to transition a package from being qualifiedly exported + // to unqualified. Clean up the qualified lists at the next + // safepoint. + _exported_pending_delete = _qualified_exports; + } + + // Mark package as unqualifiedly exported + set_unqual_exported(); + + } else { + // Add the exported module + _is_exported = true; + add_qexport(m); + } +} + +// Remove dead module entries within the package's exported list. +void PackageEntry::purge_qualified_exports() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + if (_qualified_exports != NULL) { + // Go backwards because this removes entries that are dead. + int len = _qualified_exports->length(); + for (int idx = len - 1; idx >= 0; idx--) { + ModuleEntry* module_idx = _qualified_exports->at(idx); + ClassLoaderData* cld = module_idx->loader(); + if (cld->is_unloading()) { + _qualified_exports->delete_at(idx); + } + } + } +} + +void PackageEntry::delete_qualified_exports() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + if (_exported_pending_delete != NULL) { + // If a transition occurred from qualified to unqualified, the _qualified_exports + // field should have been NULL'ed out. + assert(_qualified_exports == NULL, "Package's exported pending delete, exported list should not be active"); + delete _exported_pending_delete; + } + + if (_qualified_exports != NULL) { + delete _qualified_exports; + } + + _exported_pending_delete = NULL; + _qualified_exports = NULL; +} + +PackageEntryTable::PackageEntryTable(int table_size) + : Hashtable<Symbol*, mtClass>(table_size, sizeof(PackageEntry)) +{ +} + +PackageEntryTable::~PackageEntryTable() { + assert_locked_or_safepoint(Module_lock); + + // Walk through all buckets and all entries in each bucket, + // freeing each entry. + for (int i = 0; i < table_size(); ++i) { + for (PackageEntry* p = bucket(i); p != NULL;) { + PackageEntry* to_remove = p; + // read next before freeing. + p = p->next(); + + // Clean out the C heap allocated qualified exports list first before freeing the entry + to_remove->delete_qualified_exports(); + to_remove->name()->decrement_refcount(); + + // Unlink from the Hashtable prior to freeing + unlink_entry(to_remove); + FREE_C_HEAP_ARRAY(char, to_remove); + } + } + assert(number_of_entries() == 0, "should have removed all entries"); + assert(new_entry_free_list() == NULL, "entry present on PackageEntryTable's free list"); + free_buckets(); +} + +PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, ModuleEntry* module) { + assert_locked_or_safepoint(Module_lock); + PackageEntry* entry = (PackageEntry*) NEW_C_HEAP_ARRAY2(char, entry_size(), mtClass, CURRENT_PC); + + // Initialize everything BasicHashtable would + entry->set_next(NULL); + entry->set_hash(hash); + entry->set_literal(name); + + TRACE_INIT_PACKAGE_ID(entry); + + // Initialize fields specific to a PackageEntry + entry->init(); + entry->name()->increment_refcount(); + if (!module->is_named()) { + // Set the exported state to true because all packages + // within the unnamed module are unqualifiedly exported + entry->set_exported(true); + } + entry->set_module(module); + return entry; +} + +void PackageEntryTable::add_entry(int index, PackageEntry* new_entry) { + assert_locked_or_safepoint(Module_lock); + Hashtable<Symbol*, mtClass>::add_entry(index, (HashtableEntry<Symbol*, mtClass>*)new_entry); +} + +// Create package in loader's package entry table and return the entry. +// If entry already exists, return null. Assume Module lock was taken by caller. +PackageEntry* PackageEntryTable::locked_create_entry_or_null(Symbol* name, ModuleEntry* module) { + assert_locked_or_safepoint(Module_lock); + // Check if package already exists. Return NULL if it does. + if (lookup_only(name) != NULL) { + return NULL; + } else { + PackageEntry* entry = new_entry(compute_hash(name), name, module); + add_entry(index_for(name), entry); + return entry; + } +} + +PackageEntry* PackageEntryTable::lookup(Symbol* name, ModuleEntry* module) { + PackageEntry* p = lookup_only(name); + if (p != NULL) { + return p; + } else { + // If not found, add to table. Grab the PackageEntryTable lock first. + MutexLocker ml(Module_lock); + + // Since look-up was done lock-free, we need to check if another thread beat + // us in the race to insert the package. + PackageEntry* test = lookup_only(name); + if (test != NULL) { + // A race occurred and another thread introduced the package. + return test; + } else { + assert(module != NULL, "module should never be null"); + PackageEntry* entry = new_entry(compute_hash(name), name, module); + add_entry(index_for(name), entry); + return entry; + } + } +} + +PackageEntry* PackageEntryTable::lookup_only(Symbol* name) { + int index = index_for(name); + for (PackageEntry* p = bucket(index); p != NULL; p = p->next()) { + if (p->name()->fast_compare(name) == 0) { + return p; + } + } + return NULL; +} + +// Called when a define module for java.base is being processed. +// Verify the packages loaded thus far are in java.base's package list. +void PackageEntryTable::verify_javabase_packages(GrowableArray<Symbol*> *pkg_list) { + for (int i = 0; i < table_size(); i++) { + for (PackageEntry* entry = bucket(i); + entry != NULL; + entry = entry->next()) { + ModuleEntry* m = entry->module(); + Symbol* module_name = (m == NULL ? NULL : m->name()); + if (module_name != NULL && + (module_name->fast_compare(vmSymbols::java_base()) == 0) && + !pkg_list->contains(entry->name())) { + ResourceMark rm; + vm_exit_during_initialization("A non-java.base package was loaded prior to module system initialization", entry->name()->as_C_string()); + } + } + } + +} + +// Remove dead entries from all packages' exported list +void PackageEntryTable::purge_all_package_exports() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + for (int i = 0; i < table_size(); i++) { + for (PackageEntry* entry = bucket(i); + entry != NULL; + entry = entry->next()) { + if (entry->exported_pending_delete()) { + // exported list is pending deletion due to a transition + // from qualified to unqualified + entry->delete_qualified_exports(); + } else if (entry->is_qual_exported()) { + entry->purge_qualified_exports(); + } + } + } +} + +#ifndef PRODUCT +void PackageEntryTable::print() { + tty->print_cr("Package Entry Table (table_size=%d, entries=%d)", + table_size(), number_of_entries()); + for (int i = 0; i < table_size(); i++) { + for (PackageEntry* probe = bucket(i); + probe != NULL; + probe = probe->next()) { + probe->print(); + } + } +} + +void PackageEntry::print() { + ResourceMark rm; + tty->print_cr("package entry "PTR_FORMAT" name %s module %s is_exported %d is_exported_allUnnamed: %d next "PTR_FORMAT, + p2i(this), name()->as_C_string(), + (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE), + _is_exported, _is_exported_allUnnamed, p2i(next())); +} +#endif + +void PackageEntryTable::verify() { + int element_count = 0; + for (int index = 0; index < table_size(); index++) { + for (PackageEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + probe->verify(); + element_count++; + } + } + guarantee(number_of_entries() == element_count, + "Verify of Package Entry Table failed"); + debug_only(verify_lookup_length((double)number_of_entries() / table_size())); +} + +void PackageEntry::verify() { + guarantee(name() != NULL, "A package entry must have a corresponding symbol name."); +} + +// iteration of qualified exports +void PackageEntry::package_exports_do(ModuleClosure* const f) { + assert_locked_or_safepoint(Module_lock); + assert(f != NULL, "invariant"); + + if (is_qual_exported()) { + int qe_len = _qualified_exports->length(); + + for (int i = 0; i < qe_len; ++i) { + f->do_module(_qualified_exports->at(i)); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/classfile/packageEntry.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP +#define SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP + +#include "classfile/moduleEntry.hpp" +#include "oops/symbol.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.hpp" + +// A PackageEntry basically represents a Java package. It contains: +// - Symbol* containing the package's name. +// - ModuleEntry* for this package's containing module. +// - a flag indicating if package is exported, either qualifiedly or +// unqualifiedly. +// - a flag indicating if this package is exported to all unnamed modules. +// - a growable array containing other module entries that this +// package is exported to. +// +// Packages that are: +// - not exported: _qualified_exports = NULL && _is_exported is false +// - qualified exports: (_qualified_exports != NULL || _is_exported_allUnnamed is true) && _is_exported is true +// - unqualified exports: (_qualified_exports = NULL && _is_exported_allUnnamed is false) && _is_exported is true +// +class PackageEntry : public HashtableEntry<Symbol*, mtClass> { +private: + ModuleEntry* _module; + bool _is_exported; + bool _is_exported_allUnnamed; + GrowableArray<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint + GrowableArray<ModuleEntry*>* _qualified_exports; + TRACE_DEFINE_TRACE_ID_FIELD; + +public: + void init() { + _module = NULL; + _is_exported = false; + _is_exported_allUnnamed = false; + _exported_pending_delete = NULL; + _qualified_exports = NULL; + } + + // package name + Symbol* name() const { return literal(); } + void set_name(Symbol* n) { set_literal(n); } + + // the module containing the package definition + ModuleEntry* module() const { return _module; } + void set_module(ModuleEntry* m) { _module = m; } + + // package's export state + bool is_exported() const { return _is_exported; } // qualifiedly or unqualifiedly exported + bool is_qual_exported() const { + return (_is_exported && (_qualified_exports != NULL || _is_exported_allUnnamed)); + } + bool is_unqual_exported() const { + return (_is_exported && (_qualified_exports == NULL && !_is_exported_allUnnamed)); + } + void set_unqual_exported() { + _is_exported = true; + _is_exported_allUnnamed = false; + _qualified_exports = NULL; + } + bool exported_pending_delete() const { return (_exported_pending_delete != NULL); } + + void set_exported(bool e) { _is_exported = e; } + void set_exported(ModuleEntry* m); + + void set_is_exported_allUnnamed() { + if (!is_unqual_exported()) { + _is_exported_allUnnamed = true; + _is_exported = true; + } + } + bool is_exported_allUnnamed() const { + assert(_is_exported || !_is_exported_allUnnamed, + "is_allUnnamed set without is_exported being set"); + return _is_exported_allUnnamed; + } + + // returns true if the package is defined in the unnamed module + bool in_unnamed_module() const { return !_module->is_named(); } + + // returns true if the package specifies m as a qualified export + bool is_qexported_to(ModuleEntry* m) const; + + // add the module to the package's qualified exports + void add_qexport(ModuleEntry* m); + + PackageEntry* next() const { + return (PackageEntry*)HashtableEntry<Symbol*, mtClass>::next(); + } + + PackageEntry** next_addr() { + return (PackageEntry**)HashtableEntry<Symbol*, mtClass>::next_addr(); + } + + // iteration of qualified exports + void package_exports_do(ModuleClosure* const f); + + TRACE_DEFINE_TRACE_ID_METHODS; + + // Purge dead weak references out of exported list when any given class loader is unloaded. + void purge_qualified_exports(); + void delete_qualified_exports(); + + void print() PRODUCT_RETURN; + void verify(); +}; + +// The PackageEntryTable is a Hashtable containing a list of all packages defined +// by a particular class loader. Each package is represented as a PackageEntry node. +// The PackageEntryTable's lookup is lock free. +// +class PackageEntryTable : public Hashtable<Symbol*, mtClass> { + friend class VMStructs; +public: + enum Constants { + _packagetable_entry_size = 1009 // number of entries in package entry table + }; + +private: + PackageEntry* new_entry(unsigned int hash, Symbol* name, ModuleEntry* module); + void add_entry(int index, PackageEntry* new_entry); + +public: + PackageEntryTable(int table_size); + ~PackageEntryTable(); + + int entry_size() const { return BasicHashtable<mtClass>::entry_size(); } + + // Create package in loader's package entry table and return the entry. + // If entry already exists, return null. Assume Module lock was taken by caller. + PackageEntry* locked_create_entry_or_null(Symbol* name, ModuleEntry* module); + + // lookup Package with loader's package entry table, if not found add + PackageEntry* lookup(Symbol* name, ModuleEntry* module); + + // only lookup Package within loader's package entry table + PackageEntry* lookup_only(Symbol* Package); + + PackageEntry* bucket(int i) { + return (PackageEntry*)Hashtable<Symbol*, mtClass>::bucket(i); + } + + PackageEntry** bucket_addr(int i) { + return (PackageEntry**)Hashtable<Symbol*, mtClass>::bucket_addr(i); + } + + static unsigned int compute_hash(Symbol* name) { + return (unsigned int)(name->identity_hash()); + } + + int index_for(Symbol* name) const { + return hash_to_index(compute_hash(name)); + } + + void verify_javabase_packages(GrowableArray<Symbol*> *pkg_list); + + // purge dead weak references out of exported list + void purge_all_package_exports(); + + void print() PRODUCT_RETURN; + void verify(); +}; + +#endif // SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP
--- a/src/share/vm/classfile/sharedPathsMiscInfo.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -111,7 +111,7 @@ switch (type) { case BOOT: if (os::file_name_strcmp(path, Arguments::get_sysclasspath()) != 0) { - return fail("[BOOT classpath mismatch, actual: -Dsun.boot.class.path=", Arguments::get_sysclasspath()); + return fail("[BOOT classpath mismatch, actual: -Djdk.boot.class.path.append=", Arguments::get_sysclasspath()); } break; case NON_EXIST: // fall-through
--- a/src/share/vm/classfile/sharedPathsMiscInfo.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/sharedPathsMiscInfo.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -159,7 +159,7 @@ virtual void print_path(outputStream* out, int type, const char* path) { switch (type) { case BOOT: - out->print("Expecting -Dsun.boot.class.path=%s", path); + out->print("Expecting BOOT path %s", path); break; case NON_EXIST: out->print("Expecting that %s does not exist", path);
--- a/src/share/vm/classfile/systemDictionary.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ #include "classfile/dictionary.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/loaderConstraints.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/placeholders.hpp" #include "classfile/resolutionErrors.hpp" #include "classfile/stringTable.hpp" @@ -46,6 +47,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiEnvBase.hpp" #include "prims/methodHandles.hpp" @@ -172,7 +174,7 @@ if (class_loader.is_null()) { return false; } - return (class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_ExtClassLoader()); + return (class_loader->klass()->name() == vmSymbols::jdk_internal_misc_ClassLoaders_ExtClassLoader()); } // ---------------------------------------------------------------------------- @@ -1181,7 +1183,7 @@ instanceKlassHandle ik (THREAD, find_shared_class(class_name)); // Make sure we only return the boot class for the NULL classloader. if (ik.not_null() && - SharedClassUtil::is_shared_boot_class(ik()) && class_loader.is_null()) { + ik->is_shared_boot_class() && class_loader.is_null()) { Handle protection_domain; return load_shared_class(ik, class_loader, protection_domain, THREAD); } @@ -1195,6 +1197,12 @@ instanceKlassHandle nh = instanceKlassHandle(); // null Handle Symbol* class_name = ik->name(); + bool visible = SystemDictionaryShared::is_shared_class_visible_for_classloader( + class_name, ik, class_loader, CHECK_(nh)); + if (!visible) { + return nh; + } + // Found the class, now load the superclass and interfaces. If they // are shared, add them to the main system dictionary and reset // their hierarchy references (supers, subs, and interfaces). @@ -1265,22 +1273,86 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle + if (class_loader.is_null()) { + int length; + TempNewSymbol pkg_name = NULL; + PackageEntry* pkg_entry = NULL; + bool search_only_bootloader_append = false; + ClassLoaderData *loader_data = class_loader_data(class_loader); + + // Find the package in the boot loader's package entry table. + const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length); + if (pkg_string != NULL) { + pkg_name = SymbolTable::new_symbol((const char*)pkg_string, length, CHECK_(nh)); + pkg_entry = loader_data->packages()->lookup_only(pkg_name); + } + + // Prior to attempting to load the class, enforce the boot loader's + // visibility boundaries. + if (!Universe::is_module_initialized()) { + // During bootstrapping, prior to module initialization, any + // class attempting to be loaded must be checked against the + // java.base packages in the boot loader's PackageEntryTable. + // No class outside of java.base is allowed to be loaded during + // this bootstrapping window. + if (!DumpSharedSpaces) { + if (pkg_entry == NULL || pkg_entry->in_unnamed_module()) { + // Class is either in the unnamed package or in + // a named package within the unnamed module. Either + // case is outside of java.base, do not attempt to + // load the class post java.base definition. If + // java.base has not been defined, let the class load + // and its package will be checked later by + // ModuleEntryTable::verify_javabase_packages. + if (ModuleEntryTable::javabase_defined()) { + return nh; + } + } else { + // Check that the class' package is defined within java.base. + ModuleEntry* mod_entry = pkg_entry->module(); + Symbol* mod_entry_name = mod_entry->name(); + if (mod_entry_name->fast_compare(vmSymbols::java_base()) != 0) { + return nh; + } + } + } + } else { + assert(!DumpSharedSpaces, "Archive dumped after module system initialization"); + // After the module system has been initialized, check if the class' + // package is in a module defined to the boot loader. + if (pkg_string == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) { + // Class is either in the unnamed package, in a named package + // within a module not defined to the boot loader or in a + // a named package within the unnamed module. In all cases, + // limit visibility to search for the class only in the boot + // loader's append path. + search_only_bootloader_append = true; + } + } + + // Prior to bootstrapping's module initialization, never load a class outside + // of the boot loader's module path + assert(Universe::is_module_initialized() || DumpSharedSpaces || + !search_only_bootloader_append, + "Attempt to load a class outside of boot loader's module path"); // Search the shared system dictionary for classes preloaded into the // shared spaces. instanceKlassHandle k; { #if INCLUDE_CDS - PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time()); - k = load_shared_class(class_name, class_loader, THREAD); + if (!search_only_bootloader_append) { + PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time()); + k = load_shared_class(class_name, class_loader, THREAD); + } #endif } if (k.is_null()) { // Use VM class loader PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time()); - k = ClassLoader::load_classfile(class_name, CHECK_(nh)); + k = ClassLoader::load_classfile(class_name, search_only_bootloader_append, CHECK_(nh)); } // find_or_define_instance_class may return a different InstanceKlass @@ -1605,7 +1677,7 @@ } -// Get the next class in the diictionary. +// Get the next class in the dictionary. Klass* SystemDictionary::try_get_next_class() { return dictionary()->try_get_next_class(); } @@ -1876,6 +1948,11 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) { assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once"); + + // Create the ModuleEntry for java.base. This call needs to be done here, + // after vmSymbols::initialize() is called but before any classes are pre-loaded. + ClassLoader::create_javabase(); + // Preload commonly used klasses WKID scan = FIRST_WKID; // first do Object, then String, Class
--- a/src/share/vm/classfile/systemDictionary.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -137,6 +137,7 @@ do_klass(Properties_klass, java_util_Properties, Pre ) \ do_klass(reflect_AccessibleObject_klass, java_lang_reflect_AccessibleObject, Pre ) \ do_klass(reflect_Field_klass, java_lang_reflect_Field, Pre ) \ + do_klass(reflect_Module_klass, java_lang_reflect_Module, Pre ) \ do_klass(reflect_Parameter_klass, java_lang_reflect_Parameter, Opt ) \ do_klass(reflect_Method_klass, java_lang_reflect_Method, Pre ) \ do_klass(reflect_Constructor_klass, java_lang_reflect_Constructor, Pre ) \ @@ -169,15 +170,16 @@ do_klass(StringBuffer_klass, java_lang_StringBuffer, Pre ) \ do_klass(StringBuilder_klass, java_lang_StringBuilder, Pre ) \ do_klass(internal_Unsafe_klass, jdk_internal_misc_Unsafe, Pre ) \ + do_klass(module_Modules_klass, jdk_internal_module_Modules, Pre ) \ \ /* support for CDS */ \ do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream, Pre ) \ do_klass(File_klass, java_io_File, Pre ) \ - do_klass(URLClassLoader_klass, java_net_URLClassLoader, Pre ) \ do_klass(URL_klass, java_net_URL, Pre ) \ do_klass(Jar_Manifest_klass, java_util_jar_Manifest, Pre ) \ - do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ + do_klass(jdk_internal_misc_ClassLoaders_AppClassLoader_klass, jdk_internal_misc_ClassLoaders_AppClassLoader, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ + do_klass(ParseUtil_klass, sun_net_www_ParseUtil, Pre ) \ \ /* It's NULL in non-1.4 JDKs. */ \ do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \
--- a/src/share/vm/classfile/systemDictionaryShared.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/systemDictionaryShared.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -26,6 +26,7 @@ #ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP #define SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP +#include "classfile/sharedClassUtil.hpp" #include "classfile/systemDictionary.hpp" class SystemDictionaryShared: public SystemDictionary { @@ -42,6 +43,20 @@ oop class_loader = loader_data->class_loader(); return (class_loader == NULL); } + static bool is_shared_class_visible_for_classloader( + Symbol* class_name, + instanceKlassHandle ik, + Handle class_loader, + TRAPS) { + debug_only( { + int index = ik->shared_classpath_index(); + SharedClassPathEntry* ent = + (SharedClassPathEntry*)FileMapInfo::shared_classpath(index); + assert(ent->is_jrt(), "must from the bootmodules.jimage"); + assert(class_loader.is_null(), "Unsupported classloader"); + } ); + return true; + } }; #endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/src/share/vm/classfile/vmSymbols.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -48,10 +48,12 @@ // Mapping function names to values. New entries should be added below. #define VM_SYMBOLS_DO(template, do_alias) \ - /* commonly used class names */ \ + /* commonly used class, package, module names */ \ + template(java_base, "java.base") \ template(java_lang_System, "java/lang/System") \ template(java_lang_Object, "java/lang/Object") \ template(java_lang_Class, "java/lang/Class") \ + template(java_lang_Package, "java/lang/Package") \ template(java_lang_String, "java/lang/String") \ template(java_lang_StringLatin1, "java/lang/StringLatin1") \ template(java_lang_StringUTF16, "java/lang/StringUTF16") \ @@ -87,6 +89,7 @@ template(java_lang_reflect_Method, "java/lang/reflect/Method") \ template(java_lang_reflect_Constructor, "java/lang/reflect/Constructor") \ template(java_lang_reflect_Field, "java/lang/reflect/Field") \ + template(java_lang_reflect_Module, "java/lang/reflect/Module") \ template(java_lang_reflect_Parameter, "java/lang/reflect/Parameter") \ template(java_lang_reflect_Array, "java/lang/reflect/Array") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ @@ -97,7 +100,6 @@ template(java_security_CodeSource, "java/security/CodeSource") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ template(java_security_SecureClassLoader, "java/security/SecureClassLoader") \ - template(java_net_URLClassLoader, "java/net/URLClassLoader") \ template(java_net_URL, "java/net/URL") \ template(java_util_jar_Manifest, "java/util/jar/Manifest") \ template(impliesCreateAccessControlContext_name, "impliesCreateAccessControlContext") \ @@ -115,17 +117,25 @@ template(java_util_Hashtable, "java/util/Hashtable") \ template(java_lang_Compiler, "java/lang/Compiler") \ template(sun_misc_Signal, "sun/misc/Signal") \ - template(sun_misc_Launcher, "sun/misc/Launcher") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ - template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \ + template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \ + \ + template(jdk_internal_misc_ClassLoaders_AppClassLoader, "jdk/internal/misc/ClassLoaders$AppClassLoader") \ + template(jdk_internal_misc_ClassLoaders_ExtClassLoader, "jdk/internal/misc/ClassLoaders$ExtClassLoader") \ \ /* Java runtime version access */ \ template(sun_misc_Version, "sun/misc/Version") \ template(java_runtime_name_name, "java_runtime_name") \ template(java_runtime_version_name, "java_runtime_version") \ \ + /* system initialization */ \ + template(initPhase1_name, "initPhase1") \ + template(initPhase2_name, "initPhase2") \ + template(initPhase3_name, "initPhase3") \ + template(java_lang_reflect_module_init_signature, "(Ljava/lang/ClassLoader;Ljava/lang/String;)V") \ + \ /* class file format tags */ \ template(tag_source_file, "SourceFile") \ template(tag_inner_classes, "InnerClasses") \ @@ -342,7 +352,6 @@ template(run_finalization_name, "runFinalization") \ template(run_finalizers_on_exit_name, "runFinalizersOnExit") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ - template(initializeSystemClass_name, "initializeSystemClass") \ template(loadClass_name, "loadClass") \ template(loadClassInternal_name, "loadClassInternal") \ template(get_name, "get") \ @@ -416,14 +425,18 @@ template(signers_name, "signers_name") \ template(loader_data_name, "loader_data") \ template(vmdependencies_name, "vmdependencies") \ + template(loader_name, "loader") \ + template(module_name, "module") \ + template(getModule_name, "getModule") \ template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ - template(getFileURL_name, "getFileURL") \ - template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ - template(definePackageInternal_name, "definePackageInternal") \ - template(definePackageInternal_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)V") \ + template(defineOrCheckPackage_name, "defineOrCheckPackage") \ + template(defineOrCheckPackage_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)Ljava/lang/Package;") \ + template(fileToEncodedURL_name, "fileToEncodedURL") \ + template(fileToEncodedURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ template(getProtectionDomain_name, "getProtectionDomain") \ template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ + template(module_entry_name, "module_entry") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -501,6 +514,7 @@ template(void_class_signature, "()Ljava/lang/Class;") \ template(void_class_array_signature, "()[Ljava/lang/Class;") \ template(void_string_signature, "()Ljava/lang/String;") \ + template(void_module_signature, "()Ljava/lang/reflect/Module;") \ template(object_array_object_signature, "([Ljava/lang/Object;)Ljava/lang/Object;") \ template(object_object_array_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\ template(exception_void_signature, "(Ljava/lang/Exception;)V") \ @@ -519,6 +533,7 @@ template(reference_signature, "Ljava/lang/ref/Reference;") \ template(sun_misc_Cleaner_signature, "Lsun/misc/Cleaner;") \ template(executable_signature, "Ljava/lang/reflect/Executable;") \ + template(module_signature, "Ljava/lang/reflect/Module;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \ template(int_StringBuilder_signature, "(I)Ljava/lang/StringBuilder;") \ @@ -543,6 +558,9 @@ /* used to identify class loaders handling parallel class loading */ \ template(parallelCapable_name, "parallelLockMap") \ \ + /* used to return a class loader's unnamed module */ \ + template(unnamedModule_name, "unnamedModule") \ + \ /* JVM monitoring and management support */ \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ @@ -601,7 +619,10 @@ template(addThreadDumpForSynchronizers_signature, "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V") \ \ /* JVMTI/java.lang.instrument support and VM Attach mechanism */ \ + template(jdk_internal_module_Modules, "jdk/internal/module/Modules") \ template(sun_misc_VMSupport, "sun/misc/VMSupport") \ + template(transformedByAgent_name, "transformedByAgent") \ + template(transformedByAgent_signature, "(Ljava/lang/reflect/Module;)V") \ template(appendToClassPathForInstrumentation_name, "appendToClassPathForInstrumentation") \ do_alias(appendToClassPathForInstrumentation_signature, string_void_signature) \ template(serializePropertiesToByteArray_name, "serializePropertiesToByteArray") \
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -2257,10 +2257,8 @@ // Decrement counter at checkcast. BI_PROFILE_SUBTYPECHECK_FAILED(objKlass); ResourceMark rm(THREAD); - const char* objName = objKlass->external_name(); - const char* klassName = klassOf->external_name(); char* message = SharedRuntime::generate_class_cast_message( - objName, klassName); + objKlass, klassOf); VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message, note_classCheck_trap); } // Profile checkcast with null_seen and receiver.
--- a/src/share/vm/interpreter/interpreterRuntime.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -362,7 +362,7 @@ ResourceMark rm(thread); char* message = SharedRuntime::generate_class_cast_message( - thread, obj->klass()->external_name()); + thread, obj->klass()); if (ProfileTraps) { note_trap(thread, Deoptimization::Reason_class_check, CHECK);
--- a/src/share/vm/interpreter/linkResolver.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -270,18 +270,25 @@ // Klass resolution void LinkResolver::check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS) { - if (!Reflection::verify_class_access(ref_klass(), - sel_klass(), - true)) { + Reflection::VerifyClassAccessResults vca_result = + Reflection::verify_class_access(ref_klass(), sel_klass(), true); + if (vca_result != Reflection::ACCESS_OK) { ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "tried to access class %s from class %s", - sel_klass->external_name(), - ref_klass->external_name() - ); - return; + char* msg = Reflection::verify_class_access_msg(ref_klass(), sel_klass(), vca_result); + if (msg == NULL) { + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "failed to access class %s from class %s", + sel_klass->external_name(), + ref_klass->external_name()); + } else { + // Use module specific message returned by verify_class_access_msg(). + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "%s", msg); + } } }
--- a/src/share/vm/jvmci/jvmciEnv.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/jvmci/jvmciEnv.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -76,7 +76,9 @@ resolved_klass = ObjArrayKlass::cast(resolved_klass())->bottom_klass(); } if (resolved_klass->is_instance_klass()) { - return Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + Reflection::VerifyClassAccessResults result = + Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + return result == Reflection::ACCESS_OK; } return true; }
--- a/src/share/vm/memory/filemap.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/memory/filemap.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -227,12 +227,21 @@ SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); } else { struct stat st; - if ((os::stat(name, &st) == 0) && ((st.st_mode & S_IFDIR) == S_IFDIR)) { - if (!os::dir_is_empty(name)) { - ClassLoader::exit_with_path_failure("Cannot have non-empty directory in archived classpaths", name); + if (os::stat(name, &st) == 0) { + if (cpe->is_jrt()) { + // it's the bootmodules.jimage + ent->_timestamp = st.st_mtime; + ent->_filesize = st.st_size; + } else if ((st.st_mode & S_IFDIR) == S_IFDIR) { + if (!os::dir_is_empty(name)) { + ClassLoader::exit_with_path_failure( + "Cannot have non-empty directory in archived classpaths", name); + } + ent->_filesize = -1; } - ent->_filesize = -1; - } else { + } + if (ent->_filesize == 0) { + // unknown ent->_filesize = -2; } } @@ -285,7 +294,7 @@ fail_continue("directory is not empty: %s", name); ok = false; } - } else if (ent->is_jar()) { + } else if (ent->is_jar_or_bootimage()) { if (ent->_timestamp != st.st_mtime || ent->_filesize != st.st_size) { ok = false; @@ -294,7 +303,7 @@ "Timestamp mismatch" : "File size mismatch"); } else { - fail_continue("A jar file is not the one used while building" + fail_continue("A jar/jimage file is not the one used while building" " the shared archive file: %s", name); } } @@ -876,6 +885,11 @@ return false; } + if (Arguments::patch_dirs() != NULL) { + FileMapInfo::fail_continue("The shared archive file cannot be used with -Xpatch."); + return false; + } + if (_version != current_version()) { FileMapInfo::fail_continue("The shared archive file is the wrong version."); return false;
--- a/src/share/vm/memory/filemap.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/memory/filemap.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -44,14 +44,20 @@ class SharedClassPathEntry VALUE_OBJ_CLASS_SPEC { public: const char *_name; - time_t _timestamp; // jar timestamp, 0 if is directory or other - long _filesize; // jar file size, -1 if is directory, -2 if other - bool is_jar() { + time_t _timestamp; // jar/bootimage timestamp, 0 if is directory or other + long _filesize; // jar/bootimage file size, -1 if is directory, -2 if other + + // The _timestamp only gets set for jar files and bootmodules.jimage. + bool is_jar_or_bootimage() { return _timestamp != 0; } bool is_dir() { return _filesize == -1; } + + bool is_jrt() { + return ClassLoader::is_jrt(_name); + } }; class FileMapInfo : public CHeapObj<mtInternal> {
--- a/src/share/vm/memory/metaspaceShared.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/memory/metaspaceShared.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -695,6 +695,21 @@ } } +void MetaspaceShared::check_shared_class_loader_type(Klass* obj) { + InstanceKlass* ik = (InstanceKlass*)obj; + u2 loader_type = ik->loader_type(); + if (loader_type == 0) { + tty->print_cr("Class loader type is not set for this class %s", + ik->name()->as_C_string()); + exit(1); + } + if ((loader_type && !(loader_type & (loader_type - 1))) == 0) { + tty->print_cr("More than one loader type is set for this class %s", + ik->name()->as_C_string()); + exit(1); + } +} + void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) { // We need to iterate because verification may cause additional classes // to be loaded. @@ -726,6 +741,7 @@ } void MetaspaceShared::prepare_for_dumping() { + Arguments::check_unsupported_dumping_properties(); ClassLoader::initialize_shared_path(); FileMapInfo::allocate_classpath_entry_table(); } @@ -799,6 +815,8 @@ tty->print_cr("Shared spaces: preloaded %d classes", class_count); } + SystemDictionary::classes_do(check_shared_class_loader_type); + // Rewrite and link classes tty->print_cr("Rewriting and linking classes ..."); @@ -882,7 +900,7 @@ assert(DumpSharedSpaces, "should only be called during dumping"); if (ik->init_state() < InstanceKlass::linked) { bool saved = BytecodeVerificationLocal; - if (!SharedClassUtil::is_shared_boot_class(ik)) { + if (!(ik->is_shared_boot_class())) { // The verification decision is based on BytecodeVerificationRemote // for non-system classes. Since we are using the NULL classloader // to load non-system classes during dumping, we need to temporarily
--- a/src/share/vm/memory/metaspaceShared.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/memory/metaspaceShared.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -156,6 +156,7 @@ static bool try_link_class(InstanceKlass* ik, TRAPS); static void link_one_shared_class(Klass* obj, TRAPS); static void check_one_shared_class(Klass* obj); + static void check_shared_class_loader_type(Klass* obj); static void link_and_cleanup_shared_classes(TRAPS); static int count_class(const char* classlist_file);
--- a/src/share/vm/memory/universe.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/memory/universe.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -148,6 +148,7 @@ int Universe::_base_vtable_size = 0; bool Universe::_bootstrapping = false; +bool Universe::_module_initialized = false; bool Universe::_fully_initialized = false; size_t Universe::_heap_capacity_at_last_gc; @@ -901,6 +902,10 @@ Universe::genesis(CATCH); } +// Set after initialization of the module runtime, call_initModuleRuntime +void universe_post_module_init() { + Universe::_module_initialized = true; +} bool universe_post_init() { assert(!is_init_completed(), "Error: initialization not yet completed!");
--- a/src/share/vm/memory/universe.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/memory/universe.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -111,6 +111,7 @@ friend jint universe_init(); friend void universe2_init(); friend bool universe_post_init(); + friend void universe_post_module_init(); private: // Known classes in the VM @@ -201,6 +202,7 @@ // Initialization static bool _bootstrapping; // true during genesis + static bool _module_initialized; // true after call_initPhase2 called static bool _fully_initialized; // true after universe_init and initialize_vtables called // the array of preallocated errors with backtraces @@ -428,6 +430,7 @@ // Testers static bool is_bootstrapping() { return _bootstrapping; } + static bool is_module_initialized() { return _module_initialized; } static bool is_fully_initialized() { return _fully_initialized; } static inline bool element_type_should_be_aligned(BasicType type);
--- a/src/share/vm/oops/arrayKlass.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/oops/arrayKlass.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -102,7 +102,7 @@ ResourceMark rm(THREAD); k->initialize_supers(super_klass(), CHECK); k->vtable()->initialize_vtable(false, CHECK); - java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(NULL), CHECK); + java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(NULL), Handle(NULL), CHECK); } GrowableArray<Klass*>* ArrayKlass::compute_secondary_supers(int num_extra_slots) {
--- a/src/share/vm/oops/instanceKlass.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/oops/instanceKlass.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -224,6 +224,7 @@ init_implementor(); set_fields(NULL, 0); set_constants(NULL); + set_package(NULL); set_class_loader_data(NULL); set_source_file_name_index(0); set_source_debug_extension(NULL, 0); @@ -2118,8 +2119,9 @@ } void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { + instanceKlassHandle ik(THREAD, this); + ik->set_package(ik->name(), loader_data, CHECK); Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); - instanceKlassHandle ik(THREAD, this); Array<Method*>* methods = ik->methods(); int num_methods = methods->length(); @@ -2322,16 +2324,135 @@ return dest; } -// different verisons of is_same_class_package +const jbyte* InstanceKlass::package_from_name(Symbol* name, int& length) { + ResourceMark rm; + length = 0; + if (name == NULL) { + return NULL; + } else { + const jbyte* base_name = name->base(); + const jbyte* last_slash = UTF8::strrchr(base_name, name->utf8_length(), '/'); + + if (last_slash == NULL) { + // No package name + return NULL; + } else { + // Skip over '['s + if (*base_name == '[') { + do { + base_name++; + } while (*base_name == '['); + if (*base_name != 'L') { + // Fully qualified class names should not contain a 'L'. + // Set length to -1 to indicate that the package name + // could not be obtained due to an error condition. + // In this situtation, is_same_class_package returns false. + length = -1; + return NULL; + } + } + + // Found the package name, look it up in the symbol table. + length = last_slash - base_name; + assert(length > 0, "Bad length for package name"); + return base_name; + } + } +} + +ModuleEntry* InstanceKlass::module() const { + if (!in_unnamed_package()) { + return _package_entry->module(); + } + const Klass* host = host_klass(); + if (host == NULL) { + return class_loader_data()->modules()->unnamed_module(); + } + return host->class_loader_data()->modules()->unnamed_module(); +} + +void InstanceKlass::set_package(Symbol* name, ClassLoaderData* loader, TRAPS) { + int length; + const jbyte* base_name = package_from_name(name, length); + + if (base_name != NULL && loader != NULL) { + TempNewSymbol pkg_name = SymbolTable::new_symbol((const char*)base_name, length, CHECK); + + // Find in class loader's package entry table. + _package_entry = loader->packages()->lookup_only(pkg_name); + + // If the package name is not found in the loader's package + // entry table, it is an indication that the package has not + // been defined. Consider it defined within the unnamed module. + if (_package_entry == NULL) { + ResourceMark rm; + + if (!ModuleEntryTable::javabase_defined()) { + // Before java.base is defined during bootstrapping, define all packages in + // the java.base module. If a non-java.base package is erroneously placed + // in the java.base module it will be caught later when java.base + // is defined by ModuleEntryTable::verify_javabase_packages check. + assert(ModuleEntryTable::javabase_module() != NULL, "java.base module is NULL"); + _package_entry = loader->packages()->lookup(pkg_name, ModuleEntryTable::javabase_module()); + } else { + assert(loader->modules()->unnamed_module() != NULL, "unnamed module is NULL"); + _package_entry = loader->packages()->lookup(pkg_name, + loader->modules()->unnamed_module()); + } + + // A package should have been successfully created + assert(_package_entry != NULL, "Package entry for class %s not found, loader %s", + name->as_C_string(), loader->loader_name()); + } + + if (TraceModules) { + ResourceMark rm; + ModuleEntry* m = _package_entry->module(); + tty->print_cr("[Setting package: class: %s, package: %s, loader: %s, module: %s]", + external_name(), + pkg_name->as_C_string(), + loader->loader_name(), + (m->is_named() ? m->name()->as_C_string() : UNNAMED_MODULE)); + } + } else { + if (TraceModules) { + ResourceMark rm; + tty->print_cr("[Setting package: class: %s, package: unnamed, loader: %s, module: %s]", + external_name(), + (loader != NULL) ? loader->loader_name() : "NULL", + UNNAMED_MODULE); + } + } +} + +// different versions of is_same_class_package bool InstanceKlass::is_same_class_package(Klass* class2) { + oop classloader1 = this->class_loader(); + PackageEntry* classpkg1 = this->package(); if (class2->is_objArray_klass()) { class2 = ObjArrayKlass::cast(class2)->bottom_klass(); } - oop classloader2 = class2->class_loader(); - Symbol* classname2 = class2->name(); - - return InstanceKlass::is_same_class_package(class_loader(), name(), - classloader2, classname2); + + oop classloader2; + PackageEntry* classpkg2; + if (class2->is_instance_klass()) { + classloader2 = class2->class_loader(); + classpkg2 = InstanceKlass::cast(class2)->package(); + } else { + assert(class2->is_typeArray_klass(), "should be type array"); + classloader2 = NULL; + classpkg2 = NULL; + } + + // Same package is determined by comparing class loader + // and package entries. Both must be the same. This rule + // applies even to classes that are defined in the unnamed + // package, they still must have the same class loader. + if ((classloader1 == classloader2) && (classpkg1 == classpkg2)) { + return true; + } + + return false; } bool InstanceKlass::is_same_class_package(oop classloader2, Symbol* classname2) { @@ -2353,43 +2474,24 @@ // The Symbol*'s are in UTF8 encoding. Since we only need to check explicitly // for ASCII characters ('/', 'L', '['), we can keep them in UTF8 encoding. // Otherwise, we just compare jbyte values between the strings. - const jbyte *name1 = class_name1->base(); - const jbyte *name2 = class_name2->base(); - - const jbyte *last_slash1 = UTF8::strrchr(name1, class_name1->utf8_length(), '/'); - const jbyte *last_slash2 = UTF8::strrchr(name2, class_name2->utf8_length(), '/'); - - if ((last_slash1 == NULL) || (last_slash2 == NULL)) { + int length1; + int length2; + const jbyte *name1 = package_from_name(class_name1, length1); + const jbyte *name2 = package_from_name(class_name2, length2); + + if ((length1 < 0) || (length2 < 0)) { + // error occurred parsing package name. + return false; + } + + if ((name1 == NULL) || (name2 == NULL)) { // One of the two doesn't have a package. Only return true // if the other one also doesn't have a package. - return last_slash1 == last_slash2; - } else { - // Skip over '['s - if (*name1 == '[') { - do { - name1++; - } while (*name1 == '['); - if (*name1 != 'L') { - // Something is terribly wrong. Shouldn't be here. - return false; - } - } - if (*name2 == '[') { - do { - name2++; - } while (*name2 == '['); - if (*name2 != 'L') { - // Something is terribly wrong. Shouldn't be here. - return false; - } - } - - // Check that package part is identical - int length1 = last_slash1 - name1; - int length2 = last_slash2 - name2; - - return UTF8::equal(name1, length1, name2, length2); + return name1 == name2; } + + // Check that package part is identical + return UTF8::equal(name1, length1, name2, length2); } } @@ -2428,7 +2530,7 @@ instanceKlassHandle class2(THREAD, class2_oop); // must be in same package before we try anything else - if (!class1->is_same_class_package(class2->class_loader(), class2->name())) + if (!class1->is_same_class_package(class2())) return false; // As long as there is an outer1.getEnclosingClass,
--- a/src/share/vm/oops/instanceKlass.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/oops/instanceKlass.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -25,8 +25,11 @@ #ifndef SHARE_VM_OOPS_INSTANCEKLASS_HPP #define SHARE_VM_OOPS_INSTANCEKLASS_HPP +#include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/packageEntry.hpp" #include "gc/shared/specialized_oop_closures.hpp" +#include "classfile/moduleEntry.hpp" #include "memory/referenceType.hpp" #include "oops/annotations.hpp" #include "oops/constMethod.hpp" @@ -156,6 +159,8 @@ protected: // Annotations for this class Annotations* _annotations; + // Package this class is defined in + PackageEntry* _package_entry; // Array classes holding elements of this class. Klass* _array_klasses; // Constant pool for this class. @@ -215,16 +220,22 @@ // Start after _misc_kind field. enum { - _misc_rewritten = 1 << 2, // methods rewritten. - _misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops - _misc_should_verify_class = 1 << 4, // allow caching of preverification - _misc_is_anonymous = 1 << 5, // has embedded _host_klass field - _misc_is_contended = 1 << 6, // marked with contended annotation - _misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods - _misc_declares_default_methods = 1 << 8, // directly declares default methods (any access) - _misc_has_been_redefined = 1 << 9, // class has been redefined - _misc_is_scratch_class = 1 << 10 // class is the redefined scratch class + _misc_rewritten = 1 << 2, // methods rewritten. + _misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops + _misc_should_verify_class = 1 << 4, // allow caching of preverification + _misc_is_anonymous = 1 << 5, // has embedded _host_klass field + _misc_is_contended = 1 << 6, // marked with contended annotation + _misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods + _misc_declares_default_methods = 1 << 8, // directly declares default methods (any access) + _misc_has_been_redefined = 1 << 9, // class has been redefined + _misc_is_scratch_class = 1 << 10, // class is the redefined scratch class + _misc_is_shared_boot_class = 1 << 11, // defining class loader is boot class loader + _misc_is_shared_ext_class = 1 << 12, // defining class loader is ext class loader + _misc_is_shared_app_class = 1 << 13 // defining class loader is app class loader }; + u2 loader_type_bits() { + return _misc_is_shared_boot_class|_misc_is_shared_ext_class|_misc_is_shared_app_class; + } u2 _misc_flags; u2 _minor_version; // minor version number of class file u2 _major_version; // major version number of class file @@ -308,6 +319,39 @@ friend class SystemDictionary; public: + u2 loader_type() { + return _misc_flags & loader_type_bits(); + } + + bool is_shared_boot_class() const { + return (_misc_flags & _misc_is_shared_boot_class) != 0; + } + bool is_shared_ext_class() const { + return (_misc_flags & _misc_is_shared_ext_class) != 0; + } + bool is_shared_app_class() const { + return (_misc_flags & _misc_is_shared_app_class) != 0; + } + + void set_class_loader_type(jshort loader_type) { + assert(( _misc_flags & loader_type_bits()) == 0, + "Should only be called once for each class."); + switch (loader_type) { + case ClassLoader::BOOT: + _misc_flags |= _misc_is_shared_boot_class; + break; + case ClassLoader::EXT: + _misc_flags |= _misc_is_shared_ext_class; + break; + case ClassLoader::APP: + _misc_flags |= _misc_is_shared_app_class; + break; + default: + ShouldNotReachHere(); + break; + } + } + bool has_nonstatic_fields() const { return (_misc_flags & _misc_has_nonstatic_fields) != 0; } @@ -417,6 +461,11 @@ bool is_override(const methodHandle& super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS); // package + PackageEntry* package() const { return _package_entry; } + ModuleEntry* module() const; + bool in_unnamed_package() const { return (_package_entry == NULL); } + void set_package(PackageEntry* p) { _package_entry = p; } + void set_package(Symbol* name, ClassLoaderData* loader, TRAPS); bool is_same_class_package(Klass* class2); bool is_same_class_package(oop classloader2, Symbol* classname2); static bool is_same_class_package(oop class_loader1, Symbol* class_name1, oop class_loader2, Symbol* class_name2); @@ -853,7 +902,7 @@ // support for stub routines static ByteSize init_state_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_state)); } - TRACE_DEFINE_OFFSET; + TRACE_DEFINE_KLASS_TRACE_ID_OFFSET; static ByteSize init_thread_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_thread)); } // subclass/subinterface checks @@ -1050,6 +1099,7 @@ // Naming const char* signature_name() const; + static const jbyte* package_from_name(Symbol* name, int& length); // GC specific object visitors //
--- a/src/share/vm/oops/klass.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/oops/klass.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -180,7 +180,7 @@ set_subklass(NULL); set_next_sibling(NULL); set_next_link(NULL); - TRACE_INIT_ID(this); + TRACE_INIT_KLASS_ID(this); set_prototype_header(markOopDesc::prototype()); set_biased_lock_revocation_count(0); @@ -346,7 +346,6 @@ return NULL; } - InstanceKlass* Klass::superklass() const { assert(super() == NULL || super()->is_instance_klass(), "must be instance klass"); return _super == NULL ? NULL : InstanceKlass::cast(_super); @@ -506,7 +505,7 @@ } void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { - TRACE_INIT_ID(this); + TRACE_INIT_KLASS_ID(this); // If an exception happened during CDS restore, some of these fields may already be // set. We leave the class on the CLD list, even if incomplete so that we don't // modify the CLD list outside a safepoint. @@ -524,7 +523,27 @@ // gotten an OOM later but keep the mirror if it was created. if (java_mirror() == NULL) { Handle loader = loader_data->class_loader(); - java_lang_Class::create_mirror(this, loader, protection_domain, CHECK); + ModuleEntry* module_entry = NULL; + Klass* k = this; + if (k->is_objArray_klass()) { + k = ObjArrayKlass::cast(k)->bottom_klass(); + } + // Obtain klass' module. + if (k->is_instance_klass()) { + InstanceKlass* ik = (InstanceKlass*) k; + module_entry = ik->module(); + } else { + module_entry = ModuleEntryTable::javabase_module(); + } + // Obtain j.l.r.Module if available + oop jlrM_module = (oop)NULL; + if (module_entry != NULL && + module_entry->is_named() && + module_entry->jlrM_module() != NULL) { + jlrM_module = JNIHandles::resolve(module_entry->jlrM_module()); + } + Handle jlrM_handle(THREAD, jlrM_module); + java_lang_Class::create_mirror(this, loader, jlrM_handle, protection_domain, CHECK); } }
--- a/src/share/vm/oops/klass.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/oops/klass.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -136,7 +136,7 @@ markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; - TRACE_DEFINE_KLASS_TRACE_ID; + TRACE_DEFINE_TRACE_ID_FIELD; // Remembered sets support for the oops in the klasses. jbyte _modified_oops; // Card Table Equivalent (YC/CMS support) @@ -553,7 +553,7 @@ jlong last_biased_lock_bulk_revocation_time() { return _last_biased_lock_bulk_revocation_time; } void set_last_biased_lock_bulk_revocation_time(jlong cur_time) { _last_biased_lock_bulk_revocation_time = cur_time; } - TRACE_DEFINE_KLASS_METHODS; + TRACE_DEFINE_TRACE_ID_METHODS; // garbage collection support void oops_do(OopClosure* cl);
--- a/src/share/vm/opto/library_call.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/opto/library_call.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -3030,7 +3030,7 @@ Node* cls = null_check(argument(1), T_OBJECT); Node* kls = load_klass_from_mirror(cls, false, NULL, 0); kls = null_check(kls, T_OBJECT); - ByteSize offset = TRACE_ID_OFFSET; + ByteSize offset = TRACE_KLASS_TRACE_ID_OFFSET; Node* insp = basic_plus_adr(kls, in_bytes(offset)); Node* tvalue = make_load(NULL, insp, TypeLong::LONG, T_LONG, MemNode::unordered); Node* bits = longcon(~0x03l); // ignore bit 0 & 1
--- a/src/share/vm/precompiled/precompiled.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/precompiled/precompiled.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -58,6 +58,9 @@ # include "classfile/classFileStream.hpp" # include "classfile/classLoader.hpp" # include "classfile/javaClasses.hpp" +# include "classfile/moduleEntry.hpp" +# include "classfile/modules.hpp" +# include "classfile/packageEntry.hpp" # include "classfile/symbolTable.hpp" # include "classfile/systemDictionary.hpp" # include "classfile/vmSymbols.hpp"
--- a/src/share/vm/prims/jni.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jni.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -28,6 +28,7 @@ #include "classfile/altHashing.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/modules.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -3458,6 +3459,19 @@ return JNI_OK; JNI_END + +DT_RETURN_MARK_DECL(GetModule, jobject, HOTSPOT_JNI_GETMODULE_RETURN(_ret_ref)); + +JNI_ENTRY(jobject, jni_GetModule(JNIEnv* env, jclass clazz)) + JNIWrapper("GetModule"); + HOTSPOT_JNI_GETMODULE_ENTRY(env, clazz); + jobject res; + DT_RETURN_MARK(GetModule, jobject, (const jobject&)res); + res = Modules::get_module(env, clazz); + return res; +JNI_END + + // Structure containing all jni functions struct JNINativeInterface_ jni_NativeInterface = { NULL, @@ -3737,7 +3751,11 @@ // New 1_6 features - jni_GetObjectRefType + jni_GetObjectRefType, + + // Module features + + jni_GetModule };
--- a/src/share/vm/prims/jni.h Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jni.h Mon Nov 30 14:57:39 2015 -0800 @@ -765,6 +765,11 @@ jobjectRefType (JNICALL *GetObjectRefType) (JNIEnv* env, jobject obj); + + /* Module Features */ + + jobject (JNICALL *GetModule) + (JNIEnv* env, jclass clazz); }; /* @@ -1857,6 +1862,12 @@ return functions->GetObjectRefType(this, obj); } + /* Module Features */ + + jobject GetModule(jclass clazz) { + return functions->GetModule(this, clazz); + } + #endif /* __cplusplus */ };
--- a/src/share/vm/prims/jniCheck.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jniCheck.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -1989,7 +1989,17 @@ return result; JNI_END - +JNI_ENTRY_CHECKED(jobject, + checked_jni_GetModule(JNIEnv *env, + jclass clazz)) + functionEnter(thr); + IN_VM( + jniCheck::validate_class(thr, clazz, false); + ) + jobject result = UNCHECKED()->GetModule(env,clazz); + functionExit(thr); + return result; +JNI_END /* * Structure containing all checked jni functions @@ -2272,7 +2282,11 @@ // New 1.6 Features - checked_jni_GetObjectRefType + checked_jni_GetObjectRefType, + + // Module Features + + checked_jni_GetModule };
--- a/src/share/vm/prims/jvm.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jvm.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -24,8 +24,12 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -985,6 +989,53 @@ (jclass) JNIHandles::make_local(env, k->java_mirror()); JVM_END +// Module support ////////////////////////////////////////////////////////////////////////////// + +JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location, + jobjectArray packages)) + JVMWrapper("JVM_DefineModule"); + Modules::define_module(env, module, version, location, packages); +JVM_END + +JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)) + JVMWrapper("JVM_SetBootLoaderUnnamedModule"); + Modules::set_bootloader_unnamed_module(env, module); +JVM_END + +JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module)) + JVMWrapper("JVM_AddModuleExports"); + Modules::add_module_exports_qualified(env, from_module, package, to_module); +JVM_END + +JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package)) + JVMWrapper("JVM_AddModuleExportsToAllUnnamed"); + Modules::add_module_exports_to_all_unnamed(env, from_module, package); +JVM_END + +JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package)) + JVMWrapper("JVM_AddModuleExportsToAll"); + Modules::add_module_exports(env, from_module, package, NULL); +JVM_END + +JVM_ENTRY (void, JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module)) + JVMWrapper("JVM_AddReadsModule"); + Modules::add_reads_module(env, from_module, source_module); +JVM_END + +JVM_ENTRY(jboolean, JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module)) + JVMWrapper("JVM_CanReadModule"); + return Modules::can_read_module(env, asking_module, source_module); +JVM_END + +JVM_ENTRY(jboolean, JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module)) + JVMWrapper("JVM_IsExportedToModule"); + return Modules::is_exported_to_module(env, from_module, package, to_module); +JVM_END + +JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, jstring package)) + JVMWrapper("JVM_AddModulePackage"); + Modules::add_module_package(env, module, package); +JVM_END // Reflection support //////////////////////////////////////////////////////////////////////////////
--- a/src/share/vm/prims/jvm.h Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jvm.h Mon Nov 30 14:57:39 2015 -0800 @@ -390,6 +390,38 @@ jboolean verify); /* + * Module support funcions + */ + +JNIEXPORT void JNICALL +JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location, + jobjectArray packages); + +JNIEXPORT void JNICALL +JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); + +JNIEXPORT void JNICALL +JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + +JNIEXPORT void JNICALL +JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); + +JNIEXPORT void JNICALL +JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); + +JNIEXPORT void JNICALL +JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module); + +JNIEXPORT jboolean JNICALL +JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module); + +JNIEXPORT jboolean JNICALL +JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + +JNIEXPORT void JNICALL +JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); + +/* * Reflection support functions */ @@ -881,6 +913,7 @@ #define JVM_ACC_SYNTHETIC 0x1000 /* compiler-generated class, method or field */ #define JVM_ACC_ANNOTATION 0x2000 /* annotation type */ #define JVM_ACC_ENUM 0x4000 /* field is declared as element of enum */ +#define JVM_ACC_MODULE 0x8000 /* module-info class file */ #define JVM_ACC_PUBLIC_BIT 0 #define JVM_ACC_PRIVATE_BIT 1
--- a/src/share/vm/prims/jvmti.xml Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jvmti.xml Mon Nov 30 14:57:39 2015 -0800 @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="ISO-8859-1"?> <?xml-stylesheet type="text/xsl" href="jvmti.xsl"?> <!-- - Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it @@ -357,8 +357,8 @@ <specification label="JVM(TM) Tool Interface" majorversion="1" - minorversion="2" - microversion="3"> + minorversion="3" + microversion="1"> <title subtitle="Version"> <tm>JVM</tm> Tool Interface </title> @@ -12351,7 +12351,7 @@ </parameters> </event> - <event label="Class File Load Hook" phase="any" + <event label="Class File Load Hook" phase="start" id="ClassFileLoadHook" const="JVMTI_EVENT_CLASS_FILE_LOAD_HOOK" num="54"> <description> This event is sent when the VM obtains class file data, @@ -12367,9 +12367,9 @@ <internallink id="bci">bytecode instrumentation</internallink> for usage information. <p/> - This event may be sent before the VM is initialized (the primordial - <functionlink id="GetPhase">phase</functionlink>). During this time - no VM resources should be created. Some classes might not be compatible + This event may be sent before the VM is initialized (the start + <functionlink id="GetPhase">phase</functionlink>). + Some classes might not be compatible with the function (eg. ROMized classes) and this event will not be generated for these classes. <p/> @@ -12378,9 +12378,7 @@ using the memory allocation function <functionlink id="Allocate"></functionlink> because the VM is responsible for freeing the new class file data buffer - using <functionlink id="Deallocate"></functionlink>. - Note that <functionlink id="Allocate"></functionlink> - is permitted during the primordial phase. + using <functionlink id="Deallocate"></functionlink>. <p/> If the agent wishes to modify the class file, it must set <code>new_class_data</code> to point @@ -12427,8 +12425,6 @@ </outptr> <description> The JNI environment of the event (current) thread. - Will be <code>NULL</code> if sent during the primordial - <functionlink id="GetPhase">phase</functionlink>. </description> </param> <param id="class_being_redefined"> @@ -14340,6 +14336,9 @@ <change date="19 June 2013" version="1.2.3"> Added support for statically linked agents. </change> + <change date="1 July 2015" version="1.3.1"> + The ClassFileLoadHook events are not sent during the primordial phase anymore. + </change> </changehistory> </specification>
--- a/src/share/vm/prims/jvmtiExport.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jvmtiExport.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -46,6 +46,7 @@ #include "runtime/arguments.hpp" #include "runtime/handles.hpp" #include "runtime/interfaceSupport.hpp" +#include "runtime/javaCalls.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.inline.hpp" @@ -397,6 +398,28 @@ } } +void +JvmtiExport::add_default_read_edges(Handle h_module, TRAPS) { + if (!Universe::is_module_initialized()) { + return; // extra safety + } + assert(!h_module.is_null(), "module should always be set"); + + // Invoke the transformedByAgent method + JavaValue result(T_VOID); + JavaCalls::call_static(&result, + SystemDictionary::module_Modules_klass(), + vmSymbols::transformedByAgent_name(), + vmSymbols::transformedByAgent_signature(), + h_module, + THREAD); + + if (HAS_PENDING_EXCEPTION) { + java_lang_Throwable::print(PENDING_EXCEPTION, tty); + CLEAR_PENDING_EXCEPTION; + return; + } +} void JvmtiExport::decode_version_values(jint version, int * major, int * minor, @@ -544,6 +567,17 @@ if (_state != NULL) { _h_class_being_redefined = _state->get_class_being_redefined(); _load_kind = _state->get_class_load_kind(); + Klass* klass = (_h_class_being_redefined == NULL) ? NULL : (*_h_class_being_redefined)(); + if (_load_kind != jvmti_class_load_kind_load && klass != NULL) { + ModuleEntry* module_entry = InstanceKlass::cast(klass)->module(); + assert(module_entry != NULL, "module_entry should always be set"); + if (module_entry->is_named() && + module_entry->jlrM_module() != NULL) { + // Add read edges to the unnamed modules of the bootstrap and app class loaders + Handle class_module(_thread, JNIHandles::resolve(module_entry->jlrM_module())); // Obtain j.l.r.Module + JvmtiExport::add_default_read_edges(class_module, _thread); + } + } // Clear class_being_redefined flag here. The action // from agent handler could generate a new class file load // hook event and if it is not cleared the new event generated @@ -668,6 +702,10 @@ unsigned char **data_ptr, unsigned char **end_ptr, JvmtiCachedClassFileData **cache_ptr) { + if (JvmtiEnv::get_phase() <= JVMTI_PHASE_PRIMORDIAL) { + return; + } + JvmtiClassFileLoadHookPoster poster(h_name, class_loader, h_protection_domain, data_ptr, end_ptr, @@ -912,6 +950,9 @@ } void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) { + if (JvmtiEnv::get_phase() <= JVMTI_PHASE_PRIMORDIAL) { + return; + } HandleMark hm(thread); KlassHandle kh(thread, klass); @@ -941,6 +982,9 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) { + if (JvmtiEnv::get_phase() <= JVMTI_PHASE_PRIMORDIAL) { + return; + } HandleMark hm(thread); KlassHandle kh(thread, klass); @@ -969,6 +1013,9 @@ } void JvmtiExport::post_class_unload(Klass* klass) { + if (JvmtiEnv::get_phase() <= JVMTI_PHASE_PRIMORDIAL) { + return; + } Thread *thread = Thread::current(); HandleMark hm(thread); KlassHandle kh(thread, klass); @@ -1018,6 +1065,9 @@ void JvmtiExport::post_thread_start(JavaThread *thread) { + if (JvmtiEnv::get_phase() <= JVMTI_PHASE_PRIMORDIAL) { + return; + } assert(thread->thread_state() == _thread_in_vm, "must be in vm state"); EVT_TRIG_TRACE(JVMTI_EVENT_THREAD_START, ("JVMTI [%s] Trg Thread Start event triggered", @@ -1048,6 +1098,9 @@ void JvmtiExport::post_thread_end(JavaThread *thread) { + if (JvmtiEnv::get_phase() <= JVMTI_PHASE_PRIMORDIAL) { + return; + } EVT_TRIG_TRACE(JVMTI_EVENT_THREAD_END, ("JVMTI [%s] Trg Thread End event triggered", JvmtiTrace::safe_get_thread_name(thread)));
--- a/src/share/vm/prims/jvmtiExport.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/jvmtiExport.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -213,6 +213,8 @@ _all_dependencies_are_recorded = (on != 0); } + // Add read edges to the unnamed modules of the bootstrap and app class loaders + static void add_default_read_edges(Handle h_module, TRAPS); // let JVMTI know that the JVM_OnLoad code is running static void enter_onload_phase() NOT_JVMTI_RETURN;
--- a/src/share/vm/prims/methodHandles.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/methodHandles.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -1172,9 +1172,9 @@ if (reference_klass != NULL && reference_klass->is_instance_klass()) { // Emulate LinkResolver::check_klass_accessability. Klass* caller = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(caller_jh)); - if (!Reflection::verify_class_access(caller, - reference_klass, - true)) { + if (Reflection::verify_class_access(caller, + reference_klass, + true) != Reflection::ACCESS_OK) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), reference_klass->external_name()); } }
--- a/src/share/vm/prims/whitebox.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/prims/whitebox.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ #include <new> #include "classfile/classLoaderData.hpp" +#include "classfile/modules.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" #include "compiler/methodMatcher.hpp" @@ -159,8 +160,8 @@ WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) { CollectorPolicy * p = Universe::heap()->collector_policy(); - gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap " - SIZE_FORMAT " Maximum heap " SIZE_FORMAT " Space alignment " SIZE_FORMAT " Heap alignment " SIZE_FORMAT, + gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap " + SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Space alignment "SIZE_FORMAT" Heap alignment "SIZE_FORMAT, p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(), p->space_alignment(), p->heap_alignment()); } @@ -195,8 +196,8 @@ Universe::narrow_oop_use_implicit_null_checks() )) { tty->print_cr("WB_ReadFromNoaccessArea method is useless:\n " "\tUseCompressedOops is %d\n" - "\trhs.base() is " PTR_FORMAT "\n" - "\tUniverse::narrow_oop_base() is " PTR_FORMAT "\n" + "\trhs.base() is "PTR_FORMAT"\n" + "\tUniverse::narrow_oop_base() is "PTR_FORMAT"\n" "\tUniverse::narrow_oop_use_implicit_null_checks() is %d", UseCompressedOops, p2i(rhs.base()), @@ -249,8 +250,8 @@ WB_ENTRY(jint, WB_StressVirtualSpaceResize(JNIEnv* env, jobject o, jlong reserved_space_size, jlong magnitude, jlong iterations)) - tty->print_cr("reservedSpaceSize=" JLONG_FORMAT ", magnitude=" JLONG_FORMAT ", " - "iterations=" JLONG_FORMAT "\n", reserved_space_size, magnitude, + tty->print_cr("reservedSpaceSize="JLONG_FORMAT", magnitude="JLONG_FORMAT", " + "iterations="JLONG_FORMAT"\n", reserved_space_size, magnitude, iterations); if (reserved_space_size < 0 || magnitude < 0 || iterations < 0) { tty->print_cr("One of variables printed above is negative. Can't proceed.\n"); @@ -1234,6 +1235,39 @@ MetadataFactory::free_array(cld, (Array<u1>*)(uintptr_t)addr); WB_END +WB_ENTRY(void, WB_DefineModule(JNIEnv* env, jobject o, jobject module, jstring version, jstring location, + jobjectArray packages)) + Modules::define_module(env, module, version, location, packages); +WB_END + +WB_ENTRY(void, WB_AddModuleExports(JNIEnv* env, jobject o, jobject from_module, jstring package, jobject to_module)) + Modules::add_module_exports_qualified(env, from_module, package, to_module); +WB_END + +WB_ENTRY(void, WB_AddModuleExportsToAllUnnamed(JNIEnv* env, jobject o, jclass module, jstring package)) + Modules::add_module_exports_to_all_unnamed(env, module, package); +WB_END + +WB_ENTRY(void, WB_AddModuleExportsToAll(JNIEnv* env, jobject o, jclass module, jstring package)) + Modules::add_module_exports(env, module, package, NULL); +WB_END + +WB_ENTRY(void, WB_AddReadsModule(JNIEnv* env, jobject o, jobject from_module, jobject source_module)) + Modules::add_reads_module(env, from_module, source_module); +WB_END + +WB_ENTRY(jboolean, WB_CanReadModule(JNIEnv* env, jobject o, jobject asking_module, jobject source_module)) + return Modules::can_read_module(env, asking_module, source_module); +WB_END + +WB_ENTRY(jboolean, WB_IsExportedToModule(JNIEnv* env, jobject o, jobject from_module, jstring package, jobject to_module)) + return Modules::is_exported_to_module(env, from_module, package, to_module); +WB_END + +WB_ENTRY(void, WB_AddModulePackage(JNIEnv* env, jobject o, jclass module, jstring package)) + Modules::add_module_package(env, module, package); +WB_END + WB_ENTRY(jlong, WB_IncMetaspaceCapacityUntilGC(JNIEnv* env, jobject wb, jlong inc)) if (inc < 0) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -1262,7 +1296,6 @@ WB_END - WB_ENTRY(void, WB_AssertMatchingSafepointCalls(JNIEnv* env, jobject o, jboolean mutexSafepointValue, jboolean attemptedNoSafepointValue)) Monitor::SafepointCheckRequired sfpt_check_required = mutexSafepointValue ? Monitor::_safepoint_check_always : @@ -1360,6 +1393,10 @@ return MetaspaceShared::is_in_shared_space((void*)obj_oop); WB_END +WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) + return (jboolean)MetaspaceShared::is_in_shared_space(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); +WB_END + WB_ENTRY(jboolean, WB_AreSharedStringsIgnored(JNIEnv* env)) return StringTable::shared_string_ignored(); WB_END @@ -1589,6 +1626,22 @@ {CC"getCodeBlob", CC"(J)[Ljava/lang/Object;",(void*)&WB_GetCodeBlob }, {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, + {CC"DefineModule", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V", + (void*)&WB_DefineModule }, + {CC"AddModuleExports", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", + (void*)&WB_AddModuleExports }, + {CC"AddReadsModule", CC"(Ljava/lang/Object;Ljava/lang/Object;)V", + (void*)&WB_AddReadsModule }, + {CC"CanReadModule", CC"(Ljava/lang/Object;Ljava/lang/Object;)Z", + (void*)&WB_CanReadModule }, + {CC"IsExportedToModule", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z", + (void*)&WB_IsExportedToModule }, + {CC"AddModulePackage", CC"(Ljava/lang/Object;Ljava/lang/String;)V", + (void*)&WB_AddModulePackage }, + {CC"AddModuleExportsToAllUnnamed", CC"(Ljava/lang/Object;Ljava/lang/String;)V", + (void*)&WB_AddModuleExportsToAllUnnamed }, + {CC"AddModuleExportsToAll", CC"(Ljava/lang/Object;Ljava/lang/String;)V", + (void*)&WB_AddModuleExportsToAll }, {CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, @@ -1609,6 +1662,7 @@ CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/String;", (void*)&WB_GetMethodStringOption}, {CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared }, + {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass }, {CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored }, };
--- a/src/share/vm/runtime/arguments.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/arguments.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -91,6 +91,9 @@ const char* Arguments::_sun_java_launcher = DEFAULT_JAVA_LAUNCHER; int Arguments::_sun_java_launcher_pid = -1; bool Arguments::_sun_java_launcher_is_altjvm = false; +int Arguments::_patch_dirs_count = 0; +char** Arguments::_patch_dirs = NULL; +int Arguments::_bootclassloader_append_index = -1; // These parameters are reset in method parse_vm_init_args() bool Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods; @@ -115,6 +118,7 @@ SystemProperty *Arguments::_java_home = NULL; SystemProperty *Arguments::_java_class_path = NULL; SystemProperty *Arguments::_sun_boot_class_path = NULL; +SystemProperty *Arguments::_jdk_boot_class_path_append = NULL; char* Arguments::_ext_dirs = NULL; @@ -204,8 +208,15 @@ _sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL, true); _java_library_path = new SystemProperty("java.library.path", NULL, true); _java_home = new SystemProperty("java.home", NULL, true); + // Do not add sun.boot.class.path to the PropertyList because its JDK value + // should be NULL in JDK-9. But, keep it internally because its value is used + // by the JVM. _sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL, true); + // jdk.boot.class.path.append will only get set if -XX+bootclass/a: is specified. + // So, make sure it is initialized with a non-null value. + _jdk_boot_class_path_append = new SystemProperty("jdk.boot.class.path.append", "", true); + _java_class_path = new SystemProperty("java.class.path", "", true); // Add to System Property list. @@ -213,7 +224,8 @@ PropertyList_add(&_system_properties, _java_library_path); PropertyList_add(&_system_properties, _java_home); PropertyList_add(&_system_properties, _java_class_path); - PropertyList_add(&_system_properties, _sun_boot_class_path); + + PropertyList_add(&_system_properties, _jdk_boot_class_path_append); // Set OS specific system properties values os::init_system_properties_values(); @@ -361,7 +373,6 @@ { "AdaptiveSizePausePolicy", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "ParallelGCRetainPLAB", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "ThreadSafetyMargin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, - { "LazyBootClassLoader", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "StarvationMonitorInterval", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "PreInflateSpin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, @@ -526,8 +537,8 @@ // Constructs the system class path (aka boot class path) from the following // components, in order: // -// prefix // from -Xbootclasspath/p:... -// base // from os::get_system_properties() or -Xbootclasspath= +// prefix // from -Xpatch:... +// base // from os::get_system_properties() // suffix // from -Xbootclasspath/a:... // // This could be AllStatic, but it isn't needed after argument processing is @@ -561,7 +572,7 @@ // Array indices for the items that make up the sysclasspath. All except the // base are allocated in the C heap and freed by this class. enum { - _scp_prefix, // from -Xbootclasspath/p:... + _scp_prefix, // was -Xpatch:... _scp_base, // the default sysclasspath _scp_suffix, // from -Xbootclasspath/a:... _scp_nitems // the number of items, must be last. @@ -629,6 +640,10 @@ // Get the lengths. int i; for (i = 0; i < _scp_nitems; ++i) { + if (i == _scp_suffix) { + // Record index of boot loader's append path. + Arguments::set_bootclassloader_append_index((int)total_len); + } if (_items[i] != NULL) { lengths[i] = strlen(_items[i]); // Include space for the separator char (or a NULL for the last item). @@ -1332,6 +1347,54 @@ return true; } +// sets or adds a module name to the jdk.launcher.addmods property +bool Arguments::append_to_addmods_property(const char* module_name) { + const char* key = "jdk.launcher.addmods"; + const char* old_value = Arguments::get_property(key); + size_t buf_len = strlen(key) + strlen(module_name) + 2; + if (old_value != NULL) { + buf_len += strlen(old_value) + 1; + } + char* new_value = AllocateHeap(buf_len, mtInternal); + if (new_value == NULL) { + return false; + } + if (old_value == NULL) { + jio_snprintf(new_value, buf_len, "%s=%s", key, module_name); + } else { + jio_snprintf(new_value, buf_len, "%s=%s,%s", key, old_value, module_name); + } + bool added = add_property(new_value); + FreeHeap(new_value); + return added; +} + +#if INCLUDE_CDS +void Arguments::check_unsupported_dumping_properties() { + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); + const char* unsupported_properties[5] = { "jdk.module.main", + "jdk.module.path", + "jdk.upgrade.module.path", + "jdk.launcher.addmods", + "jdk.launcher.limitmods" }; + const char* unsupported_options[5] = { "-m", + "-modulepath", + "-upgrademodulepath", + "-addmods", + "-limitmods" }; + SystemProperty* sp = system_properties(); + while (sp != NULL) { + for (int i = 0; i < 5; i++) { + if (strcmp(sp->key(), unsupported_properties[i]) == 0) { + vm_exit_during_initialization( + "Cannot use the following option when dumping the shared archive", unsupported_options[i]); + } + } + sp = sp->next(); + } +} +#endif + //=========================================================================================================== // Setting int/mixed/comp mode flags @@ -2773,16 +2836,18 @@ JavaAssertions::setSystemClassDefault(enable); // -bootclasspath: } else if (match_option(option, "-Xbootclasspath:", &tail)) { - scp_p->reset_path(tail); - *scp_assembly_required_p = true; + jio_fprintf(defaultStream::output_stream(), + "-Xbootclasspath is no longer a supported option.\n"); + return JNI_EINVAL; // -bootclasspath/a: } else if (match_option(option, "-Xbootclasspath/a:", &tail)) { scp_p->add_suffix(tail); *scp_assembly_required_p = true; // -bootclasspath/p: } else if (match_option(option, "-Xbootclasspath/p:", &tail)) { - scp_p->add_prefix(tail); - *scp_assembly_required_p = true; + jio_fprintf(defaultStream::output_stream(), + "-Xbootclasspath/p is no longer a supported option.\n"); + return JNI_EINVAL; // -Xrun } else if (match_option(option, "-Xrun", &tail)) { if (tail != NULL) { @@ -2834,9 +2899,14 @@ "Instrumentation agents are not supported in this VM\n"); return JNI_ERR; #else - if(tail != NULL) { + if (tail != NULL) { char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail); add_init_agent("instrument", options, false); + // java agents need module java.instrument. Also -addmods ALL-SYSTEM because + // the java agent is in the unmamed module of the application class loader + if (!Arguments::append_to_addmods_property("java.instrument,ALL-SYSTEM")) { + return JNI_ENOMEM; + } } #endif // !INCLUDE_JVMTI // -Xnoclassgc @@ -3106,12 +3176,50 @@ if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != Flag::SUCCESS) { return JNI_EINVAL; } + // management agent in module java.management + if (!Arguments::append_to_addmods_property("java.management")) { + return JNI_ENOMEM; + } #else jio_fprintf(defaultStream::output_stream(), "-Dcom.sun.management is not supported in this VM.\n"); return JNI_ERR; #endif } + if (match_option(option, "-Djdk.launcher.patchdirs=", &tail)) { + // -Xpatch + int dir_count; + char** patch_dirs = os::split_path(tail, &dir_count); + if (patch_dirs == NULL) { + jio_fprintf(defaultStream::output_stream(), + "Bad value for -Xpatch.\n"); + return JNI_ERR; + } + set_patch_dirs(patch_dirs); + set_patch_dirs_count(dir_count); + + // Create a path for each patch dir consisting of dir/java.base. + char file_sep = os::file_separator()[0]; + for (int x = 0; x < dir_count; x++) { + // Really shouldn't be NULL, but check can't hurt + if (patch_dirs[x] != NULL) { + size_t len = strlen(patch_dirs[x]); + if (len != 0) { // Ignore empty strings. + len += 11; // file_sep + "java.base" + null terminator. + char* dir = NEW_C_HEAP_ARRAY(char, len, mtInternal); + jio_snprintf(dir, len, "%s%cjava.base", patch_dirs[x], file_sep); + + // See if Xpatch module path exists. + struct stat st; + if ((os::stat(dir, &st) == 0)) { + scp_p->add_prefix(dir); + *scp_assembly_required_p = true; + } + FREE_C_HEAP_ARRAY(char, dir); + } + } + } + } // -Xint } else if (match_option(option, "-Xint")) { set_mode_flags(_int); @@ -3387,6 +3495,18 @@ return JNI_OK; } +// Set property jdk.boot.class.path.append to the contents of the bootclasspath +// that follows either the jimage file or exploded module directories. The +// property will contain -Xbootclasspath/a and/or jvmti appended additions. +void Arguments::set_jdkbootclasspath_append() { + char *sysclasspath = get_sysclasspath(); + assert(sysclasspath != NULL, "NULL sysclasspath"); + int bcp_a_idx = bootclassloader_append_index(); + if (bcp_a_idx != -1 && bcp_a_idx < (int)strlen(sysclasspath)) { + _jdk_boot_class_path_append->set_value(sysclasspath + bcp_a_idx); + } +} + // Remove all empty paths from the app classpath (if IgnoreEmptyClassPaths is enabled) // // This is necessary because some apps like to specify classpath like -cp foo.jar:${XYZ}:bar.jar @@ -3524,6 +3644,11 @@ char *combined_path = scp_p->combined_path(); Arguments::set_sysclasspath(combined_path); FREE_C_HEAP_ARRAY(char, combined_path); + } else { + // At this point in sysclasspath processing anything + // added would be considered in the boot loader's append path. + // Record this index, including +1 for the file separator character. + Arguments::set_bootclassloader_append_index(((int)strlen(Arguments::get_sysclasspath()))+1); } // This must be done after all arguments have been processed. @@ -3852,6 +3977,11 @@ void Arguments::set_shared_spaces_flags() { if (DumpSharedSpaces) { + if (Arguments::patch_dirs() != NULL) { + vm_exit_during_initialization( + "Cannot use the following option when dumping the shared archive", "-Xpatch"); + } + if (RequireSharedSpaces) { warning("Cannot dump shared archive while using shared archive"); }
--- a/src/share/vm/runtime/arguments.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/arguments.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -262,6 +262,7 @@ static SystemProperty *_java_home; static SystemProperty *_java_class_path; static SystemProperty *_sun_boot_class_path; + static SystemProperty *_jdk_boot_class_path_append; // temporary: to emit warning if the default ext dirs are not empty. // remove this variable when the warning is no longer needed. @@ -286,7 +287,7 @@ // Value of the conservative maximum heap alignment needed static size_t _conservative_max_heap_alignment; - static uintx _min_heap_size; + static uintx _min_heap_size; // -Xrun arguments static AgentLibraryList _libraryList; @@ -311,6 +312,17 @@ static void set_java_compiler(bool arg) { _java_compiler = arg; } static bool java_compiler() { return _java_compiler; } + // Capture the index location of -Xbootclasspath\a within sysclasspath. + // Used when setting up the bootstrap search path in order to + // mark the boot loader's append path observability boundary. + static int _bootclassloader_append_index; + + // -Xpatch flag + static char** _patch_dirs; + static int _patch_dirs_count; + static void set_patch_dirs(char** dirs) { _patch_dirs = dirs; } + static void set_patch_dirs_count(int count) { _patch_dirs_count = count; } + // -Xdebug flag static bool _xdebug_mode; static void set_xdebug_mode(bool arg) { _xdebug_mode = arg; } @@ -361,6 +373,9 @@ // System properties static bool add_property(const char* prop); + // Miscellaneous system property setter + static bool append_to_addmods_property(const char* module_name); + // Aggressive optimization flags. static jint set_aggressive_opts_flags(); @@ -546,6 +561,18 @@ static size_t min_heap_size() { return _min_heap_size; } static void set_min_heap_size(size_t v) { _min_heap_size = v; } + // -Xbootclasspath/a + static int bootclassloader_append_index() { + return _bootclassloader_append_index; + } + static void set_bootclassloader_append_index(int value) { + _bootclassloader_append_index = value; + } + + // -Xpatch + static char** patch_dirs() { return _patch_dirs; } + static int patch_dirs_count() { return _patch_dirs_count; } + // -Xrun static AgentLibrary* libraries() { return _libraryList.first(); } static bool init_libraries_at_startup() { return !_libraryList.is_empty(); } @@ -602,8 +629,15 @@ static void set_java_home(const char *value) { _java_home->set_value(value); } static void set_library_path(const char *value) { _java_library_path->set_value(value); } static void set_ext_dirs(char *value) { _ext_dirs = os::strdup_check_oom(value); } - static void set_sysclasspath(const char *value) { _sun_boot_class_path->set_value(value); } - static void append_sysclasspath(const char *value) { _sun_boot_class_path->append_value(value); } + static void set_jdkbootclasspath_append(); + static void set_sysclasspath(const char *value) { + _sun_boot_class_path->set_value(value); + set_jdkbootclasspath_append(); + } + static void append_sysclasspath(const char *value) { + _sun_boot_class_path->append_value(value); + set_jdkbootclasspath_append(); + } static char* get_java_home() { return _java_home->value(); } static char* get_dll_dir() { return _sun_boot_library_path->value(); } @@ -614,12 +648,14 @@ // Operation modi - static Mode mode() { return _mode; } + static Mode mode() { return _mode; } static bool is_interpreter_only() { return mode() == _int; } // Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid. static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen); + + static void check_unsupported_dumping_properties() NOT_CDS_RETURN; }; bool Arguments::gc_selected() {
--- a/src/share/vm/runtime/frame.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/frame.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -642,6 +642,13 @@ m->name_and_sig_as_C_string(buf, buflen); st->print("j %s", buf); st->print("+%d", this->interpreter_frame_bci()); + ModuleEntry* module = m->method_holder()->module(); + if (module->is_named()) { + module->name()->as_C_string(buf, buflen); + st->print(" %s", buf); + module->version()->as_C_string(buf, buflen); + st->print("@%s", buf); + } } else { st->print("j " PTR_FORMAT, p2i(pc())); } @@ -668,8 +675,15 @@ st->print(" (%s)", jvmciName); } #endif - st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", - buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); + ModuleEntry* module = m->method_holder()->module(); + if (module->is_named()) { + module->name()->as_C_string(buf, buflen); + st->print(" %s", buf); + module->version()->as_C_string(buf, buflen); + st->print("@%s", buf); + } + st->print("(%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", + m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); } else { st->print("J " PTR_FORMAT, p2i(pc())); }
--- a/src/share/vm/runtime/globals.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/globals.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -2486,6 +2486,9 @@ develop(bool, TraceClassLoaderData, false, \ "Trace class loader loader_data lifetime") \ \ + develop(bool, TraceModules, false, \ + "Trace module creation and lifetime") \ + \ product(size_t, InitialBootClassLoaderMetaspaceSize, \ NOT_LP64(2200*K) LP64_ONLY(4*M), \ "Initial size of the boot class loader data metaspace") \
--- a/src/share/vm/runtime/jniHandles.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/jniHandles.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -472,6 +472,14 @@ return allocate_handle(obj); // retry } +void JNIHandleBlock::release_handle(jobject h) { + if (h != NULL) { + assert(chain_contains(h), "does not contain the JNI handle"); + // Mark the handle as deleted, allocate will reuse it + *((oop*)h) = JNIHandles::deleted_handle(); + } +} + void JNIHandleBlock::rebuild_free_list() { assert(_allocate_before_rebuild == 0 && _free_list == NULL, "just checking");
--- a/src/share/vm/runtime/jniHandles.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/jniHandles.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -138,6 +138,9 @@ // Handle allocation jobject allocate_handle(oop obj); + // Release Handle + void release_handle(jobject); + // Block allocation and block free list management static JNIHandleBlock* allocate_block(Thread* thread = NULL); static void release_block(JNIHandleBlock* block, Thread* thread = NULL);
--- a/src/share/vm/runtime/mutexLocker.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/mutexLocker.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -41,6 +41,7 @@ Mutex* Patching_lock = NULL; Monitor* SystemDictionary_lock = NULL; Mutex* PackageTable_lock = NULL; +Mutex* Module_lock = NULL; Mutex* CompiledIC_lock = NULL; Mutex* InlineCacheBuffer_lock = NULL; Mutex* VMStatistic_lock = NULL; @@ -218,7 +219,8 @@ def(JmethodIdCreation_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); // used for creating jmethodIDs. def(SystemDictionary_lock , Monitor, leaf, true, Monitor::_safepoint_check_always); // lookups done by VM thread - def(PackageTable_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); + def(PackageTable_lock , Mutex , nonleaf, false, Monitor::_safepoint_check_always); + def(Module_lock , Mutex , nonleaf , true, Monitor::_safepoint_check_always); def(InlineCacheBuffer_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); def(VMStatistic_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); def(ExpandHeap_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); // Used during compilation by VM thread
--- a/src/share/vm/runtime/mutexLocker.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/mutexLocker.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -33,6 +33,7 @@ extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code extern Monitor* SystemDictionary_lock; // a lock on the system dictionary extern Mutex* PackageTable_lock; // a lock on the class loader package table +extern Mutex* Module_lock; // a lock on module related data structures extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
--- a/src/share/vm/runtime/os.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/os.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -1204,63 +1204,10 @@ return formatted_path; } -// returns a PATH of all entries in the given directory that do not start with a '.' -static char* expand_entries_to_path(char* directory, char fileSep, char pathSep) { - DIR* dir = os::opendir(directory); - if (dir == NULL) return NULL; - - char* path = NULL; - size_t path_len = 0; // path length including \0 terminator - - size_t directory_len = strlen(directory); - struct dirent *entry; - char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal); - while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { - const char* name = entry->d_name; - if (name[0] == '.') continue; - - size_t name_len = strlen(name); - size_t needed = directory_len + name_len + 2; - size_t new_len = path_len + needed; - if (path == NULL) { - path = NEW_C_HEAP_ARRAY(char, new_len, mtInternal); - } else { - path = REALLOC_C_HEAP_ARRAY(char, path, new_len, mtInternal); - } - if (path == NULL) - break; - - // append <pathSep>directory<fileSep>name - char* p = path; - if (path_len > 0) { - p += (path_len -1); - *p = pathSep; - p++; - } - - strcpy(p, directory); - p += directory_len; - - *p = fileSep; - p++; - - strcpy(p, name); - p += name_len; - - path_len = new_len; - } - - FREE_C_HEAP_ARRAY(char, dbuf); - os::closedir(dir); - - return path; -} - bool os::set_boot_path(char fileSep, char pathSep) { const char* home = Arguments::get_java_home(); int home_len = (int)strlen(home); - char* sysclasspath = NULL; struct stat st; // modular image if bootmodules.jimage exists @@ -1275,23 +1222,16 @@ FREE_C_HEAP_ARRAY(char, jimage); // check if developer build with exploded modules - char* modules_dir = format_boot_path("%/modules", home, home_len, fileSep, pathSep); - if (os::stat(modules_dir, &st) == 0) { - if ((st.st_mode & S_IFDIR) == S_IFDIR) { - sysclasspath = expand_entries_to_path(modules_dir, fileSep, pathSep); - } + char* base_classes = format_boot_path("%/modules/java.base", home, home_len, fileSep, pathSep); + if (base_classes == NULL) return false; + if (os::stat(base_classes, &st) == 0) { + Arguments::set_sysclasspath(base_classes); + FREE_C_HEAP_ARRAY(char, base_classes); + return true; } - FREE_C_HEAP_ARRAY(char, modules_dir); + FREE_C_HEAP_ARRAY(char, base_classes); - // fallback to classes - if (sysclasspath == NULL) - sysclasspath = format_boot_path("%/classes", home, home_len, fileSep, pathSep); - - if (sysclasspath == NULL) return false; - Arguments::set_sysclasspath(sysclasspath); - FREE_C_HEAP_ARRAY(char, sysclasspath); - - return true; + return false; } /*
--- a/src/share/vm/runtime/os.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/os.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -776,6 +776,8 @@ // Amount beyond the callee frame size that we bang the stack. static int extra_bang_size_in_bytes(); + static char** split_path(const char* path, int* n); + // Extensions #include "runtime/os_ext.hpp" @@ -991,7 +993,6 @@ char fileSep, char pathSep); static bool set_boot_path(char fileSep, char pathSep); - static char** split_path(const char* path, int* n); };
--- a/src/share/vm/runtime/reflection.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/reflection.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" @@ -411,23 +413,155 @@ } -bool Reflection::verify_class_access(Klass* current_class, Klass* new_class, bool classloader_only) { + +/* + Type Accessibility check for public types: Callee Type T is accessible to Caller Type S if: + + Callee T in Callee T in package PT, + unnamed module runtime module MT + ------------------------------------------------------------------------------------------------ + + Caller S in package If MS is loose: YES If same classloader/package (PS == PT): YES + PS, runtime module MS If same runtime module: (MS == MT): YES + + Else if (MS can read MT (Establish readability) && + MT exports PT to MS or to all modules): YES + + ------------------------------------------------------------------------------------------------ + Caller S in unnamed YES Readability exists because unnamed module + module UM "reads" all modules + if (MT exports PT to UM or to all modules): YES + + ------------------------------------------------------------------------------------------------ +*/ +Reflection::VerifyClassAccessResults Reflection::verify_class_access( + Klass* current_class, Klass* new_class, bool classloader_only) { + // Verify that current_class can access new_class. If the classloader_only // flag is set, we automatically allow any accesses in which current_class // doesn't have a classloader. if ((current_class == NULL) || (current_class == new_class) || - (new_class->is_public()) || is_same_class_package(current_class, new_class)) { - return true; + return ACCESS_OK; } // Allow all accesses from sun/reflect/MagicAccessorImpl subclasses to // succeed trivially. if (current_class->is_subclass_of(SystemDictionary::reflect_MagicAccessorImpl_klass())) { - return true; + return ACCESS_OK; } - return can_relax_access_check_for(current_class, new_class, classloader_only); + // module boundaries + if (new_class->is_public()) { + // Ignore modules for DumpSharedSpaces because we do not have any package + // or module information for modules other than java.base. + if (DumpSharedSpaces) { + return ACCESS_OK; + } + + // Find the module entry for current_class, the accessor + ModuleEntry* module_from = InstanceKlass::cast(current_class)->module(); + // Find the module entry for new_class, the accessee + if (new_class->is_objArray_klass()) { + new_class = ObjArrayKlass::cast(new_class)->bottom_klass(); + } + if (!new_class->is_instance_klass()) { + // Everyone can read a typearray. + return ACCESS_OK; + } + ModuleEntry* module_to = InstanceKlass::cast(new_class)->module(); + + // both in same (possibly unnamed) module + if (module_from == module_to) + return ACCESS_OK; + + // Acceptable access to a type in an unamed module. Note that since + // unnamed modules can read all unnamed modules, this also handles the + // case where module_from is also unnamed but in a different class loader. + if (!module_to->is_named() && + (module_from->can_read_unnamed() || module_from->can_read(module_to))) + return ACCESS_OK; + + // Establish readability, check if module_from is allowed to read module_to. + if (!module_from->can_read(module_to)) { + return MODULE_NOT_READABLE; + } + + PackageEntry* package_to = InstanceKlass::cast(new_class)->package(); + assert(package_to != NULL, "can not obtain new_class' package"); + + // Once readability is established, if module_to exports T unqualifiedly, + // (to all modules), than whether module_from is in the unnamed module + // or not does not matter, access is allowed. + if (package_to->is_unqual_exported()) { + return ACCESS_OK; + } + + // Access is allowed if both 1 & 2 hold: + // 1. Readability, module_from can read module_to (established above). + // 2. Either module_to exports T to module_from qualifiedly. + // or + // module_to exports T to all unnamed modules and module_from is unnamed. + // or + // module_to exports T unqualifiedly to all modules (checked above). + if (!package_to->is_qexported_to(module_from)) { + return TYPE_NOT_EXPORTED; + } + return ACCESS_OK; + } + + if (can_relax_access_check_for(current_class, new_class, classloader_only)) { + return ACCESS_OK; + } + return OTHER_PROBLEM; +} + +// Return an error message specific to the specified Klass*'s and result. +// This function must be called from within a block containing a ResourceMark. +char* Reflection::verify_class_access_msg(Klass* current_class, + Klass* new_class, + VerifyClassAccessResults result) { + assert(result != ACCESS_OK, "must be failure result"); + char * msg = NULL; + if (result != OTHER_PROBLEM && new_class != NULL && current_class != NULL) { + ModuleEntry* module_to = InstanceKlass::cast(new_class)->module(); + const char * new_class_name = new_class->external_name(); + const char * current_class_name = current_class->external_name(); + const char * module_to_name = module_to->is_named() ? + module_to->name()->as_C_string() : UNNAMED_MODULE; + + ModuleEntry* module_from = InstanceKlass::cast(current_class)->module(); + const char * module_from_name = module_from->is_named() ? + module_from->name()->as_C_string() : UNNAMED_MODULE; + size_t len = 122 + strlen(current_class_name) + strlen(new_class_name) + + strlen(module_to_name) + 2 * strlen(module_from_name); + + if (result == MODULE_NOT_READABLE) { + len = len + strlen(module_to_name); + msg = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(msg, len - 1, + "class %s (in%s module: %s) cannot access class %s (in module: %s), %s cannot read %s", + current_class_name, + module_to->is_named() ? "" : " strict", + module_from_name, new_class_name, + module_to_name, module_from_name, module_to_name); + + } else if (result == TYPE_NOT_EXPORTED) { + if (InstanceKlass::cast(new_class)->package() != NULL) { + const char * package_name = + InstanceKlass::cast(new_class)->package()->name()->as_klass_external_name(); + len = len + strlen(package_name); + msg = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(msg, len - 1, + "class %s (in module: %s) cannot access class %s (in module: %s), %s is not exported to %s", + current_class_name, module_from_name, new_class_name, + module_to_name, package_name, module_from_name); + } + } else { + ShouldNotReachHere(); + } + } // result != OTHER_PROBLEM... + return msg; } static bool under_host_klass(InstanceKlass* ik, Klass* host_klass) {
--- a/src/share/vm/runtime/reflection.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/reflection.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -63,6 +63,14 @@ MAX_DIM = 255 }; + // Results returned by verify_class_access() + enum VerifyClassAccessResults { + ACCESS_OK = 0, + MODULE_NOT_READABLE = 1, + TYPE_NOT_EXPORTED = 2, + OTHER_PROBLEM = 3 + }; + // Boxing. Returns boxed value of appropriate type. Throws IllegalArgumentException. static oop box(jvalue* v, BasicType type, TRAPS); // Unboxing. Returns type code and sets value. @@ -83,7 +91,15 @@ static arrayOop reflect_new_multi_array(oop element_mirror, typeArrayOop dimensions, TRAPS); // Verification - static bool verify_class_access(Klass* current_class, Klass* new_class, bool classloader_only); + static VerifyClassAccessResults verify_class_access(Klass* current_class, + Klass* new_class, + bool classloader_only); + + // Return an error message specific to the specified Klass*'s and result. + // This function must be called from within a block containing a ResourceMark. + static char* verify_class_access_msg(Klass* current_class, + Klass* new_class, + VerifyClassAccessResults result); static bool verify_field_access(Klass* current_class, Klass* resolved_class,
--- a/src/share/vm/runtime/sharedRuntime.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/sharedRuntime.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -39,6 +39,8 @@ #include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" #include "memory/universe.inline.hpp" +#include "oops/klass.hpp" +#include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/forte.hpp" #include "prims/jvmtiExport.hpp" @@ -1841,28 +1843,58 @@ } JRT_END +// The caller of generate_class_cast_message() (or one of its callers) +// must use a ResourceMark in order to correctly free the result. char* SharedRuntime::generate_class_cast_message( - JavaThread* thread, const char* objName) { + JavaThread* thread, Klass* caster_klass) { // Get target class name from the checkcast instruction vframeStream vfst(thread, true); assert(!vfst.at_end(), "Java frame must exist"); Bytecode_checkcast cc(vfst.method(), vfst.method()->bcp_from(vfst.bci())); - Klass* targetKlass = vfst.method()->constants()->klass_at( + Klass* target_klass = vfst.method()->constants()->klass_at( cc.index(), thread); - return generate_class_cast_message(objName, targetKlass->external_name()); + return generate_class_cast_message(caster_klass, target_klass); } char* SharedRuntime::generate_class_cast_message( - const char* objName, const char* targetKlassName, const char* desc) { - size_t msglen = strlen(objName) + strlen(desc) + strlen(targetKlassName) + 1; + Klass* caster_klass, Klass* target_klass) { + + const char* caster_klass_name = caster_klass->external_name(); + Klass* c_klass = caster_klass->is_objArray_klass() ? + ObjArrayKlass::cast(caster_klass)->bottom_klass() : caster_klass; + ModuleEntry* caster_module; + const char* caster_module_name; + if (c_klass->is_instance_klass()) { + caster_module = InstanceKlass::cast(c_klass)->module(); + caster_module_name = caster_module->is_named() ? + caster_module->name()->as_C_string() : UNNAMED_MODULE; + } else { + caster_module_name = "java.base"; + } + const char* target_klass_name = target_klass->external_name(); + Klass* t_klass = target_klass->is_objArray_klass() ? + ObjArrayKlass::cast(target_klass)->bottom_klass() : target_klass; + ModuleEntry* target_module; + const char* target_module_name; + if (t_klass->is_instance_klass()) { + target_module = InstanceKlass::cast(t_klass)->module(); + target_module_name = target_module->is_named() ? + target_module->name()->as_C_string(): UNNAMED_MODULE; + } else { + target_module_name = "java.base"; + } + + size_t msglen = strlen(caster_klass_name) + strlen(caster_module_name) + + strlen(target_klass_name) + strlen(target_module_name) + 50; char* message = NEW_RESOURCE_ARRAY(char, msglen); if (NULL == message) { // Shouldn't happen, but don't cause even more problems if it does - message = const_cast<char*>(objName); + message = const_cast<char*>(caster_klass_name); } else { - jio_snprintf(message, msglen, "%s%s%s", objName, desc, targetKlassName); + jio_snprintf(message, msglen, "%s (in module: %s) cannot be cast to %s (in module: %s)", + caster_klass_name, caster_module_name, target_klass_name, target_module_name); } return message; }
--- a/src/share/vm/runtime/sharedRuntime.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/sharedRuntime.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -283,22 +283,21 @@ // Fill in the "X cannot be cast to a Y" message for ClassCastException // // @param thr the current thread - // @param name the name of the class of the object attempted to be cast + // @param caster_klass the class of the object we are casting // @return the dynamically allocated exception message (must be freed // by the caller using a resource mark) // // BCP must refer to the current 'checkcast' opcode for the frame // on top of the stack. - // The caller (or one of it's callers) must use a ResourceMark + // The caller (or one of its callers) must use a ResourceMark // in order to correctly free the result. // - static char* generate_class_cast_message(JavaThread* thr, const char* name); + static char* generate_class_cast_message(JavaThread* thr, Klass* caster_klass); // Fill in the "X cannot be cast to a Y" message for ClassCastException // - // @param name the name of the class of the object attempted to be cast - // @param klass the name of the target klass attempt - // @param gripe the specific kind of problem being reported + // @param caster_klass the class of the object we are casting + // @param target_klass the target klass attempt // @return the dynamically allocated exception message (must be freed // by the caller using a resource mark) // @@ -307,8 +306,7 @@ // The caller (or one of it's callers) must use a ResourceMark // in order to correctly free the result. // - static char* generate_class_cast_message(const char* name, const char* klass, - const char* gripe = " cannot be cast to "); + static char* generate_class_cast_message(Klass* caster_klass, Klass* target_klass); // Resolves a call site- may patch in the destination of the call into the // compiled code.
--- a/src/share/vm/runtime/statSampler.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/statSampler.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -237,7 +237,6 @@ // unstable interface, unsupported counters static const char* property_counters_uu[] = { - "sun.boot.class.path", "sun.boot.library.path", NULL };
--- a/src/share/vm/runtime/thread.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/thread.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -116,6 +117,9 @@ #include "runtime/rtmLocking.hpp" #endif +// Initialization after module runtime initialization +void universe_post_module_init(); // must happen after call_initPhase2 + #ifdef DTRACE_ENABLED // Only bother with this argument setup if dtrace is available @@ -992,15 +996,6 @@ return thread_oop(); } -static void call_initializeSystemClass(TRAPS) { - Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); - instanceKlassHandle klass (THREAD, k); - - JavaValue result(T_VOID); - JavaCalls::call_static(&result, klass, vmSymbols::initializeSystemClass_name(), - vmSymbols::void_method_signature(), CHECK); -} - char java_runtime_name[128] = ""; char java_runtime_version[128] = ""; @@ -3284,6 +3279,34 @@ // If CompilerThreads ever become non-JavaThreads, add them here } +static void call_initPhase1(TRAPS) { + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); + instanceKlassHandle klass (THREAD, k); + + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbols::initPhase1_name(), + vmSymbols::void_method_signature(), CHECK); +} + +static void call_initPhase2(TRAPS) { + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); + instanceKlassHandle klass (THREAD, k); + + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbols::initPhase2_name(), + vmSymbols::void_method_signature(), CHECK); + universe_post_module_init(); +} + +static void call_initPhase3(TRAPS) { + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); + instanceKlassHandle klass (THREAD, k); + + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbols::initPhase3_name(), + vmSymbols::void_method_signature(), CHECK); +} + void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { TraceTime timer("Initialize java.lang classes", TraceStartupTime); @@ -3311,10 +3334,13 @@ java_lang_Thread::set_thread_status(thread_object, java_lang_Thread::RUNNABLE); + // The VM creates objects of this class. + initialize_class(vmSymbols::java_lang_reflect_Module(), CHECK); + // The VM preresolves methods to these classes. Make sure that they get initialized initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK); initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK); - call_initializeSystemClass(CHECK); + call_initPhase1(CHECK); // get the Java runtime name after java.lang.System is initialized JDK_Version::set_runtime_name(get_java_runtime_name(THREAD)); @@ -3528,13 +3554,6 @@ ShouldNotReachHere(); } - // Always call even when there are not JVMTI environments yet, since environments - // may be attached late and JVMTI must track phases of VM execution - JvmtiExport::enter_start_phase(); - - // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. - JvmtiExport::post_vm_start(); - initialize_java_lang_classes(main_thread, CHECK_JNI_ERR); // We need this for ClassDataSharing - the initial vm.info property is set @@ -3563,12 +3582,9 @@ Management::record_vm_init_completed(); #endif // INCLUDE_MANAGEMENT - // Compute system loader. Note that this has to occur after set_init_completed, since - // valid exceptions may be thrown in the process. // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and // set_init_completed has just been called, causing exceptions not to be shortcut // anymore. We call vm_exit_during_initialization directly instead. - SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); #if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up @@ -3583,10 +3599,6 @@ } #endif // INCLUDE_ALL_GCS - // Always call even when there are not JVMTI environments yet, since environments - // may be attached late and JVMTI must track phases of VM execution - JvmtiExport::enter_live_phase(); - // Signal Dispatcher needs to be started before VMInit event is posted os::signal_init(); @@ -3605,13 +3617,6 @@ create_vm_init_libraries(); } - // Notify JVMTI agents that VM initialization is complete - nop if no agents. - JvmtiExport::post_vm_initialized(); - - if (TRACE_START() != JNI_OK) { - vm_exit_during_initialization("Failed to start tracing backend."); - } - if (CleanChunkPoolAsync) { Chunk::start_chunk_pool_cleaner_task(); } @@ -3637,6 +3642,64 @@ // (see SystemDictionary::find_method_handle_intrinsic). initialize_jsr292_core_classes(CHECK_JNI_ERR); + // The system initialization in the library has three phases + // Phase 1: java.lang.System class initialization + // java.lang.System is a primordial class loaded and initialized + // by the VM early during startup. java.lang.System.<clinit> + // only does registerNatives and keep the rest of the class + // initialization work later until thread initialization completes. + // + // System.initPhase1 initializes the system properties, the static + // fields in, out, and err. Setup java signal handlers, OS-specific + // system settings, and set thread group of the main thread. + // + // see initialize_java_lang_classes + // + // Phase 2. Module system initialization + // This will initialize the module system. Only java.base classes + // can be loaded until phase 2 completes. + // + // Call System.initPhase2 after the compiler initialization and jsr292 + // classes get initialized because module initialization runs a lot of java + // code, that for performance reasons, should be compiled. Also, this will + // enable the startup code to use lambda and other language features in this + // phase and onward. + // + // After phase 2, The VM will begin search classes from -Xbootclasspath/a. + // + // Phase 3. final setup - set security manager, system class loader and TCCL + // + // This will instantiate and set the security manager, set the system class + // loader as well as the thread context class loader. The security manager + // and system class loader may be a custom class loaded from -Xbootclasspath/a, + // other modules or the application's classpath. + + call_initPhase2(CHECK_JNI_ERR); + + // Always call even when there are not JVMTI environments yet, since environments + // may be attached late and JVMTI must track phases of VM execution + JvmtiExport::enter_start_phase(); + + // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. + JvmtiExport::post_vm_start(); + + // Final system initialization including security manager and system class loader. + call_initPhase3(CHECK_JNI_ERR); + + // cache the system class loader + SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); + + // Always call even when there are not JVMTI environments yet, since environments + // may be attached late and JVMTI must track phases of VM execution + JvmtiExport::enter_live_phase(); + + if (TRACE_START() != JNI_OK) { + vm_exit_during_initialization("Failed to start tracing backend."); + } + + // Notify JVMTI agents that VM initialization is complete - nop if no agents. + JvmtiExport::post_vm_initialized(); + #if INCLUDE_MANAGEMENT Management::initialize(THREAD);
--- a/src/share/vm/runtime/vmStructs.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/runtime/vmStructs.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -1352,10 +1352,11 @@ /* java_lang_Class fields */ \ /*********************************/ \ \ - static_field(java_lang_Class, _klass_offset, int) \ - static_field(java_lang_Class, _array_klass_offset, int) \ - static_field(java_lang_Class, _oop_size_offset, int) \ - static_field(java_lang_Class, _static_oop_field_count_offset, int) \ + static_field(java_lang_Class, _klass_offset, int) \ + static_field(java_lang_Class, _array_klass_offset, int) \ + static_field(java_lang_Class, _oop_size_offset, int) \ + static_field(java_lang_Class, _static_oop_field_count_offset, int) \ + static_field(java_lang_Class, _module_offset, int) \ \ /************************/ \ /* Miscellaneous fields */ \
--- a/src/share/vm/services/jmm.h Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/services/jmm.h Mon Nov 30 14:57:39 2015 -0800 @@ -59,7 +59,6 @@ unsigned int isThreadContentionMonitoringSupported : 1; unsigned int isCurrentThreadCpuTimeSupported : 1; unsigned int isOtherThreadCpuTimeSupported : 1; - unsigned int isBootClassPathSupported : 1; unsigned int isObjectMonitorUsageSupported : 1; unsigned int isSynchronizerUsageSupported : 1; unsigned int isThreadAllocatedMemorySupported : 1;
--- a/src/share/vm/services/management.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/services/management.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -125,7 +125,6 @@ _optional_support.isOtherThreadCpuTimeSupported = 0; } - _optional_support.isBootClassPathSupported = 1; _optional_support.isObjectMonitorUsageSupported = 1; #if INCLUDE_SERVICES // This depends on the heap inspector
--- a/src/share/vm/trace/traceDataTypes.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/trace/traceDataTypes.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -58,12 +58,11 @@ typedef enum ReservedEvent ReservedEvent; -typedef u8 classid; -typedef u8 stacktraceid; -typedef u8 methodid; -typedef u8 fieldid; +typedef u8 traceid; +class ModuleEntry; +class PackageEntry; class TraceUnicodeString; +class Symbol; #endif // SHARE_VM_TRACE_TRACEDATATYPES_HPP -
--- a/src/share/vm/trace/traceMacros.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/trace/traceMacros.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -28,16 +28,18 @@ #define EVENT_THREAD_EXIT(thread) #define EVENT_THREAD_DESTRUCT(thread) -#define TRACE_INIT_ID(k) +#define TRACE_INIT_KLASS_ID(k) +#define TRACE_INIT_MODULE_ID(m) +#define TRACE_INIT_PACKAGE_ID(p) #define TRACE_DATA TraceThreadData #define TRACE_START() JNI_OK #define TRACE_INITIALIZE() JNI_OK -#define TRACE_DEFINE_KLASS_METHODS typedef int ___IGNORED_hs_trace_type1 -#define TRACE_DEFINE_KLASS_TRACE_ID typedef int ___IGNORED_hs_trace_type2 -#define TRACE_DEFINE_OFFSET typedef int ___IGNORED_hs_trace_type3 -#define TRACE_ID_OFFSET in_ByteSize(0); ShouldNotReachHere() +#define TRACE_DEFINE_TRACE_ID_METHODS typedef int ___IGNORED_hs_trace_type1 +#define TRACE_DEFINE_TRACE_ID_FIELD typedef int ___IGNORED_hs_trace_type2 +#define TRACE_DEFINE_KLASS_TRACE_ID_OFFSET typedef int ___IGNORED_hs_trace_type3 +#define TRACE_KLASS_TRACE_ID_OFFSET in_ByteSize(0); ShouldNotReachHere() #define TRACE_TEMPLATES(template) #define TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias)
--- a/src/share/vm/trace/traceTypes.xsl Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/trace/traceTypes.xsl Mon Nov 30 14:57:39 2015 -0800 @@ -32,7 +32,6 @@ #ifndef TRACEFILES_TRACETYPES_HPP #define TRACEFILES_TRACETYPES_HPP -#include "oops/symbol.hpp" #include "trace/traceDataTypes.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ticks.hpp"
--- a/src/share/vm/trace/tracetypes.xml Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/trace/tracetypes.xml Mon Nov 30 14:57:39 2015 -0800 @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. This code is free software; you can redistribute it and/or modify it @@ -89,6 +89,7 @@ type="U8" builtin_type="CLASS"> <value type="CLASS" field="loaderClass" label="ClassLoader"/> <value type="SYMBOL" field="name" label="Name"/> + <value type="PACKAGE" field="package" label="Package"/> <value type="SHORT" field="modifiers" label="Access modifiers"/> </content_type> @@ -176,6 +177,20 @@ <value type="UTF8" field="type" label="type" /> </content_type> + <content_type id="Module" hr_name="Module" + type="U8" jvm_type="MODULE"> + <value type="SYMBOL" field="name" label="Name"/> + <value type="SYMBOL" field="version" label="Version"/> + <value type="SYMBOL" field="location" label="Location"/> + <value type="CLASS" field="classLoader" label="ClassLoader"/> + </content_type> + + <content_type id="Package" hr_name="Package" + type="U8" jvm_type="PACKAGE"> + <value type="SYMBOL" field="name" label="Name"/> + <value type="MODULE" field="module" label="Module"/> + <value type="BOOLEAN" field="exported" label="Exported"/> + </content_type> </content_types> @@ -292,6 +307,12 @@ <primary_type symbol="CLASS" datatype="U8" contenttype="CLASS" type="Klass *" sizeop="sizeof(u8)"/> + <primary_type symbol="MODULE" datatype="U8" contenttype="MODULE" + type="const ModuleEntry *" sizeop="sizeof(u8)"/> + + <primary_type symbol="PACKAGE" datatype="U8" contenttype="PACKAGE" + type="const PackageEntry *" sizeop="sizeof(u8)"/> + <!-- A Method *. The method is marked as "used" and will eventually be written into the recording constant pool. --> <primary_type symbol="METHOD" datatype="U8" contenttype="METHOD"
--- a/src/share/vm/utilities/dtrace_disabled.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/utilities/dtrace_disabled.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -1084,6 +1084,12 @@ #define HOTSPOT_JNI_UNREGISTERNATIVES_RETURN(arg0) #define HOTSPOT_JNI_UNREGISTERNATIVES_RETURN_ENABLED() 0 +/* Modules */ +#define HOTSPOT_JNI_GETMODULE_ENTRY(arg0, arg1) +#define HOTSPOT_JNI_GETMODULE_ENTRY_ENABLED() 0 +#define HOTSPOT_JNI_GETMODULE_RETURN(arg0) +#define HOTSPOT_JNI_GETMODULE_RETURN_ENABLED() + #else /* !defined(DTRACE_ENABLED) */ #error This file should only be included when dtrace is not enabled #endif /* !defined(DTRACE_ENABLED) */
--- a/src/share/vm/utilities/hashtable.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/utilities/hashtable.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -151,7 +151,7 @@ void copy_table(char** top, char* end); // Bucket handling - int hash_to_index(unsigned int full_hash) { + int hash_to_index(unsigned int full_hash) const { int h = full_hash % _table_size; assert(h >= 0 && h < _table_size, "Illegal hash value"); return h;
--- a/src/share/vm/utilities/ostream.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/utilities/ostream.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -987,8 +987,10 @@ for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) { // Print in two stages to avoid problems with long // keys/values. + assert(p->key() != NULL, "p->key() is NULL"); text->print_raw(p->key()); text->put('='); + assert(p->value() != NULL, "p->value() is NULL"); text->print_raw_cr(p->value()); } xs->tail("properties");
--- a/src/share/vm/utilities/utf8.cpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/utilities/utf8.cpp Mon Nov 30 14:57:39 2015 -0800 @@ -333,6 +333,68 @@ + ((str[4] & 0x0f) << 6) + (str[5] & 0x3f); } +bool UTF8::is_legal_utf8(const unsigned char* buffer, int length, + bool version_leq_47) { + int i = 0; + int count = length >> 2; + for (int k=0; k<count; k++) { + unsigned char b0 = buffer[i]; + unsigned char b1 = buffer[i+1]; + unsigned char b2 = buffer[i+2]; + unsigned char b3 = buffer[i+3]; + // For an unsigned char v, + // (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128; + // (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128. + unsigned char res = b0 | b0 - 1 | + b1 | b1 - 1 | + b2 | b2 - 1 | + b3 | b3 - 1; + if (res >= 128) break; + i += 4; + } + for(; i < length; i++) { + unsigned short c; + // no embedded zeros + if (buffer[i] == 0) return false; + if(buffer[i] < 128) { + continue; + } + if ((i + 5) < length) { // see if it's legal supplementary character + if (UTF8::is_supplementary_character(&buffer[i])) { + c = UTF8::get_supplementary_character(&buffer[i]); + i += 5; + continue; + } + } + switch (buffer[i] >> 4) { + default: break; + case 0x8: case 0x9: case 0xA: case 0xB: case 0xF: + return false; + case 0xC: case 0xD: // 110xxxxx 10xxxxxx + c = (buffer[i] & 0x1F) << 6; + i++; + if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) { + c += buffer[i] & 0x3F; + if (version_leq_47 || c == 0 || c >= 0x80) { + break; + } + } + return false; + case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx + c = (buffer[i] & 0xF) << 12; + i += 2; + if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) { + c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F); + if (version_leq_47 || c >= 0x800) { + break; + } + } + return false; + } // end of switch + } // end of for + return true; +} + //------------------------------------------------------------------------------------- bool UNICODE::is_latin1(jchar c) {
--- a/src/share/vm/utilities/utf8.hpp Sun Nov 29 11:00:00 2015 -0800 +++ b/src/share/vm/utilities/utf8.hpp Mon Nov 30 14:57:39 2015 -0800 @@ -73,6 +73,9 @@ static bool equal(const jbyte* base1, int length1, const jbyte* base2,int length2); static bool is_supplementary_character(const unsigned char* str); static jint get_supplementary_character(const unsigned char* str); + + static bool is_legal_utf8(const unsigned char* buffer, int length, + bool version_leq_47); };
--- a/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Mon Nov 30 14:57:39 2015 -0800 @@ -22,6 +22,8 @@ */ import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; @@ -35,11 +37,11 @@ * @modules java.base/sun.misc * java.management * java.base/jdk.internal + * @ignore 8132924 * @compile -XDignore.symbol.file java/lang/Object.java TestMonomorphicObjectCall.java * @run main TestMonomorphicObjectCall */ public class TestMonomorphicObjectCall { - final static String testClasses = System.getProperty("test.classes") + File.separator; private static void callFinalize(Object object) throws Throwable { // Call modified version of java.lang.Object::finalize() that is @@ -50,6 +52,9 @@ public static void main(String[] args) throws Throwable { if (args.length == 0) { + byte[] bytecode = Files.readAllBytes(Paths.get(System.getProperty("test.classes") + File.separator + + "java" + File.separator + "lang" + File.separator + "Object.class")); + ClassFileInstaller.writeClassToDisk("java.lang.Object", bytecode, "mods/java.base"); // Execute new instance with modified java.lang.Object executeTestJvm(); } else { @@ -62,7 +67,7 @@ // Execute test with modified version of java.lang.Object // in -Xbootclasspath. String[] vmOpts = new String[] { - "-Xbootclasspath/p:" + testClasses, + "-Xpatch:mods", "-Xcomp", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-VerifyDependencies",
--- a/test/compiler/intrinsics/classcast/NullCheckDroppingsTest.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/intrinsics/classcast/NullCheckDroppingsTest.java Mon Nov 30 14:57:39 2015 -0800 @@ -28,6 +28,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.* * @build NullCheckDroppingsTest * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/compiler/jsr292/CallSiteDepContextTest.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/jsr292/CallSiteDepContextTest.java Mon Nov 30 14:57:39 2015 -0800 @@ -24,6 +24,8 @@ /** * @test * @bug 8057967 + * @modules java.base/jdk.internal.org.objectweb.asm + * @ignore 8134101 * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceClassUnloading * -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC * -verbose:gc java.lang.invoke.CallSiteDepContextTest
--- a/test/compiler/jsr292/CreatesInterfaceDotEqualsCallInfo.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/jsr292/CreatesInterfaceDotEqualsCallInfo.java Mon Nov 30 14:57:39 2015 -0800 @@ -24,6 +24,7 @@ /** * @test + * @ignore 8072479 * @bug 8026124 * @summary Javascript file provoked assertion failure in linkResolver.cpp * @modules jdk.scripting.nashorn/jdk.nashorn.tools
--- a/test/compiler/stable/TestStableBoolean.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableBoolean.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableBoolean * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableBoolean StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableByte.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableByte.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableByte * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableByte StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableChar.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableChar.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableChar * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableChar StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableDouble.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableDouble.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableDouble * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableDouble StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableFloat.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableFloat.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableFloat * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableFloat StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableInt.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableInt.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableInt * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableInt StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableLong.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableLong.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableLong * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableLong StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableObject.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableObject.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableObject * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableObject StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/stable/TestStableShort.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/stable/TestStableShort.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @test TestStableShort * @summary tests on stable fields and arrays * @library /testlibrary /test/lib + * @ignore 8077176 * @build TestStableShort StableConfiguration sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller
--- a/test/compiler/uncommontrap/TestUnstableIfTrap.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/uncommontrap/TestUnstableIfTrap.java Mon Nov 30 14:57:39 2015 -0800 @@ -53,7 +53,7 @@ * -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,UnstableIfExecutable.test * -XX:LogFile=always_taken_not_fired.xml - * TestUnstableIfTrap ALWAYS_TAKEN false + * TestUnstableIfTrap ALWAYS_TAKEN false * @run main/othervm -Xbatch -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions * -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,UnstableIfExecutable.test
--- a/test/compiler/unsafe/UnsafeGetConstantField.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/compiler/unsafe/UnsafeGetConstantField.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,8 @@ * @test * @summary tests on constant folding of unsafe get operations * @library /testlibrary /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm + * @ignore 8134102 * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions * -Xbatch -XX:-TieredCompilation * -XX:+FoldStableValues
--- a/test/gc/TestSmallHeap.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/TestSmallHeap.java Mon Nov 30 14:57:39 2015 -0800 @@ -31,6 +31,7 @@ * @summary Verify that starting the VM with a small heap works * @library /testlibrary /test/lib * @modules java.management/sun.management + * @ignore 8076621 * @build TestSmallHeap * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseParallelGC TestSmallHeap
--- a/test/gc/g1/TestLargePageUseForAuxMemory.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestLargePageUseForAuxMemory.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,6 +27,7 @@ * @bug 8058354 8079208 * @key gc * @library /testlibrary /test/lib + * @modules jdk.jvmstat/sun.jvmstat.monitor * @requires (vm.gc=="G1" | vm.gc=="null") * @build jdk.test.lib.* sun.hotspot.WhiteBox * @build TestLargePageUseForAuxMemory
--- a/test/gc/g1/TestShrinkAuxiliaryData00.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData00.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * TestShrinkAuxiliaryData TestShrinkAuxiliaryData00 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkAuxiliaryData05.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData05.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * TestShrinkAuxiliaryData TestShrinkAuxiliaryData05 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkAuxiliaryData10.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData10.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData10 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkAuxiliaryData15.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData15.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData15 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkAuxiliaryData20.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData20.java Mon Nov 30 14:57:39 2015 -0800 @@ -29,7 +29,8 @@ * @requires vm.gc=="G1" | vm.gc=="null" * @library /testlibrary /test/lib * @modules java.base/sun.misc - * java.management + * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData20 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkAuxiliaryData25.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData25.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData25 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkAuxiliaryData30.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkAuxiliaryData30.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,6 +30,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* sun.hotspot.WhiteBox * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData30 * @run main ClassFileInstaller sun.hotspot.WhiteBox
--- a/test/gc/g1/TestShrinkDefragmentedHeap.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestShrinkDefragmentedHeap.java Mon Nov 30 14:57:39 2015 -0800 @@ -65,6 +65,7 @@ "-XX:G1HeapRegionSize=" + REGION_SIZE, "-XX:-ExplicitGCInvokesConcurrent", "-verbose:gc", + "-XaddExports:java.management/sun.management=ALL-UNNAMED", GCTest.class.getName() );
--- a/test/gc/g1/TestStringDeduplicationTools.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestStringDeduplicationTools.java Mon Nov 30 14:57:39 2015 -0800 @@ -189,7 +189,8 @@ "-Xmx" + Xmx + "m", "-XX:+UseG1GC", "-XX:+UnlockDiagnosticVMOptions", - "-XX:+VerifyAfterGC" // Always verify after GC + "-XX:+VerifyAfterGC", // Always verify after GC + "-XaddExports:java.base/sun.misc=ALL-UNNAMED" }; ArrayList<String> args = new ArrayList<String>();
--- a/test/gc/g1/TestSummarizeRSetStats.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestSummarizeRSetStats.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,9 +27,10 @@ * @library /testlibrary * @modules java.base/sun.misc * java.management/sun.management + * @ignore 8133499 * @build TestSummarizeRSetStatsTools TestSummarizeRSetStats * @summary Verify output of -XX:+G1SummarizeRSetStats - * @run main TestSummarizeRSetStats + * @run main/othervm TestSummarizeRSetStats * * Test the output of G1SummarizeRSetStats in conjunction with G1SummarizeRSetStatsPeriod. */
--- a/test/gc/g1/TestSummarizeRSetStatsPerRegion.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/g1/TestSummarizeRSetStatsPerRegion.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,9 +27,10 @@ * @library /testlibrary * @modules java.base/sun.misc * java.management/sun.management + * @ignore 8133499 * @build TestSummarizeRSetStatsTools TestSummarizeRSetStatsPerRegion * @summary Verify output of -XX:+G1SummarizeRSetStats in regards to per-region type output - * @run main TestSummarizeRSetStatsPerRegion + * @run main/othervm TestSummarizeRSetStatsPerRegion */ import jdk.test.lib.*;
--- a/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java Mon Nov 30 14:57:39 2015 -0800 @@ -28,6 +28,7 @@ * @library /testlibrary * @modules java.base/sun.misc * java.management + * @ignore 8134071 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:CompressedClassSpaceSize=50m CompressedClassSpaceSizeInJmapHeap */
--- a/test/gc/parallel/TestDynShrinkHeap.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/gc/parallel/TestDynShrinkHeap.java Mon Nov 30 14:57:39 2015 -0800 @@ -26,6 +26,7 @@ * @bug 8016479 * @requires vm.gc=="Parallel" | vm.gc=="null" * @summary Verify that the heap shrinks after full GC according to the current values of the Min/MaxHeapFreeRatio flags + * @modules java.management/sun.management * @library /testlibrary * @run main/othervm -XX:+UseAdaptiveSizePolicyWithSystemGC -XX:+UseParallelGC -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 -Xmx1g -verbose:gc TestDynShrinkHeap */
--- a/test/runtime/BadObjectClass/BootstrapRedefine.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/BadObjectClass/BootstrapRedefine.java Mon Nov 30 14:57:39 2015 -0800 @@ -26,9 +26,9 @@ * @bug 6583051 * @summary Give error if java.lang.Object has been incompatibly overridden on the bootpath * @library /testlibrary + * @ignore 8132924 * @modules java.base/sun.misc * java.management - * @compile Object.java * @run main BootstrapRedefine */ @@ -37,8 +37,18 @@ public class BootstrapRedefine { public static void main(String[] args) throws Exception { - String testClasses = System.getProperty("test.classes", "."); - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/p:" + testClasses, "-version"); + String source = "package java.lang;" + + "public class Object {" + + " void dummy1() { return; }" + + " void dummy2() { return; }" + + " void dummy3() { return; }" + + "}"; + + ClassFileInstaller.writeClassToDisk("java/lang/Object", + InMemoryJavaCompiler.compile("java.lang.Object", source), + "mods/java.base"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xpatch:mods", "-version"); new OutputAnalyzer(pb.start()) .shouldContain("Incompatible definition of java.lang.Object") .shouldHaveExitValue(1);
--- a/test/runtime/BadObjectClass/Object.java Sun Nov 29 11:00:00 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang; - -/** - * This is a fake java.lang.Object class. - */ -public class Object { - - // Add some methods - void dummy1() { return; } - void dummy2() { return; } - void dummy3() { return; } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/BootClassAppendProp/BootClassPathAppend.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8087154 + * @summary Uninitialized system property jdk.boot.class.path.append causes SIGSEGV + * @library /testlibrary + * @modules java.base/sun.misc + */ + +import jdk.test.lib.*; + +// Test that system property jdk.boot.class.path.append is initialized. Otherwise, +// -XX:+PrintCompilation does causes a SIGSEGV. +public class BootClassPathAppend { + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+PrintCompilation", "-Xcomp", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("java.lang.Object"); + output.shouldHaveExitValue(0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/BootClassAppendProp/BootClassPathAppendProp.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; + +/* + * @test + * @build BootClassPathAppendProp + * @run main/othervm -Xbootclasspath/a:/usr/lib -showversion -Xbootclasspath/a:/i/dont/exist BootClassPathAppendProp set + * @run main/othervm -Xpatch:/not/here -Xbootclasspath/a:/i/may/exist BootClassPathAppendProp override + * @run main/othervm BootClassPathAppendProp empty + */ + +// Test that property jdk.boot.class.path.append contains only the bootclasspath +// info following the .jimage file. +public class BootClassPathAppendProp { + + public static void test_prop(String expected_val) { + String propVal = System.getProperty("jdk.boot.class.path.append"); + if (!propVal.equals(expected_val)) { + throw new RuntimeException( + "Bad jdk.boot.class.path.append property value: " + propVal); + } + } + + public static void main(String[] args) { + if (args[0].equals("set")) { + test_prop("/usr/lib" + File.pathSeparator + "/i/dont/exist"); + } else if (args[0].equals("override")) { + test_prop("/i/may/exist"); + } else if (args[0].equals("empty")) { + test_prop(""); + } else { + throw new RuntimeException("Unexpected arg to main: " + args[0]); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/BootClassAppendProp/SunBootClassPath.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Make sure property sun.boot.class.path is null starting with JDK-9. + */ + +// Test that the value of property sun.boot.class.path is null. +public class SunBootClassPath { + public static void main(String[] args) throws Exception { + if (System.getProperty("sun.boot.class.path") != null) { + throw new RuntimeException("Test failed, sun.boot.class.path has value: " + + System.getProperty("sun.boot.class.path")); + } else { + System.out.println("Test SunBootClassPath passed"); + } + } +}
--- a/test/runtime/ClassFile/UnsupportedClassFileVersion.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/ClassFile/UnsupportedClassFileVersion.java Mon Nov 30 14:57:39 2015 -0800 @@ -28,7 +28,7 @@ * java.base/sun.misc * java.management * @compile -XDignore.symbol.file UnsupportedClassFileVersion.java - * @run main UnsupportedClassFileVersion + * @run main/othervm UnsupportedClassFileVersion */ import java.io.File; @@ -41,7 +41,7 @@ public class UnsupportedClassFileVersion implements Opcodes { public static void main(String... args) throws Exception { writeClassFile(); - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-cp", ".", "ClassFile"); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-cp", ".", "ClassFile"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("ClassFile has been compiled by a more recent version of the " + "Java Runtime (class file version 99.0), this version of " +
--- a/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Mon Nov 30 14:57:39 2015 -0800 @@ -27,8 +27,9 @@ * @library /testlibrary /runtime/CommandLine/OptionsValidation/common * @modules java.base/sun.misc * java.management - * jdk.attach - * jdk.management/sun.tools.attach + * jdk.attach/sun.tools.attach + * jdk.jvmstat/sun.jvmstat.monitor + * @build jdk.test.lib.* TestOptionsWithRanges * @run main/othervm/timeout=780 TestOptionsWithRanges */
--- a/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java Mon Nov 30 14:57:39 2015 -0800 @@ -26,9 +26,8 @@ * @summary Test writeable VM Options with ranges. * @library /testlibrary /runtime/CommandLine/OptionsValidation/common * @modules java.base/sun.misc + * jdk.attach/sun.tools.attach * java.management - * jdk.attach - * jdk.management/sun.tools.attach * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestOptionsWithRangesDynamic */
--- a/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/ErrorHandling/CreateCoredumpOnCrash.java Mon Nov 30 14:57:39 2015 -0800 @@ -24,10 +24,10 @@ /* * @test * @library /testlibrary - * @modules java.base/sun.misc - * java.compiler + * @modules java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor + * java.base/sun.misc * @build jdk.test.lib.* * @run driver CreateCoredumpOnCrash */ @@ -56,7 +56,7 @@ public static OutputAnalyzer runTest(String option) throws Exception { return new OutputAnalyzer( ProcessTools.createJavaProcessBuilder( - "-Xmx64m", "-XX:-TransmitErrorReport", option, Crasher.class.getName()) + "-Xmx64m", "-XX:-TransmitErrorReport", "-XaddExports:java.base/sun.misc=ALL-UNNAMED", option, Crasher.class.getName()) .start()); } }
--- a/test/runtime/NMT/JcmdWithNMTDisabled.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/NMT/JcmdWithNMTDisabled.java Mon Nov 30 14:57:39 2015 -0800 @@ -47,12 +47,12 @@ String testjdkPath = System.getProperty("test.jdk"); // First run without enabling NMT - pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "JcmdWithNMTDisabled"); + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XaddExports:java.management/sun.management=ALL-UNNAMED", "JcmdWithNMTDisabled"); output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); // Then run with explicitly disabling NMT, should not be any difference - pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "JcmdWithNMTDisabled"); + pb = ProcessTools.createJavaProcessBuilder("-Dtest.jdk=" + testjdkPath, "-XX:NativeMemoryTracking=off", "-XaddExports:java.management/sun.management=ALL-UNNAMED", "JcmdWithNMTDisabled"); output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0);
--- a/test/runtime/RedefineTests/RedefineFinalizer.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/RedefineTests/RedefineFinalizer.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,7 +30,7 @@ * java.instrument * jdk.jartool/sun.tools.jar * @build RedefineClassHelper - * @run main RedefineClassHelper + * @run main/othervm RedefineClassHelper * @run main/othervm -javaagent:redefineagent.jar RedefineFinalizer */
--- a/test/runtime/RedefineTests/RedefineRunningMethods.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/RedefineTests/RedefineRunningMethods.java Mon Nov 30 14:57:39 2015 -0800 @@ -30,7 +30,7 @@ * java.instrument * jdk.jartool/sun.tools.jar * @build RedefineClassHelper - * @run main RedefineClassHelper + * @run main/othervm RedefineClassHelper * @run main/othervm -javaagent:redefineagent.jar -XX:TraceRedefineClasses=0x600 RedefineRunningMethods */ public class RedefineRunningMethods {
--- a/test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java Mon Nov 30 14:57:39 2015 -0800 @@ -26,8 +26,9 @@ * @bug 8076110 * @summary Redefine running methods that have cached resolution errors * @library /testlibrary - * @modules java.instrument - * java.base/jdk.internal.org.objectweb.asm + * @modules java.base/jdk.internal.org.objectweb.asm + * java.instrument + * jdk.jartool/sun.tools.jar * @build RedefineClassHelper * @run main RedefineClassHelper * @run main/othervm -javaagent:redefineagent.jar -XX:TraceRedefineClasses=0x600 RedefineRunningMethodsWithResolutionErrors
--- a/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java Mon Nov 30 14:57:39 2015 -0800 @@ -60,24 +60,6 @@ output.shouldNotContain("Usage:"); // Should not print JVM help message output.shouldHaveExitValue(0); // Should report success in error code. - // (2) With an invalid archive (boot class path has been prepended) - pb = ProcessTools.createJavaProcessBuilder( - "-Xbootclasspath/p:foo.jar", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, - "-XX:+PrintSharedArchiveAndExit", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("archive is invalid"); - output.shouldNotContain("java version"); // Should not print JVM version - output.shouldHaveExitValue(1); // Should report failure in error code. - - pb = ProcessTools.createJavaProcessBuilder( - "-Xbootclasspath/p:foo.jar", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, - "-XX:+PrintSharedArchiveAndExit"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("archive is invalid"); - output.shouldNotContain("Usage:"); // Should not print JVM help message - output.shouldHaveExitValue(1); // Should report failure in error code. } catch (RuntimeException e) { e.printStackTrace(); output.shouldContain("Unable to use shared archive");
--- a/test/runtime/SharedArchiveFile/SharedStrings.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/SharedArchiveFile/SharedStrings.java Mon Nov 30 14:57:39 2015 -0800 @@ -32,6 +32,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jartool/sun.tools.jar * @build SharedStringsWb SharedStrings BasicJarBuilder sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main SharedStrings
--- a/test/runtime/StackGuardPages/testme.sh Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/StackGuardPages/testme.sh Mon Nov 30 14:57:39 2015 -0800 @@ -3,6 +3,7 @@ # # @test testme.sh # @summary Stack guard pages should be installed correctly and removed when thread is detached +# @ignore 8072481 # @run shell testme.sh #
--- a/test/runtime/Unsafe/GetKlassPointerGetJavaMirror.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/Unsafe/GetKlassPointerGetJavaMirror.java Mon Nov 30 14:57:39 2015 -0800 @@ -24,7 +24,7 @@ /* @test * @bug 8022853 * @library /testlibrary - * @modules java.base/sun.misc + * @modules jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* * @run main GetKlassPointerGetJavaMirror */
--- a/test/runtime/Unsafe/GetUncompressedObject.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/Unsafe/GetUncompressedObject.java Mon Nov 30 14:57:39 2015 -0800 @@ -25,6 +25,7 @@ * @bug 8022853 * @library /testlibrary * @modules java.base/sun.misc + * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* * @run main GetUncompressedObject */
--- a/test/runtime/Unsafe/RangeCheck.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/Unsafe/RangeCheck.java Mon Nov 30 14:57:39 2015 -0800 @@ -47,6 +47,7 @@ "-XX:-TransmitErrorReport", "-XX:-CreateCoredumpOnCrash", "-XX:-InlineUnsafeOps", // The compiler intrinsics doesn't have the assert + "-XaddExports:java.base/sun.misc=ALL-UNNAMED", DummyClassWithMainRangeCheck.class.getName()); OutputAnalyzer output = new OutputAnalyzer(pb.start());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/getSysPackage/GetSysPkgTest.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @modules java.base/jdk.internal.misc + * java.desktop + * @library /testlibrary + * @run main/othervm GetSysPkgTest + */ + +// package GetSysPkg_package; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import jdk.test.lib.*; + +// Test that JVM get_system_package() returns the module location for defined packages. +public class GetSysPkgTest { + + private static Object invoke(Method m, Object obj, Object... args) throws Throwable { + try { + return m.invoke(obj, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + + private static Method findMethod(String name) { + for (Method m : jdk.internal.misc.BootLoader.class.getDeclaredMethods()) { + if (m.getName().equals(name)) { + m.setAccessible(true); + return m; + } + } + throw new RuntimeException("Failed to find method " + name + " in java.lang.reflect.Module"); + } + + // Throw RuntimeException if getSystemPackageLocation() does not return + // the expected location. + static void getPkg(String name, String expected_loc) throws Throwable { + String loc = (String)invoke(findMethod("getSystemPackageLocation"), null, name); + if (loc == null) { + if (expected_loc == null) return; + System.out.println("Expected location: " + expected_loc + + ", for package: " + name + ", got: null"); + } else if (expected_loc == null) { + System.out.println("Expected location: null, for package: " + + name + ", got: " + loc); + } else if (!loc.equals(expected_loc)) { + System.out.println("Expected location: " + + expected_loc + ", for package: " + name + ", got: " + loc); + } else { + return; + } + throw new RuntimeException(); + } + + public static void main(String args[]) throws Throwable { + if (args.length == 0 || !args[0].equals("do_tests")) { + + // Create a package found via -Xbootclasspath/a + String source = "package BootLdr_package; " + + "public class BootLdrPkg { " + + " public int mth() { return 4; } " + + "}"; + byte[] klassbuf = + InMemoryJavaCompiler.compile("BootLdr_package.BootLdrPkg", source); + ClassFileInstaller.writeClassToDisk("BootLdr_package/BootLdrPkg", klassbuf, "bl_dir"); + + // Create a package found via -cp. + source = "package GetSysPkg_package; " + + "public class GetSysClass { " + + " public int mth() { return 4; } " + + "}"; + klassbuf = + InMemoryJavaCompiler.compile("GetSysPkg_package.GetSysClass", source); + ClassFileInstaller.writeClassToDisk("GetSysPkg_package/GetSysClass", klassbuf); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/a:bl_dir", + "-XaddExports:java.base/jdk.internal.misc=ALL-UNNAMED", "-cp", "." + File.pathSeparator + + System.getProperty("test.classes"), "GetSysPkgTest", "do_tests"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + return; + } + + getPkg("java/lang/", "jrt:/java.base"); + getPkg("java/lang", null); // Need trailing '/' + getPkg("javax/script/", null); // Package not defined + + // Make sure a class in the package is referenced. + Class newClass = Class.forName("sun.invoke.util.Wrapper"); + getPkg("sun/invoke/util/", "jrt:/java.base"); + getPkg("java/nio/charset/", "jrt:/java.base"); + + // Test a package in a module not owned by boot loader. + Class clss = Class.forName("javax.activation.DataHandler"); + if (clss == null) + throw new RuntimeException("Could not find class javax.activation.DataHandler"); + getPkg("javax/activation/", null); // Not owned by boot loader + + // Test a package not in jimage file. + clss = Class.forName("GetSysPkg_package.GetSysClass"); + if (clss == null) + throw new RuntimeException("Could not find class GetSysPkg_package.GetSysClass"); + getPkg("GetSysPkg_package/", null); + + // Access a class with a package in a boot loader module other than java.base + clss = Class.forName("java.awt.Button"); + if (clss == null) + throw new RuntimeException("Could not find class java.awt.Button"); + getPkg("java/awt/", "jrt:/java.desktop"); + + // Test getting the package location from a class found via -Xbootclasspath/a + clss = Class.forName("BootLdr_package.BootLdrPkg"); + if (clss == null) + throw new RuntimeException("Could not find class BootLdr_package.BootLdrPkg"); + String bootldrPkg = (String)invoke(findMethod("getSystemPackageLocation"), null, "BootLdr_package/"); + if (bootldrPkg == null || !bootldrPkg.toLowerCase().endsWith("bl_dir")) { + System.out.println("Expected BootLdr_package/ to end in bl_dir, but got " + + bootldrPkg == null ? "null" : bootldrPkg); + throw new RuntimeException(); + } + } +}
--- a/test/runtime/lambda-features/TestStaticandInstance.java Sun Nov 29 11:00:00 2015 -0800 +++ b/test/runtime/lambda-features/TestStaticandInstance.java Mon Nov 30 14:57:39 2015 -0800 @@ -26,6 +26,7 @@ * @test * @bug 8087342 * @summary Test linkresolver search static, instance and overpass duplicates + * @modules java.base/jdk.internal.org.objectweb.asm * @run main/othervm -Xverify:none TestStaticandInstance */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/modules/AccModuleTest.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary + * @modules java.base/sun.misc + * @compile acc_module.jcod + * @build AccModuleTest + * @run main AccModuleTest + */ + +import java.io.File; +import jdk.test.lib.*; + +public class AccModuleTest { + + public static void main(String args[]) throws Throwable { + System.out.println("Test that ACC_MODULE in class access flags does not cause ClassFormatError"); + Class clss = Class.forName("acc_module"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/modules/AccessCheck/ExportAllUnnamed.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test if package p2 in module m2 is exported to all unnamed, + * then class p1.c1 in an unnamed module can read p2.c2 in module m2. + * @library /testlibrary /../../test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @compile -XaddExports:java.base/jdk.internal.module=ALL-UNNAMED ExportAllUnnamed.java + * @run main/othervm -XaddExports:java.base/jdk.internal.module=ALL-UNNAMED -Xbootclasspath/a:. ExportAllUnnamed + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported unqualifiedly +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2 +// Access allowed, an unnamed module can read all modules and p2 in module +// m2 is exported to all unnamed modules. + +public class ExportAllUnnamed { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported unqualifiedly + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves a module named "m1" that results in a configuration. It + // then augments that configuration with additional modules (and edges) induced + // by service-use relationships. + Configuration cf = Configuration.resolve(finder, + Layer.boot().configuration(), + ModuleFinder.empty(), + "m1"); + + // map each module to differing class loaders for this test + Map<String, ClassLoader> map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.create(cf, Layer.boot(), map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = MySameClassLoader.loader1.loadClass("p2.c2"); + Module m2 = p2_c2_class.getModule(); + + // Export m2/p2 to all unnamed modules. + jdk.internal.module.Modules.addExportsToAllUnnamed(m2, "p2"); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, unnamed module failed to access public type p2.c2 " + + "that was exported to all unnamed"); + } + } + + public static void main(String args[]) throws Throwable { + ExportAllUnnamed test = new ExportAllUnnamed(); + test.createLayerOnBoot(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/modules/AccessCheck/ModuleLibrary.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +/** + * A container of modules that acts as a ModuleFinder for testing + * purposes. + */ + +class ModuleLibrary implements ModuleFinder { + private final Map<String, ModuleReference> namesToReference = new HashMap<>(); + + private ModuleLibrary() { } + + void add(ModuleDescriptor... descriptors) { + for (ModuleDescriptor descriptor: descriptors) { + String name = descriptor.name(); + if (!namesToReference.containsKey(name)) { + //modules.add(descriptor); + + URI uri = URI.create("module:/" + descriptor.name()); + + Supplier<ModuleReader> supplier = () -> { + throw new UnsupportedOperationException(); + }; + + ModuleReference mref = new ModuleReference(descriptor, uri, supplier); + + namesToReference.put(name, mref); + } + } + } + + static ModuleLibrary of(ModuleDescriptor... descriptors) { + ModuleLibrary ml = new ModuleLibrary(); + ml.add(descriptors); + return ml; + } + + @Override + public Optional<ModuleReference> find(String name) { + return Optional.ofNullable(namesToReference.get(name)); + } + + @Override + public Set<ModuleReference> findAll() { + return new HashSet<>(namesToReference.values()); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/modules/AccessCheck/NmodNpkgDiffCL_CheckRead.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can not read module m2, then class p1.c1 + * in module m1 can not access p2.c2 in module m2. + * @library /testlibrary /../../test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build NmodNpkgDiffCL_CheckRead + * @run main/othervm -Xbootclasspath/a:. NmodNpkgDiffCL_CheckRead + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can not read m2 +// package p2 in m2 is exported to m1 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2. +// Access denied since m1 can not read m2. +// +public class NmodNpkgDiffCL_CheckRead { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m3 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m3") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Define module: m3 + // Can read: java.base, m2 + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .requires("m2") + .conceals("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves a module named "m1" that results in a configuration. It + // then augments that configuration with additional modules (and edges) induced + // by service-use relationships. + Configuration cf = Configuration.resolve(finder, + Layer.boot().configuration(), + ModuleFinder.empty(), + "m1"); + + // map each module to differing class loaders for this test + Map<String, ClassLoader> map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + map.put("m3", MyDiffClassLoader.loader2); + + // Create Layer that contains m1, m2 and m3 + Layer layer = Layer.create(cf, Layer.boot(), map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("m3") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m1 but m2 is not readable from m1)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("cannot access")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + NmodNpkgDiffCL_CheckRead test = new NmodNpkgDiffCL_CheckRead(); + test.createLayerOnBoot(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/modules/AccessCheck/NmodNpkgDiffCL_PkgExpQualOther.java Mon Nov 30 14:57:39 2015 -0800 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, but package p2 in m2 + * is exported specifically to module m3, then class p1.c1 in m1 can not + * access p2.c2 in m2. + * @library /testlibrary /../../test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build NmodNpkgDiffCL_PkgExpQualOther + * @run main/othervm -Xbootclasspath/a:. NmodNpkgDiffCL_PkgExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can read m2 +// package p2 in m2 is exported to m3 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access denied since although m1 can read m2, p2 is exported only to m3. +// +public class NmodNpkgDiffCL_PkgExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2, m3 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .requires("m3") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base, m3 + // Packages: p2 + // Packages exported: p2 is exported to m3 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m3") + .build(); + + // Define module: m3 + // Can read: java.base, m2 + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base")