提交 f7219d10 编写于 作者: A asaha

Merge

......@@ -965,7 +965,26 @@ db221c0a423e776bec5c3198d11d3f26827bd786 jdk8u131-b08
56e71d16083904ceddfdd1d66312582a42781646 jdk8u131-b09
1da23ae49386608550596502d90a381ee6c1dfaa jdk8u131-b10
829ea9b92cda9545652f1b309f56c57383024ebb jdk8u131-b11
41e0713bcca27cef5d6a9afd44c7ca4811937713 jdk8u131-b31
e318654a4fa352a06935dd56eebf88ae387b31f9 jdk8u131-b32
32998fc932dc58c6bbac185cc17d2752fa6dba4c jdk8u131-b33
50b3fa6791f46bc582528bdc7f6311b3b6832c51 jdk8u131-b34
692bc6b674dcab72453de08ee9da0856a7e41c0f jdk8u141-b00
0cee0db0180b64655751e7058c251103f9660f85 jdk8u141-b01
82435799636c8b50a090aebcb5af49946afa7bb5 jdk8u141-b02
678f11cc769eb79d35d49a94c769304df67a9cef jdk8u141-b03
62b0b4a31b44e8b159bff106c04ecfabc9d78d9b jdk8u141-b04
53a48dc8e4418ed422c69361193add798cb4ed55 jdk8u141-b05
4b7067065b0ad08c41a6334b44877319cbb2de54 jdk8u141-b06
42f196fd7c589e439c4e6d86b7d845ff024cfe45 jdk8u141-b07
37ba410ffd431c76961255b87398f6ace7b6794f jdk8u141-b08
b23c5879a33cf2c2e7c3e2cdfb0285bb7e64198e jdk8u141-b09
1a3f8a55df45dd79cb566d172e925faa464534f0 jdk8u141-b10
de803a292be4add77fd8a1e034481f0692c89f95 jdk8u141-b11
d6e7c7d2c6f69906b4cb643a6813eccba0de988f jdk8u141-b12
df6af363337eff5b22ae7940b0981231fdf5dfb4 jdk8u141-b13
3a1543e089c32592be9c201c6e021295fbf5fdc1 jdk8u141-b14
2d5100bddeb80cf767485b787fc3051311e3d7b9 jdk8u151-b00
596b584c68b73ec635347807571463580deb955f jdk8u151-b01
1f6f436360d5cd375b806aec1c78abb8fcb4e5f6 jdk8u151-b02
02d5e7b64b288429f3836dcfb8ac304774775965 jdk8u161-b00
此差异已折叠。
......@@ -236,7 +236,7 @@ void VM_Version::initialize() {
assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
char buf[512];
jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(has_v9() ? ", v9" : (has_v8() ? ", v8" : "")),
(has_hardware_popc() ? ", popc" : ""),
(has_vis1() ? ", vis1" : ""),
......@@ -249,6 +249,7 @@ void VM_Version::initialize() {
(has_sha256() ? ", sha256" : ""),
(has_sha512() ? ", sha512" : ""),
(is_ultra3() ? ", ultra3" : ""),
(has_sparc5_instr() ? ", sparc5" : ""),
(is_sun4v() ? ", sun4v" : ""),
(is_niagara_plus() ? ", niagara_plus" : (is_niagara() ? ", niagara" : "")),
(is_sparc64() ? ", sparc64" : ""),
......@@ -364,6 +365,7 @@ void VM_Version::initialize() {
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
tty->print_cr("L2 data cache line size: %u", L2_data_cache_line_size());
tty->print("Allocation");
if (AllocatePrefetchStyle <= 0) {
......@@ -447,9 +449,10 @@ void VM_Version::revert() {
unsigned int VM_Version::calc_parallel_worker_threads() {
unsigned int result;
if (is_M_series()) {
// for now, use same gc thread calculation for M-series as for niagara-plus
// in future, we may want to tweak parameters for nof_parallel_worker_thread
if (is_M_series() || is_S_series()) {
// for now, use same gc thread calculation for M-series and S-series as for
// niagara-plus. In future, we may want to tweak parameters for
// nof_parallel_worker_thread
result = nof_parallel_worker_threads(5, 16, 8);
} else if (is_niagara_plus()) {
result = nof_parallel_worker_threads(5, 16, 8);
......@@ -458,3 +461,37 @@ unsigned int VM_Version::calc_parallel_worker_threads() {
}
return result;
}
int VM_Version::parse_features(const char* implementation) {
int features = unknown_m;
// Convert to UPPER case before compare.
char* impl = os::strdup(implementation);
for (int i = 0; impl[i] != 0; i++)
impl[i] = (char)toupper((uint)impl[i]);
if (strstr(impl, "SPARC64") != NULL) {
features |= sparc64_family_m;
} else if (strstr(impl, "SPARC-M") != NULL) {
// M-series SPARC is based on T-series.
features |= (M_family_m | T_family_m);
} else if (strstr(impl, "SPARC-S") != NULL) {
// S-series SPARC is based on T-series.
features |= (S_family_m | T_family_m);
} else if (strstr(impl, "SPARC-T") != NULL) {
features |= T_family_m;
if (strstr(impl, "SPARC-T1") != NULL) {
features |= T1_model_m;
}
} else if (strstr(impl, "SUN4V-CPU") != NULL) {
// Generic or migration class LDOM
features |= T_family_m;
} else {
#ifndef PRODUCT
warning("Failed to parse CPU implementation = '%s'", impl);
#endif
}
os::free((void*)impl);
return features;
}
......@@ -47,13 +47,14 @@ protected:
cbcond_instructions = 13,
sparc64_family = 14,
M_family = 15,
T_family = 16,
T1_model = 17,
sparc5_instructions = 18,
aes_instructions = 19,
sha1_instruction = 20,
sha256_instruction = 21,
sha512_instruction = 22
S_family = 16,
T_family = 17,
T1_model = 18,
sparc5_instructions = 19,
aes_instructions = 20,
sha1_instruction = 21,
sha256_instruction = 22,
sha512_instruction = 23
};
enum Feature_Flag_Set {
......@@ -76,6 +77,7 @@ protected:
cbcond_instructions_m = 1 << cbcond_instructions,
sparc64_family_m = 1 << sparc64_family,
M_family_m = 1 << M_family,
S_family_m = 1 << S_family,
T_family_m = 1 << T_family,
T1_model_m = 1 << T1_model,
sparc5_instructions_m = 1 << sparc5_instructions,
......@@ -105,6 +107,7 @@ protected:
// Returns true if the platform is in the niagara line (T series)
static bool is_M_family(int features) { return (features & M_family_m) != 0; }
static bool is_S_family(int features) { return (features & S_family_m) != 0; }
static bool is_T_family(int features) { return (features & T_family_m) != 0; }
static bool is_niagara() { return is_T_family(_features); }
#ifdef ASSERT
......@@ -119,7 +122,7 @@ protected:
static bool is_T1_model(int features) { return is_T_family(features) && ((features & T1_model_m) != 0); }
static int maximum_niagara1_processor_count() { return 32; }
static int parse_features(const char* implementation);
public:
// Initialization
static void initialize();
......@@ -152,6 +155,7 @@ public:
static bool is_niagara_plus() { return is_T_family(_features) && !is_T1_model(_features); }
static bool is_M_series() { return is_M_family(_features); }
static bool is_S_series() { return is_S_family(_features); }
static bool is_T4() { return is_T_family(_features) && has_cbcond(); }
static bool is_T7() { return is_T_family(_features) && has_sparc5_instr(); }
......
......@@ -406,6 +406,8 @@ void VM_Version::get_processor_features() {
_stepping = 0;
_cpuFeatures = 0;
_logical_processors_per_package = 1;
// i486 internal cache is both I&D and has a 16-byte line size
_L1_data_cache_line_size = 16;
if (!Use486InstrsOnly) {
// Get raw processor info
......@@ -424,6 +426,7 @@ void VM_Version::get_processor_features() {
// Logical processors are only available on P4s and above,
// and only if hyperthreading is available.
_logical_processors_per_package = logical_processor_count();
_L1_data_cache_line_size = L1_line_size();
}
}
......@@ -1034,6 +1037,7 @@ void VM_Version::get_processor_features() {
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Logical CPUs per core: %u",
logical_processors_per_package());
tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
tty->print("UseSSE=%d", (int) UseSSE);
if (UseAVX > 0) {
tty->print(" UseAVX=%d", (int) UseAVX);
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, 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
......@@ -595,7 +595,7 @@ public:
return (result == 0 ? 1 : result);
}
static intx prefetch_data_size() {
static intx L1_line_size() {
intx result = 0;
if (is_intel()) {
result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1);
......@@ -607,6 +607,10 @@ public:
return result;
}
static intx prefetch_data_size() {
return L1_line_size();
}
//
// Feature identification
//
......
......@@ -262,6 +262,7 @@ void PICL::close_library() {
// We need to keep these here as long as we have to build on Solaris
// versions before 10.
#ifndef SI_ARCHITECTURE_32
#define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */
#endif
......@@ -270,231 +271,233 @@ void PICL::close_library() {
#define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */
#endif
static void do_sysinfo(int si, const char* string, int* features, int mask) {
char tmp;
size_t bufsize = sysinfo(si, &tmp, 1);
#ifndef SI_CPUBRAND
#define SI_CPUBRAND 523 /* return cpu brand string */
#endif
// All SI defines used below must be supported.
guarantee(bufsize != -1, "must be supported");
class Sysinfo {
char* _string;
public:
Sysinfo(int si) : _string(NULL) {
char tmp;
size_t bufsize = sysinfo(si, &tmp, 1);
if (bufsize != -1) {
char* buf = (char*) os::malloc(bufsize, mtInternal);
if (buf != NULL) {
if (sysinfo(si, buf, bufsize) == bufsize) {
_string = buf;
} else {
os::free(buf);
}
}
}
}
char* buf = (char*) malloc(bufsize);
~Sysinfo() {
if (_string != NULL) {
os::free(_string);
}
}
if (buf == NULL)
return;
const char* value() const {
return _string;
}
if (sysinfo(si, buf, bufsize) == bufsize) {
// Compare the string.
if (strcmp(buf, string) == 0) {
*features |= mask;
}
bool valid() const {
return _string != NULL;
}
free(buf);
}
bool match(const char* s) const {
return valid() ? strcmp(_string, s) == 0 : false;
}
bool match_substring(const char* s) const {
return valid() ? strstr(_string, s) != NULL : false;
}
};
class Sysconf {
int _value;
public:
Sysconf(int sc) : _value(-1) {
_value = sysconf(sc);
}
bool valid() const {
return _value != -1;
}
int value() const {
return _value;
}
};
#ifndef _SC_DCACHE_LINESZ
#define _SC_DCACHE_LINESZ 508 /* Data cache line size */
#endif
#ifndef _SC_L2CACHE_LINESZ
#define _SC_L2CACHE_LINESZ 527 /* Size of L2 cache line */
#endif
int VM_Version::platform_features(int features) {
// getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are
// supported on Solaris 10 and later.
if (os::Solaris::supports_getisax()) {
assert(os::Solaris::supports_getisax(), "getisax() must be available");
// Check 32-bit architecture.
do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m);
// Check 32-bit architecture.
if (Sysinfo(SI_ARCHITECTURE_32).match("sparc")) {
features |= v8_instructions_m;
}
// Check 64-bit architecture.
do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m);
// Check 64-bit architecture.
if (Sysinfo(SI_ARCHITECTURE_64).match("sparcv9")) {
features |= generic_v9_m;
}
// Extract valid instruction set extensions.
uint_t avs[2];
uint_t avn = os::Solaris::getisax(avs, 2);
assert(avn <= 2, "should return two or less av's");
uint_t av = avs[0];
// Extract valid instruction set extensions.
uint_t avs[2];
uint_t avn = os::Solaris::getisax(avs, 2);
assert(avn <= 2, "should return two or less av's");
uint_t av = avs[0];
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print("getisax(2) returned: " PTR32_FORMAT, av);
if (avn > 1) {
tty->print(", " PTR32_FORMAT, avs[1]);
}
tty->cr();
if (PrintMiscellaneous && Verbose) {
tty->print("getisax(2) returned: " PTR32_FORMAT, av);
if (avn > 1) {
tty->print(", " PTR32_FORMAT, avs[1]);
}
tty->cr();
}
#endif
if (av & AV_SPARC_MUL32) features |= hardware_mul32_m;
if (av & AV_SPARC_DIV32) features |= hardware_div32_m;
if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m;
if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m;
if (av & AV_SPARC_POPC) features |= hardware_popc_m;
if (av & AV_SPARC_VIS) features |= vis1_instructions_m;
if (av & AV_SPARC_VIS2) features |= vis2_instructions_m;
if (avn > 1) {
uint_t av2 = avs[1];
if (av & AV_SPARC_MUL32) features |= hardware_mul32_m;
if (av & AV_SPARC_DIV32) features |= hardware_div32_m;
if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m;
if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m;
if (av & AV_SPARC_POPC) features |= hardware_popc_m;
if (av & AV_SPARC_VIS) features |= vis1_instructions_m;
if (av & AV_SPARC_VIS2) features |= vis2_instructions_m;
if (avn > 1) {
uint_t av2 = avs[1];
#ifndef AV2_SPARC_SPARC5
#define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */
#endif
if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m;
}
if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m;
}
// Next values are not defined before Solaris 10
// but Solaris 8 is used for jdk6 update builds.
// We only build on Solaris 10 and up, but some of the values below
// are not defined on all versions of Solaris 10, so we define them,
// if necessary.
#ifndef AV_SPARC_ASI_BLK_INIT
#define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */
#endif
if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m;
if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m;
#ifndef AV_SPARC_FMAF
#define AV_SPARC_FMAF 0x0100 /* Fused Multiply-Add */
#endif
if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m;
if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m;
#ifndef AV_SPARC_FMAU
#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */
#define AV_SPARC_FMAU 0x0200 /* Unfused Multiply-Add */
#endif
if (av & AV_SPARC_FMAU) features |= fmau_instructions_m;
if (av & AV_SPARC_FMAU) features |= fmau_instructions_m;
#ifndef AV_SPARC_VIS3
#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */
#define AV_SPARC_VIS3 0x0400 /* VIS3 instruction set extensions */
#endif
if (av & AV_SPARC_VIS3) features |= vis3_instructions_m;
if (av & AV_SPARC_VIS3) features |= vis3_instructions_m;
#ifndef AV_SPARC_CBCOND
#define AV_SPARC_CBCOND 0x10000000 /* compare and branch instrs supported */
#endif
if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m;
if (av & AV_SPARC_CBCOND) features |= cbcond_instructions_m;
#ifndef AV_SPARC_AES
#define AV_SPARC_AES 0x00020000 /* aes instrs supported */
#endif
if (av & AV_SPARC_AES) features |= aes_instructions_m;
if (av & AV_SPARC_AES) features |= aes_instructions_m;
#ifndef AV_SPARC_SHA1
#define AV_SPARC_SHA1 0x00400000 /* sha1 instruction supported */
#endif
if (av & AV_SPARC_SHA1) features |= sha1_instruction_m;
if (av & AV_SPARC_SHA1) features |= sha1_instruction_m;
#ifndef AV_SPARC_SHA256
#define AV_SPARC_SHA256 0x00800000 /* sha256 instruction supported */
#endif
if (av & AV_SPARC_SHA256) features |= sha256_instruction_m;
if (av & AV_SPARC_SHA256) features |= sha256_instruction_m;
#ifndef AV_SPARC_SHA512
#define AV_SPARC_SHA512 0x01000000 /* sha512 instruction supported */
#endif
if (av & AV_SPARC_SHA512) features |= sha512_instruction_m;
} else {
// getisax(2) failed, use the old legacy code.
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose)
tty->print_cr("getisax(2) is not supported.");
#endif
char tmp;
size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1);
char* buf = (char*) malloc(bufsize);
if (buf != NULL) {
if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) {
// Figure out what kind of sparc we have
char *sparc_string = strstr(buf, "sparc");
if (sparc_string != NULL) { features |= v8_instructions_m;
if (sparc_string[5] == 'v') {
if (sparc_string[6] == '8') {
if (sparc_string[7] == '-') { features |= hardware_mul32_m;
features |= hardware_div32_m;
} else if (sparc_string[7] == 'p') features |= generic_v9_m;
else features |= generic_v8_m;
} else if (sparc_string[6] == '9') features |= generic_v9_m;
}
}
// Check for visualization instructions
char *vis = strstr(buf, "vis");
if (vis != NULL) { features |= vis1_instructions_m;
if (vis[3] == '2') features |= vis2_instructions_m;
}
}
free(buf);
}
}
if (av & AV_SPARC_SHA512) features |= sha512_instruction_m;
// Determine the machine type.
do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m);
if (Sysinfo(SI_MACHINE).match("sun4v")) {
features |= sun4v_m;
}
{
// Using kstat to determine the machine type.
kstat_ctl_t* kc = kstat_open();
kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL);
const char* implementation = "UNKNOWN";
if (ksp != NULL) {
if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) {
kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
for (int i = 0; i < ksp->ks_ndata; i++) {
if (strcmp((const char*)&(knm[i].name),"implementation") == 0) {
#ifndef KSTAT_DATA_STRING
#define KSTAT_DATA_STRING 9
#endif
if (knm[i].data_type == KSTAT_DATA_CHAR) {
// VM is running on Solaris 8 which does not have value.str.
implementation = &(knm[i].value.c[0]);
} else if (knm[i].data_type == KSTAT_DATA_STRING) {
// VM is running on Solaris 10.
#ifndef KSTAT_NAMED_STR_PTR
// Solaris 8 was used to build VM, define the structure it misses.
struct str_t {
union {
char *ptr; /* NULL-term string */
char __pad[8]; /* 64-bit padding */
} addr;
uint32_t len; /* # bytes for strlen + '\0' */
};
#define KSTAT_NAMED_STR_PTR(knptr) (( (str_t*)&((knptr)->value) )->addr.ptr)
#endif
implementation = KSTAT_NAMED_STR_PTR(&knm[i]);
}
// If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes
// is available to us as well
Sysinfo cpu_info(SI_CPUBRAND);
bool use_solaris_12_api = cpu_info.valid();
const char* impl;
int impl_m = 0;
if (use_solaris_12_api) {
impl = cpu_info.value();
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("cpu_info.implementation: %s", implementation);
}
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Parsing CPU implementation from %s", impl);
}
#endif
// Convert to UPPER case before compare.
char* impl = strdup(implementation);
for (int i = 0; impl[i] != 0; i++)
impl[i] = (char)toupper((uint)impl[i]);
if (strstr(impl, "SPARC64") != NULL) {
features |= sparc64_family_m;
} else if (strstr(impl, "SPARC-M") != NULL) {
// M-series SPARC is based on T-series.
features |= (M_family_m | T_family_m);
} else if (strstr(impl, "SPARC-T") != NULL) {
features |= T_family_m;
if (strstr(impl, "SPARC-T1") != NULL) {
features |= T1_model_m;
}
} else {
if (strstr(impl, "SPARC") == NULL) {
impl_m = parse_features(impl);
} else {
// Otherwise use kstat to determine the machine type.
kstat_ctl_t* kc = kstat_open();
if (kc != NULL) {
kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL);
if (ksp != NULL) {
if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) {
kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
for (int i = 0; i < ksp->ks_ndata; i++) {
if (strcmp((const char*)&(knm[i].name), "implementation") == 0) {
impl = KSTAT_NAMED_STR_PTR(&knm[i]);
#ifndef PRODUCT
// kstat on Solaris 8 virtual machines (branded zones)
// returns "(unsupported)" implementation.
warning("kstat cpu_info implementation = '%s', should contain SPARC", impl);
#endif
implementation = "SPARC";
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Parsing CPU implementation from %s", impl);
}
#endif
impl_m = parse_features(impl);
break;
}
free((void*)impl);
break;
}
} // for(
}
}
kstat_close(kc);
}
assert(strcmp(implementation, "UNKNOWN") != 0,
"unknown cpu info (changed kstat interface?)");
kstat_close(kc);
}
assert(impl_m != 0, err_msg("Unknown CPU implementation %s", impl));
features |= impl_m;
bool is_sun4v = (features & sun4v_m) != 0;
if (use_solaris_12_api && is_sun4v) {
// If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes
Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ);
if (l1_dcache_line_size.valid()) {
_L1_data_cache_line_size = l1_dcache_line_size.value();
}
// Figure out cache line sizes using PICL
PICL picl((features & sparc64_family_m) != 0, (features & sun4v_m) != 0);
_L2_data_cache_line_size = picl.L2_data_cache_line_size();
Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ);
if (l2_dcache_line_size.valid()) {
_L2_data_cache_line_size = l2_dcache_line_size.value();
}
} else {
// Otherwise figure out the cache line sizes using PICL
bool is_fujitsu = (features & sparc64_family_m) != 0;
PICL picl(is_fujitsu, is_sun4v);
_L1_data_cache_line_size = picl.L1_data_cache_line_size();
_L2_data_cache_line_size = picl.L2_data_cache_line_size();
}
return features;
}
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
......@@ -78,7 +78,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen
// The null-class-loader should always be kept alive.
_keep_alive(is_anonymous || h_class_loader.is_null()),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
// empty
......@@ -96,6 +96,45 @@ void ClassLoaderData::Dependencies::init(TRAPS) {
_list_head = oopFactory::new_objectArray(2, CHECK);
}
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
Chunk* c = _head;
while (c != NULL) {
Chunk* next = c->_next;
delete c;
c = next;
}
}
oop* ClassLoaderData::ChunkedHandleList::add(oop o) {
if (_head == NULL || _head->_size == Chunk::CAPACITY) {
Chunk* next = new Chunk(_head);
OrderAccess::release_store_ptr(&_head, next);
}
oop* handle = &_head->_data[_head->_size];
*handle = o;
OrderAccess::release_store(&_head->_size, _head->_size + 1);
return handle;
}
inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) {
for (juint i = 0; i < size; i++) {
if (c->_data[i] != NULL) {
f->do_oop(&c->_data[i]);
}
}
}
void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) {
Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head);
if (head != NULL) {
// Must be careful when reading size of head
oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size));
for (Chunk* c = head->_next; c != NULL; c = c->_next) {
oops_do_chunk(f, c, c->_size);
}
}
}
bool ClassLoaderData::claim() {
if (_claimed == 1) {
return false;
......@@ -111,7 +150,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
_handles->oops_do(f);
_handles.oops_do(f);
if (klass_closure != NULL) {
classes_do(klass_closure);
}
......@@ -342,11 +381,6 @@ ClassLoaderData::~ClassLoaderData() {
_metaspace = NULL;
// release the metaspace
delete m;
// release the handles
if (_handles != NULL) {
JNIHandleBlock::release_block(_handles);
_handles = NULL;
}
}
// Clear all the JNI handles for methods
......@@ -406,15 +440,9 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
return _metaspace;
}
JNIHandleBlock* ClassLoaderData::handles() const { return _handles; }
void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; }
jobject ClassLoaderData::add_handle(Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
if (handles() == NULL) {
set_handles(JNIHandleBlock::allocate_block());
}
return handles()->allocate_handle(h());
return (jobject) _handles.add(h());
}
// Add this metadata pointer to be freed when it's safe. This is only during
......@@ -479,7 +507,6 @@ void ClassLoaderData::dump(outputStream * const out) {
p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name());
if (claimed()) out->print(" claimed ");
if (is_unloading()) out->print(" unloading ");
out->print(" handles " INTPTR_FORMAT, p2i(handles()));
out->cr();
if (metaspace_or_null() != NULL) {
out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
......
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2017, 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
......@@ -51,7 +51,6 @@
class ClassLoaderData;
class JNIMethodBlock;
class JNIHandleBlock;
class Metadebug;
// GC root for walking class loader data created
......@@ -145,6 +144,31 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void oops_do(OopClosure* f);
};
class ChunkedHandleList VALUE_OBJ_CLASS_SPEC {
struct Chunk : public CHeapObj<mtClass> {
static const size_t CAPACITY = 32;
oop _data[CAPACITY];
volatile juint _size;
Chunk* _next;
Chunk(Chunk* c) : _next(c), _size(0) { }
};
Chunk* _head;
void oops_do_chunk(OopClosure* f, Chunk* c, const juint size);
public:
ChunkedHandleList() : _head(NULL) {}
~ChunkedHandleList();
// Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock().
// However, multiple threads can execute oops_do concurrently with add.
oop* add(oop o);
void oops_do(OopClosure* f);
};
friend class ClassLoaderDataGraph;
friend class ClassLoaderDataGraphKlassIteratorAtomic;
friend class ClassLoaderDataGraphMetaspaceIterator;
......@@ -169,7 +193,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
// Has to be an int because we cas it.
Klass* _klasses; // The classes defined by the class loader.
JNIHandleBlock* _handles; // Handles to constant pool arrays
ChunkedHandleList _handles; // Handles to constant pool arrays, etc, which
// have the same life cycle of the corresponding ClassLoader.
// 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
......@@ -196,9 +221,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void set_metaspace(Metaspace* m) { _metaspace = m; }
JNIHandleBlock* handles() const;
void set_handles(JNIHandleBlock* handles);
Mutex* metaspace_lock() const { return _metaspace_lock; }
// GC interface.
......
......@@ -1151,6 +1151,7 @@ void nmethod::clear_inline_caches() {
// Clear ICStubs of all compiled ICs
void nmethod::clear_ic_stubs() {
assert_locked_or_safepoint(CompiledIC_lock);
ResourceMark rm;
RelocIterator iter(this);
while(iter.next()) {
if (iter.type() == relocInfo::virtual_call_type) {
......
......@@ -449,8 +449,8 @@ public:
void delete_replaced_nodes() {
_replaced_nodes.reset();
}
void apply_replaced_nodes() {
_replaced_nodes.apply(this);
void apply_replaced_nodes(uint idx) {
_replaced_nodes.apply(this, idx);
}
void merge_replaced_nodes_with(SafePointNode* sfpt) {
_replaced_nodes.merge_with(sfpt->_replaced_nodes);
......
......@@ -1048,7 +1048,7 @@ void Parse::do_exits() {
kit.make_dtrace_method_exit(method());
}
if (_replaced_nodes_for_exceptions) {
kit.map()->apply_replaced_nodes();
kit.map()->apply_replaced_nodes(_new_idx);
}
// Done with exception-path processing.
ex_map = kit.make_exception_state(ex_oop);
......@@ -1069,7 +1069,7 @@ void Parse::do_exits() {
_exits.add_exception_state(ex_map);
}
}
_exits.map()->apply_replaced_nodes();
_exits.map()->apply_replaced_nodes(_new_idx);
}
//-----------------------------create_entry_map-------------------------------
......
......@@ -91,13 +91,17 @@ void ReplacedNodes::reset() {
}
// Perfom node replacement (used when returning to caller)
void ReplacedNodes::apply(Node* n) {
void ReplacedNodes::apply(Node* n, uint idx) {
if (is_empty()) {
return;
}
for (int i = 0; i < _replaced_nodes->length(); i++) {
ReplacedNode replaced = _replaced_nodes->at(i);
n->replace_edge(replaced.initial(), replaced.improved());
// Only apply if improved node was created in a callee to avoid
// issues with irreducible loops in the caller
if (replaced.improved()->_idx >= idx) {
n->replace_edge(replaced.initial(), replaced.improved());
}
}
}
......
......@@ -71,7 +71,7 @@ class ReplacedNodes VALUE_OBJ_CLASS_SPEC {
void record(Node* initial, Node* improved);
void transfer_from(const ReplacedNodes& other, uint idx);
void reset();
void apply(Node* n);
void apply(Node* n, uint idx);
void merge_with(const ReplacedNodes& other);
bool is_empty() const;
void dump(outputStream *st) const;
......
......@@ -5129,6 +5129,7 @@ void execute_internal_vm_tests() {
run_unit_test(TestKlass_test());
run_unit_test(Test_linked_list());
run_unit_test(TestChunkedList_test());
run_unit_test(ObjectMonitor::sanity_checks());
#if INCLUDE_VM_STRUCTS
run_unit_test(VMStructs::test());
#endif
......
......@@ -2529,6 +2529,10 @@ void ObjectMonitor::DeferredInitialize () {
SETKNOB(FastHSSEC) ;
#undef SETKNOB
if (Knob_Verbose) {
sanity_checks();
}
if (os::is_MP()) {
BackOffMask = (1 << Knob_SpinBackOff) - 1 ;
if (Knob_ReportSettings) ::printf ("BackOffMask=%X\n", BackOffMask) ;
......@@ -2549,6 +2553,66 @@ void ObjectMonitor::DeferredInitialize () {
InitDone = 1 ;
}
void ObjectMonitor::sanity_checks() {
int error_cnt = 0;
int warning_cnt = 0;
bool verbose = Knob_Verbose != 0 NOT_PRODUCT(|| VerboseInternalVMTests);
if (verbose) {
tty->print_cr("INFO: sizeof(ObjectMonitor)=" SIZE_FORMAT,
sizeof(ObjectMonitor));
}
uint cache_line_size = VM_Version::L1_data_cache_line_size();
if (verbose) {
tty->print_cr("INFO: L1_data_cache_line_size=%u", cache_line_size);
}
ObjectMonitor dummy;
u_char *addr_begin = (u_char*)&dummy;
u_char *addr_header = (u_char*)&dummy._header;
u_char *addr_owner = (u_char*)&dummy._owner;
uint offset_header = (uint)(addr_header - addr_begin);
if (verbose) tty->print_cr("INFO: offset(_header)=%u", offset_header);
uint offset_owner = (uint)(addr_owner - addr_begin);
if (verbose) tty->print_cr("INFO: offset(_owner)=%u", offset_owner);
if ((uint)(addr_header - addr_begin) != 0) {
tty->print_cr("ERROR: offset(_header) must be zero (0).");
error_cnt++;
}
if (cache_line_size != 0) {
// We were able to determine the L1 data cache line size so
// do some cache line specific sanity checks
if ((offset_owner - offset_header) < cache_line_size) {
tty->print_cr("WARNING: the _header and _owner fields are closer "
"than a cache line which permits false sharing.");
warning_cnt++;
}
if ((sizeof(ObjectMonitor) % cache_line_size) != 0) {
tty->print_cr("WARNING: ObjectMonitor size is not a multiple of "
"a cache line which permits false sharing.");
warning_cnt++;
}
}
ObjectSynchronizer::sanity_checks(verbose, cache_line_size, &error_cnt,
&warning_cnt);
if (verbose || error_cnt != 0 || warning_cnt != 0) {
tty->print_cr("INFO: error_cnt=%d", error_cnt);
tty->print_cr("INFO: warning_cnt=%d", warning_cnt);
}
guarantee(error_cnt == 0,
"Fatal error(s) found in ObjectMonitor::sanity_checks()");
}
#ifndef PRODUCT
void ObjectMonitor::verify() {
}
......
......@@ -189,6 +189,8 @@ public:
bool check(TRAPS); // true if the thread owns the monitor.
void check_slow(TRAPS);
void clear();
static void sanity_checks(); // public for -XX:+ExecuteInternalVMTests
// in PRODUCT for -XX:SyncKnobs=Verbose=1
#ifndef PRODUCT
void verify();
void print();
......@@ -234,8 +236,6 @@ public:
// WARNING: this must be the very first word of ObjectMonitor
// This means this class can't use any virtual member functions.
// TODO-FIXME: assert that offsetof(_header) is 0 or get rid of the
// implicit 0 offset in emitted code.
volatile markOop _header; // displaced object header word - mark
void* volatile _object; // backward object pointer - strong root
......
......@@ -319,6 +319,7 @@ void NMethodSweeper::possibly_sweep() {
}
void NMethodSweeper::sweep_code_cache() {
ResourceMark rm;
Ticks sweep_start_counter = Ticks::now();
_flushed_count = 0;
......@@ -626,6 +627,7 @@ int NMethodSweeper::process_nmethod(nmethod *nm) {
// state of the code cache if it's requested.
void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) {
if (PrintMethodFlushing) {
ResourceMark rm;
stringStream s;
// Dump code cache state into a buffer before locking the tty,
// because log_state() will use locks causing lock conflicts.
......@@ -643,6 +645,7 @@ void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) {
}
if (LogCompilation && (xtty != NULL)) {
ResourceMark rm;
stringStream s;
// Dump code cache state into a buffer before locking the tty,
// because log_state() will use locks causing lock conflicts.
......
......@@ -437,19 +437,22 @@ void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
// Hash Code handling
//
// Performance concern:
// OrderAccess::storestore() calls release() which STs 0 into the global volatile
// OrderAccess::Dummy variable. This store is unnecessary for correctness.
// Many threads STing into a common location causes considerable cache migration
// or "sloshing" on large SMP system. As such, I avoid using OrderAccess::storestore()
// until it's repaired. In some cases OrderAccess::fence() -- which incurs local
// latency on the executing processor -- is a better choice as it scales on SMP
// systems. See http://blogs.sun.com/dave/entry/biased_locking_in_hotspot for a
// discussion of coherency costs. Note that all our current reference platforms
// provide strong ST-ST order, so the issue is moot on IA32, x64, and SPARC.
// OrderAccess::storestore() calls release() which at one time stored 0
// into the global volatile OrderAccess::dummy variable. This store was
// unnecessary for correctness. Many threads storing into a common location
// causes considerable cache migration or "sloshing" on large SMP systems.
// As such, I avoided using OrderAccess::storestore(). In some cases
// OrderAccess::fence() -- which incurs local latency on the executing
// processor -- is a better choice as it scales on SMP systems.
//
// See http://blogs.oracle.com/dave/entry/biased_locking_in_hotspot for
// a discussion of coherency costs. Note that all our current reference
// platforms provide strong ST-ST order, so the issue is moot on IA32,
// x64, and SPARC.
//
// As a general policy we use "volatile" to control compiler-based reordering
// and explicit fences (barriers) to control for architectural reordering performed
// by the CPU(s) or platform.
// and explicit fences (barriers) to control for architectural reordering
// performed by the CPU(s) or platform.
struct SharedGlobals {
// These are highly shared mostly-read variables.
......@@ -1636,7 +1639,55 @@ void ObjectSynchronizer::release_monitors_owned_by_thread(TRAPS) {
}
//------------------------------------------------------------------------------
// Non-product code
// Debugging code
void ObjectSynchronizer::sanity_checks(const bool verbose,
const uint cache_line_size,
int *error_cnt_ptr,
int *warning_cnt_ptr) {
u_char *addr_begin = (u_char*)&GVars;
u_char *addr_stwRandom = (u_char*)&GVars.stwRandom;
u_char *addr_hcSequence = (u_char*)&GVars.hcSequence;
if (verbose) {
tty->print_cr("INFO: sizeof(SharedGlobals)=" SIZE_FORMAT,
sizeof(SharedGlobals));
}
uint offset_stwRandom = (uint)(addr_stwRandom - addr_begin);
if (verbose) tty->print_cr("INFO: offset(stwRandom)=%u", offset_stwRandom);
uint offset_hcSequence = (uint)(addr_hcSequence - addr_begin);
if (verbose) {
tty->print_cr("INFO: offset(_hcSequence)=%u", offset_hcSequence);
}
if (cache_line_size != 0) {
// We were able to determine the L1 data cache line size so
// do some cache line specific sanity checks
if (offset_stwRandom < cache_line_size) {
tty->print_cr("WARNING: the SharedGlobals.stwRandom field is closer "
"to the struct beginning than a cache line which permits "
"false sharing.");
(*warning_cnt_ptr)++;
}
if ((offset_hcSequence - offset_stwRandom) < cache_line_size) {
tty->print_cr("WARNING: the SharedGlobals.stwRandom and "
"SharedGlobals.hcSequence fields are closer than a cache "
"line which permits false sharing.");
(*warning_cnt_ptr)++;
}
if ((sizeof(SharedGlobals) - offset_hcSequence) < cache_line_size) {
tty->print_cr("WARNING: the SharedGlobals.hcSequence field is closer "
"to the struct end than a cache line which permits false "
"sharing.");
(*warning_cnt_ptr)++;
}
}
}
#ifndef PRODUCT
......
......@@ -121,6 +121,9 @@ class ObjectSynchronizer : AllStatic {
static void oops_do(OopClosure* f);
// debugging
static void sanity_checks(const bool verbose,
const unsigned int cache_line_size,
int *error_cnt_ptr, int *warning_cnt_ptr);
static void verify() PRODUCT_RETURN;
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
......
......@@ -50,6 +50,7 @@ bool Abstract_VM_Version::_supports_atomic_getset8 = false;
bool Abstract_VM_Version::_supports_atomic_getadd4 = false;
bool Abstract_VM_Version::_supports_atomic_getadd8 = false;
unsigned int Abstract_VM_Version::_logical_processors_per_package = 1U;
unsigned int Abstract_VM_Version::_L1_data_cache_line_size = 0;
int Abstract_VM_Version::_reserve_for_allocation_prefetch = 0;
#ifndef HOTSPOT_RELEASE_VERSION
......
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2014, 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
......@@ -42,6 +42,7 @@ class Abstract_VM_Version: AllStatic {
static bool _supports_atomic_getadd4;
static bool _supports_atomic_getadd8;
static unsigned int _logical_processors_per_package;
static unsigned int _L1_data_cache_line_size;
static int _vm_major_version;
static int _vm_minor_version;
static int _vm_build_number;
......@@ -114,6 +115,10 @@ class Abstract_VM_Version: AllStatic {
return _logical_processors_per_package;
}
static unsigned int L1_data_cache_line_size() {
return _L1_data_cache_line_size;
}
// Need a space at the end of TLAB for prefetch instructions
// which may fault when accessing memory outside of heap.
static int reserve_for_allocation_prefetch() {
......
/*
* Copyright (c) 2017, Red Hat, Inc. 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 8174164
* @summary SafePointNode::_replaced_nodes breaks with irreducible loops
* @run main/othervm -XX:-BackgroundCompilation TestReplacedNodesOSR
*
*/
public class TestReplacedNodesOSR {
static Object dummy;
static interface I {
}
static class A implements I {
}
static final class MyException extends Exception {
}
static final A obj = new A();
static I static_field() { return obj; }
// When OSR compiled, this method has an irreducible loop
static void test(int v, MyException e) {
int i = 0;
for (;;) {
if (i == 1000) {
break;
}
try {
if ((i%2) == 0) {
int j = 0;
for (;;) {
j++;
if (i+j != v) {
if (j == 1000) {
break;
}
} else {
A a = (A)static_field();
// replaced node recorded here
throw e;
}
}
}
} catch(MyException ex) {
}
i++;
// replaced node applied on return of the method
// replaced node used here
dummy = static_field();
}
}
static public void main(String[] args) {
for (int i = 0; i < 1000; i++) {
test(1100, new MyException());
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册