Skip to content

Commit 50c4dac

Browse files
Preview mode changes.
* Serialization fix * squash everything latest * image reader test update * repatching * reader perf fix * BASELINE_SEPT_09-15:08
1 parent c3bad8f commit 50c4dac

File tree

12 files changed

+1372
-652
lines changed

12 files changed

+1372
-652
lines changed

bin/idea.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ if [ -d "$TOPLEVEL_DIR/.hg" ] ; then
125125
VCS_TYPE="hg4idea"
126126
fi
127127

128-
if [ -d "$TOPLEVEL_DIR/.git" ] ; then
128+
# Git worktrees use a '.git' file rather than directory, so test both.
129+
if [ -d "$TOPLEVEL_DIR/.git" -o -f "$TOPLEVEL_DIR/.git" ] ; then
129130
VCS_TYPE="Git"
130131
fi
131132

make/CompileJavaModules.gmk

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,16 @@ endif
9999

100100
################################################################################
101101
# Setup the main compilation
102+
103+
COMPILATION_OUTPUTDIR := $(if $($(MODULE)_BIN), $($(MODULE)_BIN), $(JDK_OUTPUTDIR)/modules)
104+
102105
$(eval $(call SetupJavaCompilation, $(MODULE), \
103106
SMALL_JAVA := false, \
104107
MODULE := $(MODULE), \
105108
SRC := $(wildcard $(MODULE_SRC_DIRS)), \
106109
INCLUDES := $(JDK_USER_DEFINED_FILTER), \
107110
FAIL_NO_SRC := $(FAIL_NO_SRC), \
108-
BIN := $(if $($(MODULE)_BIN), $($(MODULE)_BIN), $(JDK_OUTPUTDIR)/modules), \
111+
BIN := $(COMPILATION_OUTPUTDIR), \
109112
HEADERS := $(SUPPORT_OUTPUTDIR)/headers, \
110113
CREATE_API_DIGEST := true, \
111114
CLEAN := $(CLEAN), \
@@ -137,14 +140,23 @@ ifneq ($(COMPILER), bootjdk)
137140
MODULE_VALUECLASS_SRC_DIRS := $(call FindModuleValueClassSrcDirs, $(MODULE))
138141
MODULE_VALUECLASS_SOURCEPATH := $(call GetModuleValueClassSrcPath)
139142

143+
# Temporarily compile valueclasses into a separate directory with the form:
144+
# <tempdir>/<module>/<classpath>
145+
# and then copy the class files into:
146+
# <outdir>/<module>/META-INF/preview/<classpath>
147+
# We cannot compile directly into the desired directory because it's the
148+
# compiler which creates the original '<module>/<classpath>/...' hierarchy.
149+
VALUECLASS_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/$(VALUECLASSES_STR)
150+
PREVIEW_OUTPUTDIR := $(COMPILATION_OUTPUTDIR)/$(MODULE)/META-INF/preview
151+
140152
ifneq ($(MODULE_VALUECLASS_SRC_DIRS),)
141153
$(eval $(call SetupJavaCompilation, $(MODULE)-$(VALUECLASSES_STR), \
142154
SMALL_JAVA := false, \
143155
MODULE := $(MODULE), \
144156
SRC := $(wildcard $(MODULE_VALUECLASS_SRC_DIRS)), \
145157
INCLUDES := $(JDK_USER_DEFINED_FILTER), \
146158
FAIL_NO_SRC := $(FAIL_NO_SRC), \
147-
BIN := $(SUPPORT_OUTPUTDIR)/$(VALUECLASSES_STR)/, \
159+
BIN := $(VALUECLASS_OUTPUTDIR)/, \
148160
JAR := $(JDK_OUTPUTDIR)/lib/$(VALUECLASSES_STR)/$(MODULE)-$(VALUECLASSES_STR).jar, \
149161
HEADERS := $(SUPPORT_OUTPUTDIR)/headers, \
150162
DISABLED_WARNINGS := $(DISABLED_WARNINGS_java) preview, \
@@ -162,6 +174,14 @@ ifneq ($(COMPILER), bootjdk)
162174

163175
TARGETS += $($(MODULE)-$(VALUECLASSES_STR))
164176

177+
# Restructure the class file hierarchy from <module>/<classpath>/... to <module>/META-INF/preview/<classpath>/...
178+
$(PREVIEW_OUTPUTDIR)/_copy_valueclasses.marker: $($(MODULE)-$(VALUECLASSES_STR))
179+
$(call MakeTargetDir)
180+
$(CP) -R $(VALUECLASS_OUTPUTDIR)/$(MODULE)/. $(@D)/
181+
$(TOUCH) $@
182+
183+
TARGETS += $(PREVIEW_OUTPUTDIR)/_copy_valueclasses.marker
184+
165185
$(eval $(call SetupCopyFiles, $(MODULE)-copy-valueclass-jar, \
166186
FILES := $(JDK_OUTPUTDIR)/lib/$(VALUECLASSES_STR)/$(MODULE)-$(VALUECLASSES_STR).jar, \
167187
DEST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/$(VALUECLASSES_STR), \

make/test/BuildMicrobenchmark.gmk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
9292
--add-exports java.base/jdk.internal.classfile.impl=ALL-UNNAMED \
9393
--add-exports java.base/jdk.internal.event=ALL-UNNAMED \
9494
--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
95+
--add-exports java.base/jdk.internal.jimage=ALL-UNNAMED \
9596
--add-exports java.base/jdk.internal.misc=ALL-UNNAMED \
9697
--add-exports java.base/jdk.internal.util=ALL-UNNAMED \
9798
--add-exports java.base/jdk.internal.value=ALL-UNNAMED \

src/hotspot/share/classfile/classLoader.cpp

Lines changed: 116 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,18 @@ static JImageClose_t JImageClose = nullptr;
9696
static JImageFindResource_t JImageFindResource = nullptr;
9797
static JImageGetResource_t JImageGetResource = nullptr;
9898

99-
// JimageFile pointer, or null if exploded JDK build.
99+
// JImageFile pointer, or null if exploded JDK build.
100100
static JImageFile* JImage_file = nullptr;
101101

102+
// JImageMode status to control preview behaviour. JImage_file is unusable
103+
// for normal lookup until (JImage_mode != JIMAGE_MODE_UNINITIALIZED).
104+
enum JImageMode {
105+
JIMAGE_MODE_UNINITIALIZED = 0,
106+
JIMAGE_MODE_DEFAULT = 1,
107+
JIMAGE_MODE_ENABLE_PREVIEW = 2
108+
};
109+
static JImageMode JImage_mode = JIMAGE_MODE_UNINITIALIZED;
110+
102111
// Globals
103112

104113
PerfCounter* ClassLoader::_perf_accumulated_time = nullptr;
@@ -153,7 +162,7 @@ void ClassLoader::print_counters(outputStream *st) {
153162

154163
GrowableArray<ModuleClassPathList*>* ClassLoader::_patch_mod_entries = nullptr;
155164
GrowableArray<ModuleClassPathList*>* ClassLoader::_exploded_entries = nullptr;
156-
ClassPathEntry* ClassLoader::_jrt_entry = nullptr;
165+
ClassPathImageEntry* ClassLoader::_jrt_entry = nullptr;
157166

158167
ClassPathEntry* volatile ClassLoader::_first_append_entry_list = nullptr;
159168
ClassPathEntry* volatile ClassLoader::_last_append_entry = nullptr;
@@ -170,15 +179,6 @@ static bool string_starts_with(const char* str, const char* str_to_find) {
170179
}
171180
#endif
172181

173-
static const char* get_jimage_version_string() {
174-
static char version_string[10] = "";
175-
if (version_string[0] == '\0') {
176-
jio_snprintf(version_string, sizeof(version_string), "%d.%d",
177-
VM_Version::vm_major_version(), VM_Version::vm_minor_version());
178-
}
179-
return (const char*)version_string;
180-
}
181-
182182
bool ClassLoader::string_ends_with(const char* str, const char* str_to_find) {
183183
size_t str_len = strlen(str);
184184
size_t str_to_find_len = strlen(str_to_find);
@@ -233,6 +233,73 @@ Symbol* ClassLoader::package_from_class_name(const Symbol* name, bool* bad_class
233233
return SymbolTable::new_symbol(name, pointer_delta_as_int(start, base), pointer_delta_as_int(end, base));
234234
}
235235

236+
// --------------------------------
237+
// The following jimage_xxx static functions encapsulate all JImage_file and JImage_mode access.
238+
// This is done to make it easy to reason about the JImage file state (exists vs initialized etc.).
239+
240+
// Opens the named JImage file and sets the JImage file reference.
241+
// Returns true if opening the JImage file was successful (see also jimage_exists()).
242+
static bool jimage_open(const char* modules_path) {
243+
// Currently 'error' is not set to anything useful, so ignore it here.
244+
jint error;
245+
JImage_file = (*JImageOpen)(modules_path, &error);
246+
return JImage_file != nullptr;
247+
}
248+
249+
// Closes and clears the JImage file reference (this will only be called during shutdown).
250+
static void jimage_close() {
251+
if (JImage_file != nullptr) {
252+
(*JImageClose)(JImage_file);
253+
JImage_file = nullptr;
254+
}
255+
}
256+
257+
// Returns whether a JImage file was opened (but NOT whether it was initialized yet).
258+
static bool jimage_exists() {
259+
return JImage_file != nullptr;
260+
}
261+
262+
// Returns the JImage file reference (which may or may not be initialized).
263+
static JImageFile* jimage_non_null() {
264+
assert(jimage_exists(), "should have been opened by ClassLoader::lookup_vm_options "
265+
"and remained throughout normal JVM lifetime");
266+
return JImage_file;
267+
}
268+
269+
// Called once to set the access mode for resource (i.e. preview or non-preview) before
270+
// general resource lookup can occur.
271+
static void jimage_init(bool enable_preview) {
272+
assert(JImage_mode == JIMAGE_MODE_UNINITIALIZED, "jimage_init must not be called twice");
273+
JImage_mode = enable_preview ? JIMAGE_MODE_ENABLE_PREVIEW : JIMAGE_MODE_DEFAULT;
274+
}
275+
276+
// Returns true if jimage_init() has been called. Once the JImage file is initialized,
277+
// jimage_is_preview_enabled() can be called to correctly determine the access mode.
278+
static bool jimage_is_initialized() {
279+
return jimage_exists() && JImage_mode != JIMAGE_MODE_UNINITIALIZED;
280+
}
281+
282+
// Returns the access mode for an initialized JImage file (reflects --enable-preview).
283+
static bool jimage_is_preview_enabled() {
284+
assert(jimage_is_initialized(), "jimage is not initialized");
285+
return JImage_mode == JIMAGE_MODE_ENABLE_PREVIEW;
286+
}
287+
288+
// Looks up the location of a named JImage resource. This "raw" lookup function allows
289+
// the preview mode to be manually specified, so must not be accessible outside this
290+
// class. ClassPathImageEntry manages all calls for resources after startup is complete.
291+
static JImageLocationRef jimage_find_resource(const char* module_name,
292+
const char* file_name,
293+
bool is_preview,
294+
jlong *size) {
295+
return ((*JImageFindResource)(jimage_non_null(),
296+
module_name,
297+
file_name,
298+
is_preview,
299+
size));
300+
}
301+
// --------------------------------
302+
236303
// Given a fully qualified package name, find its defining package in the class loader's
237304
// package entry table.
238305
PackageEntry* ClassLoader::get_package_entry(Symbol* pkg_name, ClassLoaderData* loader_data) {
@@ -371,28 +438,15 @@ ClassFileStream* ClassPathZipEntry::open_stream(JavaThread* current, const char*
371438

372439
DEBUG_ONLY(ClassPathImageEntry* ClassPathImageEntry::_singleton = nullptr;)
373440

374-
JImageFile* ClassPathImageEntry::jimage() const {
375-
return JImage_file;
376-
}
377-
378-
JImageFile* ClassPathImageEntry::jimage_non_null() const {
379-
assert(ClassLoader::has_jrt_entry(), "must be");
380-
assert(jimage() != nullptr, "should have been opened by ClassLoader::lookup_vm_options "
381-
"and remained throughout normal JVM lifetime");
382-
return jimage();
383-
}
384-
385441
void ClassPathImageEntry::close_jimage() {
386-
if (jimage() != nullptr) {
387-
(*JImageClose)(jimage());
388-
JImage_file = nullptr;
389-
}
442+
jimage_close();
390443
}
391444

392-
ClassPathImageEntry::ClassPathImageEntry(JImageFile* jimage, const char* name) :
445+
ClassPathImageEntry::ClassPathImageEntry(const char* name) :
393446
ClassPathEntry() {
394-
guarantee(jimage != nullptr, "jimage file is null");
447+
guarantee(jimage_is_initialized(), "jimage is not initialized");
395448
guarantee(name != nullptr, "jimage file name is null");
449+
396450
assert(_singleton == nullptr, "VM supports only one jimage");
397451
DEBUG_ONLY(_singleton = this);
398452
size_t len = strlen(name) + 1;
@@ -411,16 +465,18 @@ ClassFileStream* ClassPathImageEntry::open_stream(JavaThread* current, const cha
411465
// 2. A package is in at most one module in the jimage file.
412466
//
413467
ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current, const char* name, ClassLoaderData* loader_data) {
468+
bool is_preview = jimage_is_preview_enabled();
469+
414470
jlong size;
415-
JImageLocationRef location = (*JImageFindResource)(jimage_non_null(), "", get_jimage_version_string(), name, &size);
471+
JImageLocationRef location = jimage_find_resource("", name, is_preview, &size);
416472

417473
if (location == 0) {
418474
TempNewSymbol class_name = SymbolTable::new_symbol(name);
419475
TempNewSymbol pkg_name = ClassLoader::package_from_class_name(class_name);
420476

421477
if (pkg_name != nullptr) {
422478
if (!Universe::is_module_initialized()) {
423-
location = (*JImageFindResource)(jimage_non_null(), JAVA_BASE_NAME, get_jimage_version_string(), name, &size);
479+
location = jimage_find_resource(JAVA_BASE_NAME, name, is_preview, &size);
424480
} else {
425481
PackageEntry* package_entry = ClassLoader::get_package_entry(pkg_name, loader_data);
426482
if (package_entry != nullptr) {
@@ -431,7 +487,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
431487
assert(module->is_named(), "Boot classLoader package is in unnamed module");
432488
const char* module_name = module->name()->as_C_string();
433489
if (module_name != nullptr) {
434-
location = (*JImageFindResource)(jimage_non_null(), module_name, get_jimage_version_string(), name, &size);
490+
location = jimage_find_resource(module_name, name, is_preview, &size);
435491
}
436492
}
437493
}
@@ -444,7 +500,7 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
444500
char* data = NEW_RESOURCE_ARRAY(char, size);
445501
(*JImageGetResource)(jimage_non_null(), location, data, size);
446502
// Resource allocated
447-
assert(this == (ClassPathImageEntry*)ClassLoader::get_jrt_entry(), "must be");
503+
assert(this == ClassLoader::get_jrt_entry(), "must be");
448504
return new ClassFileStream((u1*)data,
449505
checked_cast<int>(size),
450506
_name,
@@ -454,16 +510,9 @@ ClassFileStream* ClassPathImageEntry::open_stream_for_loader(JavaThread* current
454510
return nullptr;
455511
}
456512

457-
JImageLocationRef ClassLoader::jimage_find_resource(JImageFile* jf,
458-
const char* module_name,
459-
const char* file_name,
460-
jlong &size) {
461-
return ((*JImageFindResource)(jf, module_name, get_jimage_version_string(), file_name, &size));
462-
}
463-
464513
bool ClassPathImageEntry::is_modules_image() const {
465514
assert(this == _singleton, "VM supports a single jimage");
466-
assert(this == (ClassPathImageEntry*)ClassLoader::get_jrt_entry(), "must be used for jrt entry");
515+
assert(this == ClassLoader::get_jrt_entry(), "must be used for jrt entry");
467516
return true;
468517
}
469518

@@ -618,14 +667,15 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
618667
struct stat st;
619668
if (os::stat(path, &st) == 0) {
620669
// Directory found
621-
if (JImage_file != nullptr) {
670+
if (jimage_exists()) {
622671
assert(Arguments::has_jimage(), "sanity check");
623672
const char* canonical_path = get_canonical_path(path, current);
624673
assert(canonical_path != nullptr, "canonical_path issue");
625674

626-
_jrt_entry = new ClassPathImageEntry(JImage_file, canonical_path);
675+
// Hand over lifecycle control of the JImage file to the _jrt_entry singleton
676+
// (see ClassPathImageEntry::close_jimage). The image must be initialized by now.
677+
_jrt_entry = new ClassPathImageEntry(canonical_path);
627678
assert(_jrt_entry != nullptr && _jrt_entry->is_modules_image(), "No java runtime image present");
628-
assert(_jrt_entry->jimage() != nullptr, "No java runtime image");
629679
} // else it's an exploded build.
630680
} else {
631681
// If path does not exist, exit
@@ -1388,49 +1438,51 @@ void ClassLoader::initialize(TRAPS) {
13881438
setup_bootstrap_search_path(THREAD);
13891439
}
13901440

1391-
static char* lookup_vm_resource(JImageFile *jimage, const char *jimage_version, const char *path) {
1392-
jlong size;
1393-
JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", jimage_version, path, &size);
1394-
if (location == 0)
1395-
return nullptr;
1396-
char *val = NEW_C_HEAP_ARRAY(char, size+1, mtClass);
1397-
(*JImageGetResource)(jimage, location, val, size);
1398-
val[size] = '\0';
1399-
return val;
1400-
}
1401-
14021441
// Lookup VM options embedded in the modules jimage file
14031442
char* ClassLoader::lookup_vm_options() {
1404-
jint error;
14051443
char modules_path[JVM_MAXPATHLEN];
14061444
const char* fileSep = os::file_separator();
14071445

14081446
// Initialize jimage library entry points
14091447
load_jimage_library();
14101448

14111449
jio_snprintf(modules_path, JVM_MAXPATHLEN, "%s%slib%smodules", Arguments::get_java_home(), fileSep, fileSep);
1412-
JImage_file =(*JImageOpen)(modules_path, &error);
1413-
if (JImage_file == nullptr) {
1414-
return nullptr;
1450+
if (jimage_open(modules_path)) {
1451+
// Special case where we lookup the options string *before* calling jimage_init().
1452+
// Since VM arguments have not been parsed, and the ClassPathImageEntry singleton
1453+
// has not been created yet, we access the JImage file directly in non-preview mode.
1454+
jlong size;
1455+
JImageLocationRef location =
1456+
jimage_find_resource(JAVA_BASE_NAME, "jdk/internal/vm/options", /* is_preview */ false, &size);
1457+
if (location != 0) {
1458+
char *options = NEW_C_HEAP_ARRAY(char, size+1, mtClass);
1459+
(*JImageGetResource)(jimage_non_null(), location, options, size);
1460+
options[size] = '\0';
1461+
return options;
1462+
}
14151463
}
1464+
return nullptr;
1465+
}
14161466

1417-
const char *jimage_version = get_jimage_version_string();
1418-
char *options = lookup_vm_resource(JImage_file, jimage_version, "jdk/internal/vm/options");
1419-
return options;
1467+
// Finishes initializing the JImageFile (if present) by setting the access mode.
1468+
void ClassLoader::init_jimage(bool enable_preview) {
1469+
if (jimage_exists()) {
1470+
jimage_init(enable_preview);
1471+
}
14201472
}
14211473

14221474
bool ClassLoader::is_module_observable(const char* module_name) {
14231475
assert(JImageOpen != nullptr, "jimage library should have been opened");
1424-
if (JImage_file == nullptr) {
1476+
if (!jimage_exists()) {
14251477
struct stat st;
14261478
const char *path = get_exploded_module_path(module_name, true);
14271479
bool res = os::stat(path, &st) == 0;
14281480
FREE_C_HEAP_ARRAY(char, path);
14291481
return res;
14301482
}
1483+
// We don't expect preview mode (i.e. --enable-preview) to affect module visibility.
14311484
jlong size;
1432-
const char *jimage_version = get_jimage_version_string();
1433-
return (*JImageFindResource)(JImage_file, module_name, jimage_version, "module-info.class", &size) != 0;
1485+
return jimage_find_resource(module_name, "module-info.class", /* is_preview */ false, &size) != 0;
14341486
}
14351487

14361488
jlong ClassLoader::classloader_time_ms() {

0 commit comments

Comments
 (0)