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
4 changes: 2 additions & 2 deletions src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,9 +789,9 @@ void VM_Version::store_cpu_features(void* buf) {
*(uint64_t*)buf = _features;
}

bool VM_Version::supports_features(void* features_buffer) {
bool VM_Version::verify_aot_code_cache_features(void* features_buffer) {
uint64_t features_to_test = *(uint64_t*)features_buffer;
return (_features & features_to_test) == features_to_test;
return (_features == features_to_test);
}

#if defined(LINUX)
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/aarch64/vm_version_aarch64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ class VM_Version : public Abstract_VM_Version {
// Size of the buffer must be same as returned by cpu_features_size()
static void store_cpu_features(void* buf);

static bool supports_features(void* features_to_test);
static bool verify_aot_code_cache_features(void* features_buffer);
};

#endif // CPU_AARCH64_VM_VERSION_AARCH64_HPP
8 changes: 4 additions & 4 deletions src/hotspot/cpu/x86/vm_version_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3366,12 +3366,12 @@ int VM_Version::cpu_features_size() {
}

void VM_Version::store_cpu_features(void* buf) {
VM_Features copy = _features;
copy.clear_feature(CPU_HT); // HT does not result in incompatibility of aot code cache
VM_Features copy = _features.aot_code_cache_features();
memcpy(buf, &copy, sizeof(VM_Features));
}

bool VM_Version::supports_features(void* features_buffer) {
bool VM_Version::verify_aot_code_cache_features(void* features_buffer) {
VM_Features* features_to_test = (VM_Features*)features_buffer;
return _features.supports_features(features_to_test);
VM_Features rt_features = _features.aot_code_cache_features();
return rt_features.verify_aot_code_cache_features(features_to_test);
}
15 changes: 11 additions & 4 deletions src/hotspot/cpu/x86/vm_version_x86.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,14 +517,21 @@ class VM_Version : public Abstract_VM_Version {
return (_features_bitmap[idx] & bit_mask(feature)) != 0;
}

bool supports_features(VM_Features* features_to_test) {
bool verify_aot_code_cache_features(VM_Features* features_to_test) {
for (int i = 0; i < features_bitmap_element_count(); i++) {
if ((_features_bitmap[i] & features_to_test->_features_bitmap[i]) != features_to_test->_features_bitmap[i]) {
if (_features_bitmap[i] != features_to_test->_features_bitmap[i]) {
return false;
}
}
}
return true;
}

VM_Features aot_code_cache_features() {
VM_Features copy = *this;
// HT does not result in incompatibility of aot code cache
copy.clear_feature(CPU_HT);
return copy;
}
};

// CPU feature flags vector, can be affected by VM settings.
Expand Down Expand Up @@ -1134,7 +1141,7 @@ class VM_Version : public Abstract_VM_Version {
// Size of the buffer must be same as returned by cpu_features_size()
static void store_cpu_features(void* buf);

static bool supports_features(void* features_to_test);
static bool verify_aot_code_cache_features(void* features_buffer);
};

#endif // CPU_X86_VM_VERSION_X86_HPP
43 changes: 26 additions & 17 deletions src/hotspot/share/code/aotCodeCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,24 @@ const char* aot_code_entry_kind_name[] = {
static LogStream& load_failure_log() {
static LogStream err_stream(LogLevel::Error, LogTagSetMapping<LOG_TAGS(aot, codecache, init)>::tagset());
static LogStream dbg_stream(LogLevel::Debug, LogTagSetMapping<LOG_TAGS(aot, codecache, init)>::tagset());
if (RequireSharedSpaces) {
if (RequireSharedSpaces || AbortVMOnAOTCodeFailure) {
return err_stream;
} else {
return dbg_stream;
}
}

// Report AOT code cache failure and exit VM
// if (AOTMode is `on` and AbortVMOnAOTCodeFailure is default)
// or AbortVMOnAOTCodeFailure is `true`.
//
// Note, specifying -XX:-AbortVMOnAOTCodeFailure on command line
// will prevent aborting VM when AOTMode is `on`. It is used for testing.

static void report_load_failure() {
if (AbortVMOnAOTCodeFailure) {
bool abort_vm = AbortVMOnAOTCodeFailure ||
(FLAG_IS_DEFAULT(AbortVMOnAOTCodeFailure) && RequireSharedSpaces);
if (abort_vm) {
vm_exit_during_initialization("Unable to use AOT Code Cache.", nullptr);
}
load_failure_log().print_cr("Unable to use AOT Code Cache.");
Expand Down Expand Up @@ -482,25 +491,25 @@ bool AOTCodeCache::Config::verify_cpu_features(AOTCodeCache* cache) const {
log.print_cr("CPU features recorded in AOTCodeCache: %s", ss.as_string());
}

if (VM_Version::supports_features(cached_cpu_features_buffer)) {
if (log.is_enabled()) {
ResourceMark rm; // required for stringStream::as_string()
stringStream ss;
char* runtime_cpu_features = NEW_RESOURCE_ARRAY(char, VM_Version::cpu_features_size());
VM_Version::store_cpu_features(runtime_cpu_features);
VM_Version::get_missing_features_name(runtime_cpu_features, cached_cpu_features_buffer, ss);
if (!ss.is_empty()) {
log.print_cr("Additional runtime CPU features: %s", ss.as_string());
}
}
} else {
if (!VM_Version::verify_aot_code_cache_features(cached_cpu_features_buffer)) {
if (load_failure_log().is_enabled()) {
ResourceMark rm; // required for stringStream::as_string()
stringStream ss;
load_failure_log().print_cr("AOT Code Cache disabled: cpu features are incompatible");
char* runtime_cpu_features = NEW_RESOURCE_ARRAY(char, VM_Version::cpu_features_size());
VM_Version::store_cpu_features(runtime_cpu_features);
VM_Version::get_missing_features_name(cached_cpu_features_buffer, runtime_cpu_features, ss);
load_failure_log().print_cr("AOT Code Cache disabled: required cpu features are missing: %s", ss.as_string());

stringStream missing_features;
VM_Version::get_missing_features_name(cached_cpu_features_buffer, runtime_cpu_features, missing_features);
if (!missing_features.is_empty()) {
load_failure_log().print_cr("cpu features that are required: \"%s\"", missing_features.as_string());
}

stringStream additional_features;
VM_Version::get_missing_features_name(runtime_cpu_features, cached_cpu_features_buffer, additional_features);
if (!additional_features.is_empty()) {
load_failure_log().print("cpu features that are additional: \"%s\"", additional_features.as_string());
}
load_failure_log().print_cr("");
}
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/runtime/abstract_vm_version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ class Abstract_VM_Version: AllStatic {
// Size of the buffer must be same as returned by cpu_features_size()
static void store_cpu_features(void* buf) { return; }

// features_to_test is an opaque object that stores arch specific representation of cpu features
static bool supports_features(void* features_to_test) { return false; };
// features_buffer is an opaque object that stores arch specific representation of cpu features
static bool verify_aot_code_cache_features(void* features_buffer) { return false; };
};

#endif // SHARE_RUNTIME_ABSTRACT_VM_VERSION_HPP
Original file line number Diff line number Diff line change
Expand Up @@ -51,41 +51,77 @@
import jdk.test.whitebox.cpuinfo.CPUInfo;

public class AOTCodeCPUFeatureIncompatibilityTest {
enum IncompatibilityMode {
MISSING,
ADDITIONAL
}
public static void main(String... args) throws Exception {
int mode;
List<String> cpuFeatures = CPUInfo.getFeatures();
if (Platform.isX64()) {
// Minimum value of UseSSE required by JVM is 2. So the production run has to be executed with UseSSE=2.
// To simulate the case of incmpatible SSE feature, we can run this test only on system with higher SSE level (sse3 or above).
if (isSSE3Supported(cpuFeatures)) {
testIncompatibleFeature("-XX:UseSSE=2", "sse3");
testIncompatibleFeature("-XX:UseSSE=2", "sse3", IncompatibilityMode.MISSING);
testIncompatibleFeature("-XX:UseSSE=2", "sse3", IncompatibilityMode.ADDITIONAL);
}
if (isAVXSupported(cpuFeatures)) {
testIncompatibleFeature("-XX:UseAVX=0", "avx");
testIncompatibleFeature("-XX:UseAVX=0", "avx", IncompatibilityMode.MISSING);
testIncompatibleFeature("-XX:UseAVX=0", "avx", IncompatibilityMode.ADDITIONAL);
}
} else if (Platform.isAArch64()) {
if (isCRC32Supported(cpuFeatures)) {
testIncompatibleFeature("-XX:-UseCRC32", "crc32", IncompatibilityMode.MISSING);
testIncompatibleFeature("-XX:-UseCRC32", "crc32", IncompatibilityMode.ADDITIONAL);
}
}
}

// vmOption = command line option to disable CPU feature
// featureName = name of the CPU feature used by the JVM in the log messages
public static void testIncompatibleFeature(String vmOption, String featureName) throws Exception {
public static void testIncompatibleFeature(String vmOption, String featureName, IncompatibilityMode mode) throws Exception {
new CDSAppTester("AOTCodeCPUFeatureIncompatibilityTest") {
@Override
public String[] vmArgs(RunMode runMode) {
if (runMode == RunMode.PRODUCTION) {
return new String[] {vmOption, "-Xlog:aot+codecache*=debug"};
} else {
return new String[] {"-Xlog:aot+codecache*=debug"};
if (runMode == RunMode.ASSEMBLY) {
if (mode == IncompatibilityMode.MISSING) {
return new String[] {"-Xlog:aot+codecache*=debug"};
} else {
return new String[] {vmOption, "-Xlog:aot+codecache*=debug"};
}
} else if (runMode == RunMode.PRODUCTION) {
if (mode == IncompatibilityMode.MISSING) {
return new String[] {vmOption,
"-XX:+UnlockDiagnosticVMOptions",
// Prevent exiting VM on failure
"-XX:-AbortVMOnAOTCodeFailure",
"-Xlog:aot+codecache*=debug"};
} else {
return new String[] {"-XX:+UnlockDiagnosticVMOptions",
// Prevent exiting VM on failure
"-XX:-AbortVMOnAOTCodeFailure",
"-Xlog:aot+codecache*=debug"};
}
}
return new String[]{};
}
@Override
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
if (runMode == RunMode.ASSEMBLY || runMode == RunMode.PRODUCTION) {
out.shouldMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*");
if (mode == IncompatibilityMode.MISSING) {
out.shouldMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*");
} else {
out.shouldNotMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*");
}
}

if (runMode == RunMode.PRODUCTION) {
out.shouldMatch("AOT Code Cache disabled: required cpu features are missing:.*" + featureName + ".*");
out.shouldContain("Unable to use AOT Code Cache");
out.shouldMatch("AOT Code Cache disabled: cpu features are incompatible");
if (mode == IncompatibilityMode.MISSING) {
out.shouldMatch("cpu features that are required:.*" + featureName + ".*");
} else {
out.shouldMatch("cpu features that are additional:.*" + featureName + ".*");
}
}
}
@Override
Expand All @@ -108,4 +144,9 @@ static boolean isSSE3Supported(List<String> cpuFeatures) {
static boolean isAVXSupported(List<String> cpuFeatures) {
return cpuFeatures.contains("avx");
}

// Only used on aarch64 platofrm
static boolean isCRC32Supported(List<String> cpuFeatures) {
return cpuFeatures.contains("crc32");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public String[] vmArgs(RunMode runMode) {
case RunMode.PRODUCTION: {
List<String> args = getVMArgsForHeapConfig(zeroBaseInProdPhase, zeroShiftInProdPhase);
args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions",
"-XX:-AbortVMOnAOTCodeFailure",
"-Xlog:aot=info", // we need this to parse CompressedOops settings
"-Xlog:aot+codecache+init=debug",
"-Xlog:aot+codecache+exit=debug"));
Expand Down