Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 42 additions & 28 deletions src/hotspot/share/classfile/classLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ static JImageGetResource_t JImageGetResource = nullptr;
// JImageFile pointer, or null if exploded JDK build.
static JImageFile* JImage_file = nullptr;

// JImageMode status to control preview behaviour. JImage_file is unusable
// for normal lookup until (JImage_mode != JIMAGE_MODE_UNINITIALIZED).
enum JImageMode {
JIMAGE_MODE_UNINITIALIZED = 0,
JIMAGE_MODE_DEFAULT = 1,
JIMAGE_MODE_ENABLE_PREVIEW = 2
// PreviewMode status to control preview behaviour. JImage_file is unusable
// for normal lookup until (Preview_mode != PREVIEW_MODE_UNINITIALIZED).
enum PreviewMode {
PREVIEW_MODE_UNINITIALIZED = 0,
PREVIEW_MODE_DEFAULT = 1,
PREVIEW_MODE_ENABLE_PREVIEW = 2
};
static JImageMode JImage_mode = JIMAGE_MODE_UNINITIALIZED;
static PreviewMode Preview_mode = PREVIEW_MODE_UNINITIALIZED;

// Globals

Expand Down Expand Up @@ -234,7 +234,7 @@ Symbol* ClassLoader::package_from_class_name(const Symbol* name, bool* bad_class
}

// --------------------------------
// The following jimage_xxx static functions encapsulate all JImage_file and JImage_mode access.
// The following jimage_xxx static functions encapsulate all JImage_file and Preview_mode access.
// This is done to make it easy to reason about the JImage file state (exists vs initialized etc.).

// Opens the named JImage file and sets the JImage file reference.
Expand Down Expand Up @@ -266,23 +266,15 @@ static JImageFile* jimage_non_null() {
return JImage_file;
}

// Called once to set the access mode for resource (i.e. preview or non-preview) before
// general resource lookup can occur.
static void jimage_init(bool enable_preview) {
assert(JImage_mode == JIMAGE_MODE_UNINITIALIZED, "jimage_init must not be called twice");
JImage_mode = enable_preview ? JIMAGE_MODE_ENABLE_PREVIEW : JIMAGE_MODE_DEFAULT;
}

// Returns true if jimage_init() has been called. Once the JImage file is initialized,
// jimage_is_preview_enabled() can be called to correctly determine the access mode.
static bool jimage_is_initialized() {
return jimage_exists() && JImage_mode != JIMAGE_MODE_UNINITIALIZED;
return jimage_exists() && Preview_mode != PREVIEW_MODE_UNINITIALIZED;
}

// Returns the access mode for an initialized JImage file (reflects --enable-preview).
static bool jimage_is_preview_enabled() {
assert(jimage_is_initialized(), "jimage is not initialized");
return JImage_mode == JIMAGE_MODE_ENABLE_PREVIEW;
static bool is_preview_enabled() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, the preview related names were associated with jimage mode, expanding that to the exploded image raises a question about the name and the name set_preview_mode ; there may be some ambiguity in this is_preview_enabled() and the vm wide method(s) indicating --enable-preview across all HotSpot functions.
It would be good if this name could reflect the mode of loading classes.
Maybe...
is_class_loading_mode_preview() based on class_loading_mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it is the "class loader", so to me the question "is preview enabled?" in this class would mean (implicitly) "for class loading". I guess "should_load_preview_classes()" and "set_preview_class_loading()" are more descriptive, but then again the flag controlling this is "--enable-preview", so "is preview enabled" ties back very nicely.

I'd vote to not change it in this PR and we can discuss the finer points of this after Xmas.

return Preview_mode == PREVIEW_MODE_ENABLE_PREVIEW;
}

// Looks up the location of a named JImage resource. This "raw" lookup function allows
Expand Down Expand Up @@ -465,7 +457,7 @@ ClassFileStream* ClassPathImageEntry::open_stream(JavaThread* current, const cha
// 2. A package is in at most one module in the jimage file.
//
ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current, const char* name, ClassLoaderData* loader_data) {
bool is_preview = jimage_is_preview_enabled();
const bool is_preview = is_preview_enabled();

jlong size;
JImageLocationRef location = 0;
Expand Down Expand Up @@ -694,13 +686,23 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
static const char* get_exploded_module_path(const char* module_name, bool c_heap) {
const char *home = Arguments::get_java_home();
const char file_sep = os::file_separator()[0];
// 10 represents the length of "modules" + 2 file separators + \0
// 10 represents the length of "modules" (7) + 2 file separators + \0
size_t len = strlen(home) + strlen(module_name) + 10;
char *path = c_heap ? NEW_C_HEAP_ARRAY(char, len, mtModule) : NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name);
return path;
}

// Gets a preview path for a given class path as a resource.
static const char* get_preview_path(const char* path) {
const char file_sep = os::file_separator()[0];
// 18 represents the length of "META-INF" (8) + "preview" (7) + 2 file separators + \0
size_t len = strlen(path) + 18;
char *preview_path = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(preview_path, len, "%s%cMETA-INF%cpreview", path, file_sep, file_sep);
return preview_path;
}

// During an exploded modules build, each module defined to the boot loader
// will be added to the ClassLoader::_exploded_entries array.
void ClassLoader::add_to_exploded_build_list(JavaThread* current, Symbol* module_sym) {
Expand All @@ -716,19 +718,32 @@ void ClassLoader::add_to_exploded_build_list(JavaThread* current, Symbol* module
if (os::stat(path, &st) == 0) {
// Directory found
ClassPathEntry* new_entry = create_class_path_entry(current, path, &st);

// If the path specification is valid, enter it into this module's list.
// There is no need to check for duplicate modules in the exploded entry list,
// since no two modules with the same name can be defined to the boot loader.
// This is checked at module definition time in Modules::define_module.
if (new_entry != nullptr) {
ModuleClassPathList* module_cpl = new ModuleClassPathList(module_sym);
log_info(class, load)("path: %s", path);

// If we are in preview mode, attempt to add a preview entry *before* the
// new class path entry if a preview path exists.
if (is_preview_enabled()) {
const char* preview_path = get_preview_path(path);
if (os::stat(preview_path, &st) == 0) {
ClassPathEntry* preview_entry = create_class_path_entry(current, preview_path, &st);
if (preview_entry != nullptr) {
module_cpl->add_to_list(preview_entry);
log_info(class, load)("preview path: %s", preview_path);
}
}
}

module_cpl->add_to_list(new_entry);
{
MutexLocker ml(current, Module_lock);
_exploded_entries->push(module_cpl);
}
log_info(class, load)("path: %s", path);
}
}
}
Expand Down Expand Up @@ -1477,7 +1492,7 @@ char* ClassLoader::lookup_vm_options() {

jio_snprintf(modules_path, JVM_MAXPATHLEN, "%s%slib%smodules", Arguments::get_java_home(), fileSep, fileSep);
if (jimage_open(modules_path)) {
// Special case where we lookup the options string *before* calling jimage_init().
// Special case where we lookup the options string *before* set_preview_mode() is called.
// Since VM arguments have not been parsed, and the ClassPathImageEntry singleton
// has not been created yet, we access the JImage file directly in non-preview mode.
jlong size;
Expand All @@ -1494,10 +1509,9 @@ char* ClassLoader::lookup_vm_options() {
}

// Finishes initializing the JImageFile (if present) by setting the access mode.
void ClassLoader::init_jimage(bool enable_preview) {
if (jimage_exists()) {
jimage_init(enable_preview);
}
void ClassLoader::set_preview_mode(bool enable_preview) {
assert(Preview_mode == PREVIEW_MODE_UNINITIALIZED, "set_preview_mode must not be called twice");
Preview_mode = enable_preview ? PREVIEW_MODE_ENABLE_PREVIEW : PREVIEW_MODE_DEFAULT;
}

bool ClassLoader::is_module_observable(const char* module_name) {
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/classfile/classLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ class ClassLoader: AllStatic {
// Called once, after all flags are processed, to finish initializing the
// JImage file. Until this is called, jimage_find_resource(), and any other
// JImage resource lookups or access will fail.
static void init_jimage(bool enable_preview);
static void set_preview_mode(bool enable_preview);

// Determines if the named module is present in the
// modules jimage file or in the exploded modules directory.
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3038,7 +3038,7 @@ jint Arguments::finalize_vm_init_args() {
return JNI_ERR;
}

ClassLoader::init_jimage(is_valhalla_enabled());
ClassLoader::set_preview_mode(is_valhalla_enabled());

// finalize --module-patch.
if (finalize_patch_module() != JNI_OK) {
Expand Down