bool Arguments::parse_argument(const char* arg, Flag::Flags origin) {
#define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]"
#define BUFLEN 255
char name[BUFLEN+1];
char dummy;
if (sscanf(arg, "-%" XSTR(BUFLEN) NAME_RANGE "%c", name, &dummy) == 1) {
return set_bool_flag(name, false, origin);
}
if (sscanf(arg, "+%" XSTR(BUFLEN) NAME_RANGE "%c", name, &dummy) == 1) {
return set_bool_flag(name, true, origin);
}
char punct;
if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "%c", name, &punct) == 2 && punct == '=') {
const char* value = strchr(arg, '=') + 1;
Flag* flag = Flag::find_flag(name, strlen(name));
if (flag != NULL && flag->is_ccstr()) {
if (flag->ccstr_accumulates()) {
return append_to_string_flag(name, value, origin);
} else {
if (value[0] == '\0') {
value = NULL;
}
return set_string_flag(name, value, origin);
}
}
}
if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE ":%c", name, &punct) == 2 && punct == '=') {
const char* value = strchr(arg, '=') + 1;
if (value[0] == '\0') {
value = NULL;
}
return set_string_flag(name, value, origin);
}
#define SIGNED_FP_NUMBER_RANGE "[-0123456789.]"
#define SIGNED_NUMBER_RANGE "[-0123456789]"
#define NUMBER_RANGE "[0123456789]"
char value[BUFLEN + 1];
char value2[BUFLEN + 1];
if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "=" "%" XSTR(BUFLEN) SIGNED_NUMBER_RANGE "." "%" XSTR(BUFLEN) NUMBER_RANGE "%c", name, value, value2, &dummy) == 3) {
if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "=" "%" XSTR(BUFLEN) SIGNED_FP_NUMBER_RANGE "%c", name, value, &dummy) == 2) {
return set_fp_numeric_flag(name, value, origin);
}
}
#define VALUE_RANGE "[-kmgtKMGT0123456789]"
if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "=" "%" XSTR(BUFLEN) VALUE_RANGE "%c", name, value, &dummy) == 2) {
return set_numeric_flag(name, value, origin);
}
return false;
}
void Arguments::add_string(char*** bldarray, int* count, const char* arg) {
assert(bldarray != NULL, "illegal argument");
if (arg == NULL) {
return;
}
int new_count = *count + 1;
if (*bldarray == NULL) {
} else {
}
(*bldarray)[*count] = strdup(arg);
}
void Arguments::build_jvm_args(const char* arg) {
add_string(&_jvm_args_array, &_num_jvm_args, arg);
}
void Arguments::build_jvm_flags(const char* arg) {
add_string(&_jvm_flags_array, &_num_jvm_flags, arg);
}
const char* Arguments::build_resource_string(char** args, int count) {
if (args == NULL || count == 0) {
return NULL;
}
size_t length = 0;
for (int i = 0; i < count; i++) {
length += strlen(args[i]) + 1; // add 1 for a space or NULL terminating character
}
char* s = NEW_RESOURCE_ARRAY(char, length);
char* dst = s;
for (int j = 0; j < count; j++) {
size_t offset = strlen(args[j]) + 1; // add 1 for a space or NULL terminating character
jio_snprintf(dst, length, "%s ", args[j]); // jio_snprintf will replace the last space character with NULL character
dst += offset;
length -= offset;
}
return (const char*) s;
}
void Arguments::print_on(outputStream* st) {
st->print_cr("VM Arguments:");
if (num_jvm_flags() > 0) {
st->print("jvm_flags: "); print_jvm_flags_on(st);
}
if (num_jvm_args() > 0) {
st->print("jvm_args: "); print_jvm_args_on(st);
}
st->print_cr("java_command: %s", java_command() ? java_command() : "<unknown>");
if (_java_class_path != NULL) {
char* path = _java_class_path->value();
st->print_cr("java_class_path (initial): %s", strlen(path) == 0 ? "<not set>" : path );
}
st->print_cr("Launcher Type: %s", _sun_java_launcher);
}
void Arguments::print_jvm_flags_on(outputStream* st) {
if (_num_jvm_flags > 0) {
for (int i=0; i < _num_jvm_flags; i++) {
st->print("%s ", _jvm_flags_array[i]);
}
st->cr();
}
}
void Arguments::print_jvm_args_on(outputStream* st) {
if (_num_jvm_args > 0) {
for (int i=0; i < _num_jvm_args; i++) {
st->print("%s ", _jvm_args_array[i]);
}
st->cr();
}
}
bool Arguments::process_argument(const char* arg,
jboolean ignore_unrecognized, Flag::Flags origin) {
JDK_Version since = JDK_Version();
if (parse_argument(arg, origin) || ignore_unrecognized) {
return true;
}
bool has_plus_minus = (*arg == '+' || *arg == '-');
const char* const argname = has_plus_minus ? arg + 1 : arg;
if (is_newly_obsolete(arg, &since)) {
char version[256];
since.to_string(version, sizeof(version));
warning("ignoring option %s; support was removed in %s", argname, version);
return true;
}
size_t arg_len;
const char* equal_sign = strchr(argname, '=');
if (equal_sign == NULL) {
arg_len = strlen(argname);
} else {
arg_len = equal_sign - argname;
}
Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true, true);
if (found_flag != NULL) {
char locked_message_buf[BUFLEN];
found_flag->get_locked_message(locked_message_buf, BUFLEN);
if (strlen(locked_message_buf) == 0) {
if (found_flag->is_bool() && !has_plus_minus) {
jio_fprintf(defaultStream::error_stream(),
"Missing +/- setting for VM option '%s'\n", argname);
} else if (!found_flag->is_bool() && has_plus_minus) {
jio_fprintf(defaultStream::error_stream(),
"Unexpected +/- setting in VM option '%s'\n", argname);
} else {
jio_fprintf(defaultStream::error_stream(),
"Improperly specified VM option '%s'\n", argname);
}
} else {
jio_fprintf(defaultStream::error_stream(), "%s", locked_message_buf);
}
} else {
jio_fprintf(defaultStream::error_stream(),
"Unrecognized VM option '%s'\n", argname);
Flag* fuzzy_matched = Flag::fuzzy_match((const char*)argname, arg_len, true);
if (fuzzy_matched != NULL) {
jio_fprintf(defaultStream::error_stream(),
"Did you mean '%s%s%s'?\n",
(fuzzy_matched->is_bool()) ? "(+/-)" : "",
fuzzy_matched->_name,
(fuzzy_matched->is_bool()) ? "" : "=<value>");
}
}
return arg[0] == '#';
}
bool Arguments::process_settings_file(const char* file_name, bool should_exist, jboolean ignore_unrecognized) {
FILE* stream = fopen(file_name, "rb");
if (stream == NULL) {
if (should_exist) {
jio_fprintf(defaultStream::error_stream(),
"Could not open settings file %s\n", file_name);
return false;
} else {
return true;
}
}
char token[1024];
int pos = 0;
bool in_white_space = true;
bool in_comment = false;
bool in_quote = false;
char quote_c = 0;
bool result = true;
int c = getc(stream);
while(c != EOF && pos < (int)(sizeof(token)-1)) {
if (in_white_space) {
if (in_comment) {
if (c == '\n') in_comment = false;
} else {
if (c == '#') in_comment = true;
else if (!isspace(c)) {
in_white_space = false;
token[pos++] = c;
}
}
} else {
if (c == '\n' || (!in_quote && isspace(c))) {
token[pos] = '\0';
logOption(token);
result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE);
build_jvm_flags(token);
pos = 0;
in_white_space = true;
in_quote = false;
} else if (!in_quote && (c == '\'' || c == '"')) {
in_quote = true;
quote_c = c;
} else if (in_quote && (c == quote_c)) {
in_quote = false;
} else {
token[pos++] = c;
}
}
c = getc(stream);
}
if (pos > 0) {
token[pos] = '\0';
result &= process_argument(token, ignore_unrecognized, Flag::CONFIG_FILE);
build_jvm_flags(token);
}
fclose(stream);
return result;
}
const char* Arguments::get_property(const char* key) {
return PropertyList_get_value(system_properties(), key);
}
bool Arguments::add_property(const char* prop) {
const char* eq = strchr(prop, '=');
char* key;
const static char ns[1] = {0};
char* value = (char *)ns;
size_t key_len = (eq == NULL) ? strlen(prop) : (eq - prop);
key = AllocateHeap(key_len + 1, mtInternal);
strncpy(key, prop, key_len);
key[key_len] = '\0';
if (eq != NULL) {
size_t value_len = strlen(prop) - key_len - 1;
value = AllocateHeap(value_len + 1, mtInternal);
strncpy(value, &prop[key_len + 1], value_len + 1);
}
if (strcmp(key, "java.compiler") == 0) {
process_java_compiler_argument(value);
FreeHeap(key);
if (eq != NULL) {
FreeHeap(value);
}
return true;
} else if (strcmp(key, "sun.java.command") == 0) {
_java_command = value;
} else if (strcmp(key, "sun.java.launcher.pid") == 0) {
FreeHeap(key);
if (eq != NULL) {
FreeHeap(value);
}
return true;
} else if (strcmp(key, "java.vendor.url.bug") == 0) {
_java_vendor_url_bug = value;
} else if (strcmp(key, "sun.boot.library.path") == 0) {
PropertyList_unique_add(&_system_properties, key, value, true);
return true;
}
PropertyList_unique_add(&_system_properties, key, value);
return true;
}
void Arguments::set_mode_flags(Mode mode) {
set_java_compiler(false);
_mode = mode;
PropertyList_unique_add(&_system_properties, "java.vm.info",
(char*)VM_Version::vm_info_string(), false);
UseInterpreter = true;
UseCompiler = true;
UseLoopCounter = true;
#ifndef ZERO
if (FLAG_IS_DEFAULT(UseFastAccessorMethods)) {
UseFastAccessorMethods = (mode == _int);
}
if (FLAG_IS_DEFAULT(UseFastEmptyMethods)) {
UseFastEmptyMethods = (mode == _int);
}
#endif
ClipInlining = Arguments::_ClipInlining;
AlwaysCompileLoopMethods = Arguments::_AlwaysCompileLoopMethods;
UseOnStackReplacement = Arguments::_UseOnStackReplacement;
BackgroundCompilation = Arguments::_BackgroundCompilation;
switch (mode) {
default:
ShouldNotReachHere();
break;
case _int:
UseCompiler = false;
UseLoopCounter = false;
AlwaysCompileLoopMethods = false;
UseOnStackReplacement = false;
break;
case _mixed:
break;
case _comp:
UseInterpreter = false;
BackgroundCompilation = false;
ClipInlining = false;
if (TieredCompilation) {
Tier3InvokeNotifyFreqLog = 0;
Tier4InvocationThreshold = 0;
}
break;
}
}
#if defined(COMPILER2) || defined(_LP64) || !INCLUDE_CDS
static void no_shared_spaces(const char* message) {
if (RequireSharedSpaces) {
jio_fprintf(defaultStream::error_stream(),
"Class data sharing is inconsistent with other specified options.\n");
vm_exit_during_initialization("Unable to use shared archive.", message);
} else {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
}
}
#endif
void Arguments::set_tiered_flags() {
if (FLAG_IS_DEFAULT(CompilationPolicyChoice)) {
FLAG_SET_DEFAULT(CompilationPolicyChoice, 3);
}
if (CompilationPolicyChoice < 2) {
vm_exit_during_initialization(
"Incompatible compilation policy selected", NULL);
}
if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
#ifndef AARCH64
FLAG_SET_DEFAULT(ReservedCodeCacheSize, ReservedCodeCacheSize * 5);
#else
FLAG_SET_DEFAULT(ReservedCodeCacheSize,
MIN2(CODE_CACHE_DEFAULT_LIMIT, ReservedCodeCacheSize * 5));
#endif
}
if (!UseInterpreter) { // -Xcomp
Tier3InvokeNotifyFreqLog = 0;
Tier4InvocationThreshold = 0;
}
}
int Arguments::get_min_number_of_compiler_threads() {
#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK)
return 0; // case 1
#else
if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) {
return 1; // case 2 or case 3
}
return 2; // case 4 (tiered)
#endif
}
#if INCLUDE_ALL_GCS
static void disable_adaptive_size_policy(const char* collector_name) {
if (UseAdaptiveSizePolicy) {
if (FLAG_IS_CMDLINE(UseAdaptiveSizePolicy)) {
warning("disabling UseAdaptiveSizePolicy; it is incompatible with %s.",
collector_name);
}
FLAG_SET_DEFAULT(UseAdaptiveSizePolicy, false);
}
}
void Arguments::set_parnew_gc_flags() {
assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC && !UseG1GC,
"control point invariant");
assert(UseParNewGC, "Error");
disable_adaptive_size_policy("UseParNewGC");
if (FLAG_IS_DEFAULT(ParallelGCThreads)) {
FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads());
assert(ParallelGCThreads > 0, "We should always have at least one thread by default");
} else if (ParallelGCThreads == 0) {
jio_fprintf(defaultStream::error_stream(),
"The ParNew GC can not be combined with -XX:ParallelGCThreads=0\n");
vm_exit(1);
}
if (FLAG_IS_DEFAULT(YoungPLABSize)) {
FLAG_SET_DEFAULT(YoungPLABSize, (intx)1024);
}
if (FLAG_IS_DEFAULT(OldPLABSize)) {
FLAG_SET_DEFAULT(OldPLABSize, (intx)1024);
}
if (AlwaysTenure) {
FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0);
}
if (UseCompressedOops && !ParGCUseLocalOverflow) {
if (!FLAG_IS_DEFAULT(ParGCUseLocalOverflow)) {
warning("Forcing +ParGCUseLocalOverflow: needed if using compressed references");
}
FLAG_SET_DEFAULT(ParGCUseLocalOverflow, true);
}
assert(ParGCUseLocalOverflow || !UseCompressedOops, "Error");
}
void Arguments::set_cms_and_parnew_gc_flags() {
assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC, "Error");
assert(UseConcMarkSweepGC, "CMS is expected to be on here");
if (FLAG_IS_DEFAULT(UseParNewGC)) {
FLAG_SET_ERGO(bool, UseParNewGC, true);
}
disable_adaptive_size_policy("UseConcMarkSweepGC");
if (UseParNewGC) {
set_parnew_gc_flags();
}
size_t max_heap = align_size_down(MaxHeapSize,
CardTableRS::ct_max_alignment_constraint());
intx tenuring_default = (intx)6;
size_t young_gen_per_worker = CMSYoungGenPerWorker;
const uintx parallel_gc_threads =
(ParallelGCThreads == 0 ? 1 : ParallelGCThreads);
const size_t preferred_max_new_size_unaligned =
MIN2(max_heap/(NewRatio+1), ScaleForWordSize(young_gen_per_worker * parallel_gc_threads));
size_t preferred_max_new_size =
align_size_up(preferred_max_new_size_unaligned, os::vm_page_size());
if (FLAG_IS_DEFAULT(MaxNewSize) && FLAG_IS_DEFAULT(NewRatio)) {
if (!FLAG_IS_DEFAULT(NewSize)) { // NewSize explicitly set at command-line
FLAG_SET_ERGO(uintx, MaxNewSize, MAX2(NewSize, preferred_max_new_size));
} else {
FLAG_SET_ERGO(uintx, MaxNewSize, preferred_max_new_size);
}
if (PrintGCDetails && Verbose) {
tty->print_cr("CMS ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize);
}
if (PrintGCDetails && Verbose) {
tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT
" initial_heap_size: " SIZE_FORMAT
" max_heap: " SIZE_FORMAT,
min_heap_size(), InitialHeapSize, max_heap);
}
size_t min_new = preferred_max_new_size;
if (FLAG_IS_CMDLINE(NewSize)) {
min_new = NewSize;
}
if (max_heap > min_new && min_heap_size() > min_new) {
if (FLAG_IS_DEFAULT(NewSize)) {
FLAG_SET_ERGO(uintx, NewSize, MAX2(NewSize, min_new));
FLAG_SET_ERGO(uintx, NewSize, MIN2(preferred_max_new_size, NewSize));
if (PrintGCDetails && Verbose) {
tty->print_cr("CMS ergo set NewSize: " SIZE_FORMAT, NewSize);
}
}
if (FLAG_IS_DEFAULT(OldSize)) {
if (max_heap > NewSize) {
FLAG_SET_ERGO(uintx, OldSize, MIN2(NewRatio*NewSize, max_heap - NewSize));
if (PrintGCDetails && Verbose) {
tty->print_cr("CMS ergo set OldSize: " SIZE_FORMAT, OldSize);
}
}
}
}
}
if (FLAG_IS_DEFAULT(MaxTenuringThreshold) &&
FLAG_IS_DEFAULT(SurvivorRatio)) {
FLAG_SET_ERGO(uintx, MaxTenuringThreshold, tenuring_default);
}
if (FLAG_IS_DEFAULT(SurvivorRatio) && MaxTenuringThreshold == 0) {
FLAG_SET_ERGO(uintx, SurvivorRatio, MAX2((uintx)1024, SurvivorRatio));
}
if (!FLAG_IS_DEFAULT(OldPLABSize)) {
if (FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim)) {
FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, OldPLABSize);
} else {
jio_fprintf(defaultStream::error_stream(),
"Both OldPLABSize and CMSParPromoteBlocksToClaim"
" options are specified for the CMS collector."
" CMSParPromoteBlocksToClaim will take precedence.\n");
}
}
if (!FLAG_IS_DEFAULT(ResizeOldPLAB) && !ResizeOldPLAB) {
if (FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim)) {
FLAG_SET_ERGO(uintx, CMSParPromoteBlocksToClaim, 50); // default value before 6631166
}
}
FLAG_SET_ERGO(uintx, OldPLABSize, CMSParPromoteBlocksToClaim);
if (!FLAG_IS_DEFAULT(CMSParPromoteBlocksToClaim) || !FLAG_IS_DEFAULT(OldPLABWeight)) {
CFLS_LAB::modify_initialization(OldPLABSize, OldPLABWeight);
}
if (PrintGCDetails && Verbose) {
tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk",
(unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K));
tty->print_cr("ConcGCThreads: %u", (uint) ConcGCThreads);
}
}
#endif // INCLUDE_ALL_GCS
void set_object_alignment() {
assert(is_power_of_2(ObjectAlignmentInBytes), "ObjectAlignmentInBytes must be power of 2");
MinObjAlignmentInBytes = ObjectAlignmentInBytes;
assert(MinObjAlignmentInBytes >= HeapWordsPerLong * HeapWordSize, "ObjectAlignmentInBytes value is too small");
MinObjAlignment = MinObjAlignmentInBytes / HeapWordSize;
assert(MinObjAlignmentInBytes == MinObjAlignment * HeapWordSize, "ObjectAlignmentInBytes value is incorrect");
MinObjAlignmentInBytesMask = MinObjAlignmentInBytes - 1;
LogMinObjAlignmentInBytes = exact_log2(ObjectAlignmentInBytes);
LogMinObjAlignment = LogMinObjAlignmentInBytes - LogHeapWordSize;
OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes;
#if INCLUDE_ALL_GCS
CompactibleFreeListSpace::set_cms_values();
#endif // INCLUDE_ALL_GCS
}
bool verify_object_alignment() {
if (!is_power_of_2(ObjectAlignmentInBytes)) {
jio_fprintf(defaultStream::error_stream(),
"error: ObjectAlignmentInBytes=%d must be power of 2\n",
(int)ObjectAlignmentInBytes);
return false;
}
if ((int)ObjectAlignmentInBytes < BytesPerLong) {
jio_fprintf(defaultStream::error_stream(),
"error: ObjectAlignmentInBytes=%d must be greater or equal %d\n",
(int)ObjectAlignmentInBytes, BytesPerLong);
return false;
}
if ((int)ObjectAlignmentInBytes > 256) {
jio_fprintf(defaultStream::error_stream(),
"error: ObjectAlignmentInBytes=%d must not be greater than 256\n",
(int)ObjectAlignmentInBytes);
return false;
}
if ((int)ObjectAlignmentInBytes >= os::vm_page_size()) {
jio_fprintf(defaultStream::error_stream(),
"error: ObjectAlignmentInBytes=%d must be less than page size %d\n",
(int)ObjectAlignmentInBytes, os::vm_page_size());
return false;
}
if(SurvivorAlignmentInBytes == 0) {
SurvivorAlignmentInBytes = ObjectAlignmentInBytes;
} else {
if (!is_power_of_2(SurvivorAlignmentInBytes)) {
jio_fprintf(defaultStream::error_stream(),
"error: SurvivorAlignmentInBytes=%d must be power of 2\n",
(int)SurvivorAlignmentInBytes);
return false;
}
if (SurvivorAlignmentInBytes < ObjectAlignmentInBytes) {
jio_fprintf(defaultStream::error_stream(),
"error: SurvivorAlignmentInBytes=%d must be greater than ObjectAlignmentInBytes=%d \n",
(int)SurvivorAlignmentInBytes, (int)ObjectAlignmentInBytes);
return false;
}
}
return true;
}
size_t Arguments::max_heap_for_compressed_oops() {
assert(OopEncodingHeapMax > (uint64_t)os::vm_page_size(), "Unusual page size");
size_t displacement_due_to_null_page = align_size_up_(os::vm_page_size(),
_conservative_max_heap_alignment);
LP64_ONLY(return OopEncodingHeapMax - displacement_due_to_null_page);
NOT_LP64(ShouldNotReachHere(); return 0);
}
bool Arguments::should_auto_select_low_pause_collector() {
if (UseAutoGCSelectPolicy &&
!FLAG_IS_DEFAULT(MaxGCPauseMillis) &&
(MaxGCPauseMillis <= AutoGCSelectPauseMillis)) {
if (PrintGCDetails) {
tty->print_cr("Automatic selection of the low pause collector"
" based on pause goal of %d (ms)", (int) MaxGCPauseMillis);
}
return true;
}
return false;
}
void Arguments::set_use_compressed_oops() {
#ifndef ZERO
#ifdef _LP64
size_t max_heap_size = MAX2(MaxHeapSize, InitialHeapSize);
if (max_heap_size <= max_heap_for_compressed_oops()) {
#if !defined(COMPILER1) || defined(TIERED)
if (FLAG_IS_DEFAULT(UseCompressedOops)) {
FLAG_SET_ERGO(bool, UseCompressedOops, true);
}
#endif
#ifdef _WIN64
if (UseLargePages && UseCompressedOops) {
Universe::set_narrow_oop_use_implicit_null_checks(false);
}
#endif // _WIN64
} else {
if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) {
warning("Max heap size too large for Compressed Oops");
FLAG_SET_DEFAULT(UseCompressedOops, false);
FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
}
}
#endif // _LP64
#endif // ZERO
}
void Arguments::set_use_compressed_klass_ptrs() {
#ifndef ZERO
#ifdef _LP64
if (!UseCompressedOops) {
if (UseCompressedClassPointers) {
warning("UseCompressedClassPointers requires UseCompressedOops");
}
FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
} else {
if (FLAG_IS_DEFAULT(UseCompressedClassPointers)) {
FLAG_SET_ERGO(bool, UseCompressedClassPointers, true);
}
if (UseCompressedClassPointers) {
if (CompressedClassSpaceSize > KlassEncodingMetaspaceMax) {
warning("CompressedClassSpaceSize is too large for UseCompressedClassPointers");
FLAG_SET_DEFAULT(UseCompressedClassPointers, false);
}
}
}
#endif // _LP64
#endif // !ZERO
}
void Arguments::set_conservative_max_heap_alignment() {
size_t heap_alignment = GenCollectedHeap::conservative_max_heap_alignment();
#if INCLUDE_ALL_GCS
if (UseParallelGC) {
heap_alignment = ParallelScavengeHeap::conservative_max_heap_alignment();
} else if (UseG1GC) {
heap_alignment = G1CollectedHeap::conservative_max_heap_alignment();
}
#endif // INCLUDE_ALL_GCS
_conservative_max_heap_alignment = MAX4(heap_alignment,
(size_t)os::vm_allocation_granularity(),
os::max_page_size(),
CollectorPolicy::compute_heap_alignment());
}
void Arguments::select_gc_ergonomically() {
if (os::is_server_class_machine()) {
if (should_auto_select_low_pause_collector()) {
FLAG_SET_ERGO(bool, UseConcMarkSweepGC, true);
} else {
FLAG_SET_ERGO(bool, UseParallelGC, true);
}
}
}
void Arguments::select_gc() {
if (!gc_selected()) {
select_gc_ergonomically();
}
}
void Arguments::set_ergonomics_flags() {
select_gc();
#ifdef COMPILER2
if (!DumpSharedSpaces && !RequireSharedSpaces &&
(FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) {
no_shared_spaces("COMPILER2 default: -Xshare:auto | off, have to manually setup to on.");
}
#endif
set_conservative_max_heap_alignment();
#ifndef ZERO
#ifdef _LP64
set_use_compressed_oops();
set_use_compressed_klass_ptrs();
#endif // _LP64
#endif // !ZERO
}
void Arguments::set_parallel_gc_flags() {
assert(UseParallelGC || UseParallelOldGC, "Error");
if (FLAG_IS_DEFAULT(UseParallelOldGC)) {
FLAG_SET_DEFAULT(UseParallelOldGC, true);
}
FLAG_SET_DEFAULT(UseParallelGC, true);
FLAG_SET_DEFAULT(ParallelGCThreads,
Abstract_VM_Version::parallel_worker_threads());
if (ParallelGCThreads == 0) {
jio_fprintf(defaultStream::error_stream(),
"The Parallel GC can not be combined with -XX:ParallelGCThreads=0\n");
vm_exit(1);
}
if (UseAdaptiveSizePolicy) {
if (FLAG_IS_DEFAULT(MinHeapFreeRatio)) {
FLAG_SET_DEFAULT(MinHeapFreeRatio, 0);
_min_heap_free_ratio = MinHeapFreeRatio;
}
if (FLAG_IS_DEFAULT(MaxHeapFreeRatio)) {
FLAG_SET_DEFAULT(MaxHeapFreeRatio, 100);
_max_heap_free_ratio = MaxHeapFreeRatio;
}
}
if (!FLAG_IS_DEFAULT(SurvivorRatio)) {
if (FLAG_IS_DEFAULT(InitialSurvivorRatio)) {
FLAG_SET_DEFAULT(InitialSurvivorRatio, SurvivorRatio + 2);
}
if (FLAG_IS_DEFAULT(MinSurvivorRatio)) {
FLAG_SET_DEFAULT(MinSurvivorRatio, SurvivorRatio + 2);
}
}
if (UseParallelOldGC) {
if (FLAG_IS_DEFAULT(MarkSweepDeadRatio)) {
FLAG_SET_DEFAULT(MarkSweepDeadRatio, 1);
}
}
}
void Arguments::set_g1_gc_flags() {
assert(UseG1GC, "Error");
#ifdef COMPILER1
FastTLABRefill = false;
#endif
FLAG_SET_DEFAULT(ParallelGCThreads,
Abstract_VM_Version::parallel_worker_threads());
if (ParallelGCThreads == 0) {
vm_exit_during_initialization("The flag -XX:+UseG1GC can not be combined with -XX:ParallelGCThreads=0", NULL);
}
#if INCLUDE_ALL_GCS
if (G1ConcRefinementThreads == 0) {
FLAG_SET_DEFAULT(G1ConcRefinementThreads, ParallelGCThreads);
}
#endif
if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
FLAG_SET_DEFAULT(MarkStackSizeMax, 128 * TASKQUEUE_SIZE);
}
if (FLAG_IS_DEFAULT(GCTimeRatio) || GCTimeRatio == 0) {
FLAG_SET_DEFAULT(GCTimeRatio, 9);
}
if (PrintGCDetails && Verbose) {
tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk",
(unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K));
tty->print_cr("ConcGCThreads: %u", (uint) ConcGCThreads);
}
}
#if !INCLUDE_ALL_GCS
#ifdef ASSERT
static bool verify_serial_gc_flags() {
return (UseSerialGC &&
!(UseParNewGC || (UseConcMarkSweepGC || CMSIncrementalMode) || UseG1GC ||
UseParallelGC || UseParallelOldGC));
}
#endif // ASSERT
#endif // INCLUDE_ALL_GCS
void Arguments::set_gc_specific_flags() {
#if INCLUDE_ALL_GCS
if (UseParallelGC || UseParallelOldGC) {
set_parallel_gc_flags();
} else if (UseConcMarkSweepGC) { // Should be done before ParNew check below
set_cms_and_parnew_gc_flags();
} else if (UseParNewGC) { // Skipped if CMS is set above
set_parnew_gc_flags();
} else if (UseG1GC) {
set_g1_gc_flags();
}
check_deprecated_gcs();
check_deprecated_gc_flags();
if (AssumeMP && !UseSerialGC) {
if (FLAG_IS_DEFAULT(ParallelGCThreads) && ParallelGCThreads == 1) {
warning("If the number of processors is expected to increase from one, then"
" you should configure the number of parallel GC threads appropriately"
" using -XX:ParallelGCThreads=N");
}
}
if (MinHeapFreeRatio == 100) {
FLAG_SET_ERGO(uintx, MinHeapFreeRatio, 99);
}
if (!ClassUnloading) {
FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false);
FLAG_SET_CMDLINE(bool, ClassUnloadingWithConcurrentMark, false);
FLAG_SET_CMDLINE(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false);
}
#else // INCLUDE_ALL_GCS
assert(verify_serial_gc_flags(), "SerialGC unset");
#endif // INCLUDE_ALL_GCS
}
julong Arguments::limit_by_allocatable_memory(julong limit) {
julong max_allocatable;
julong result = limit;
if (os::has_allocatable_memory_limit(&max_allocatable)) {
result = MIN2(result, max_allocatable / MaxVirtMemFraction);
}
return result;
}
void Arguments::set_heap_size() {
if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) {
FLAG_SET_CMDLINE(uintx, MaxRAMFraction, DefaultMaxRAMFraction);
}
julong phys_mem =
FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
: (julong)MaxRAM;
if (UseCGroupMemoryLimitForHeap) {
const char* lim_file = "/sys/fs/cgroup/memory/memory.limit_in_bytes";
FILE *fp = fopen(lim_file, "r");
if (fp != NULL) {
julong cgroup_max = 0;
int ret = fscanf(fp, JULONG_FORMAT, &cgroup_max);
if (ret == 1 && cgroup_max > 0) {
if (PrintGCDetails && Verbose) {
tty->print_cr("Setting phys_mem to the min of cgroup limit ("
JULONG_FORMAT "MB) and initial phys_mem ("
JULONG_FORMAT "MB)", cgroup_max/M, phys_mem/M);
}
phys_mem = MIN2(cgroup_max, phys_mem);
} else {
warning("Unable to read/parse cgroup memory limit from %s: %s",
lim_file, errno != 0 ? strerror(errno) : "unknown error");
}
fclose(fp);
} else {
warning("Unable to open cgroup memory limit file %s (%s)", lim_file, strerror(errno));
}
}
if (FLAG_IS_DEFAULT(MaxRAMPercentage) &&
!FLAG_IS_DEFAULT(MaxRAMFraction))
MaxRAMPercentage = 100.0 / MaxRAMFraction;
if (FLAG_IS_DEFAULT(MinRAMPercentage) &&
!FLAG_IS_DEFAULT(MinRAMFraction))
MinRAMPercentage = 100.0 / MinRAMFraction;
if (FLAG_IS_DEFAULT(InitialRAMPercentage) &&
!FLAG_IS_DEFAULT(InitialRAMFraction))
InitialRAMPercentage = 100.0 / InitialRAMFraction;
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
const julong reasonable_min = (julong)((phys_mem * MinRAMPercentage) / 100);
if (reasonable_min < MaxHeapSize) {
reasonable_max = reasonable_min;
} else {
reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize);
}
if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) {
reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit);
}
if (UseCompressedOops) {
julong max_coop_heap = (julong)max_heap_for_compressed_oops();
if (HeapBaseMinAddress + MaxHeapSize < max_coop_heap) {
max_coop_heap -= HeapBaseMinAddress;
}
reasonable_max = MIN2(reasonable_max, max_coop_heap);
}
reasonable_max = limit_by_allocatable_memory(reasonable_max);
if (!FLAG_IS_DEFAULT(InitialHeapSize)) {
reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize);
}
if (PrintGCDetails && Verbose) {
tty->print_cr(" Maximum heap size " SIZE_FORMAT, (size_t) reasonable_max);
}
FLAG_SET_ERGO(uintx, MaxHeapSize, (uintx)reasonable_max);
}
if (InitialHeapSize == 0 || min_heap_size() == 0) {
julong reasonable_minimum = (julong)(OldSize + NewSize);
reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize);
reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum);
if (InitialHeapSize == 0) {
julong reasonable_initial = (julong)((phys_mem * InitialRAMPercentage) / 100);
reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)min_heap_size());
reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
reasonable_initial = limit_by_allocatable_memory(reasonable_initial);
if (PrintGCDetails && Verbose) {
tty->print_cr(" Initial heap size " SIZE_FORMAT, (uintx)reasonable_initial);
}
FLAG_SET_ERGO(uintx, InitialHeapSize, (uintx)reasonable_initial);
}
if (min_heap_size() == 0) {
set_min_heap_size(MIN2((uintx)reasonable_minimum, InitialHeapSize));
if (PrintGCDetails && Verbose) {
tty->print_cr(" Minimum heap size " SIZE_FORMAT, min_heap_size());
}
}
}
}
jint Arguments::set_aggressive_heap_flags() {
julong initHeapSize;
julong total_memory = os::physical_memory();
if (total_memory < (julong) 256 * M) {
jio_fprintf(defaultStream::error_stream(),
"You need at least 256mb of memory to use -XX:+AggressiveHeap\n");
vm_exit(1);
}
initHeapSize = MIN2(total_memory / (julong) 2,
total_memory - (julong) 160 * M);
initHeapSize = limit_by_allocatable_memory(initHeapSize);
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize);
FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize);
set_min_heap_size(initHeapSize);
}
if (FLAG_IS_DEFAULT(NewSize)) {
FLAG_SET_CMDLINE(uintx, NewSize,
((julong) MaxHeapSize / (julong) 8) * (julong) 3);
FLAG_SET_CMDLINE(uintx, MaxNewSize, NewSize);
}
#ifndef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD.
FLAG_SET_DEFAULT(UseLargePages, true);
#endif
FLAG_SET_CMDLINE(uintx, BaseFootPrintEstimate, MaxHeapSize);
FLAG_SET_CMDLINE(bool, ResizeTLAB, false);
FLAG_SET_CMDLINE(uintx, TLABSize, 256 * K);
FLAG_SET_CMDLINE(uintx, YoungPLABSize, 256 * K); // Note: this is in words
FLAG_SET_CMDLINE(uintx, OldPLABSize, 8 * K); // Note: this is in words
FLAG_SET_CMDLINE(bool, UseParallelGC, true);
FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100);
FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true);
return JNI_OK;
}
void Arguments::set_bytecode_flags() {
if (UseSharedSpaces) {
FLAG_SET_DEFAULT(RewriteBytecodes, false);
FLAG_SET_DEFAULT(RewriteFrequentPairs, false);
}
if (!RewriteBytecodes) {
FLAG_SET_DEFAULT(RewriteFrequentPairs, false);
}
}
void Arguments::set_aggressive_opts_flags() {
#ifdef COMPILER2
if (AggressiveUnboxing) {
if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
FLAG_SET_DEFAULT(EliminateAutoBox, true);
} else if (!EliminateAutoBox) {
AggressiveUnboxing = false;
}
if (FLAG_IS_DEFAULT(DoEscapeAnalysis)) {
FLAG_SET_DEFAULT(DoEscapeAnalysis, true);
} else if (!DoEscapeAnalysis) {
AggressiveUnboxing = false;
}
}
if (AggressiveOpts || !FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
if (FLAG_IS_DEFAULT(EliminateAutoBox)) {
FLAG_SET_DEFAULT(EliminateAutoBox, true);
}
if (FLAG_IS_DEFAULT(AutoBoxCacheMax)) {
FLAG_SET_DEFAULT(AutoBoxCacheMax, 20000);
}
char buffer[1024];
jio_snprintf(buffer, 1024, "java.lang.Integer.IntegerCache.high=" INTX_FORMAT, AutoBoxCacheMax);
add_property(buffer);
}
if (AggressiveOpts && FLAG_IS_DEFAULT(BiasedLockingStartupDelay)) {
FLAG_SET_DEFAULT(BiasedLockingStartupDelay, 500);
}
#endif
if (AggressiveOpts) {
}
}
void Arguments::process_java_compiler_argument(char* arg) {
if (strlen(arg) == 0 || strcasecmp(arg, "NONE") == 0) {
set_java_compiler(true); // "-Djava.compiler[=...]" most recently seen.
}
}
void Arguments::process_java_launcher_argument(const char* launcher, void* extra_info) {
_sun_java_launcher = strdup(launcher);
if (strcmp("gamma", _sun_java_launcher) == 0) {
_created_by_gamma_launcher = true;
}
}
bool Arguments::created_by_java_launcher() {
assert(_sun_java_launcher != NULL, "property must have value");
return strcmp(DEFAULT_JAVA_LAUNCHER, _sun_java_launcher) != 0;
}
bool Arguments::created_by_gamma_launcher() {
return _created_by_gamma_launcher;
}
bool Arguments::verify_interval(uintx val, uintx min,
uintx max, const char* name) {
if (val >= min && val <= max) {
return true;
}
jio_fprintf(defaultStream::error_stream(),
"%s of " UINTX_FORMAT " is invalid; must be between " UINTX_FORMAT
" and " UINTX_FORMAT "\n",
name, val, min, max);
return false;
}
bool Arguments::verify_min_value(intx val, intx min, const char* name) {
if (val >= min ) {
return true;
}
jio_fprintf(defaultStream::error_stream(),
"%s of " INTX_FORMAT " is invalid; must be at least " INTX_FORMAT "\n",
name, val, min);
return false;
}
bool Arguments::verify_percentage(uintx value, const char* name) {
if (is_percentage(value)) {
return true;
}
jio_fprintf(defaultStream::error_stream(),
"%s of " UINTX_FORMAT " is invalid; must be between 0 and 100\n",
name, value);
return false;
}
void check_gclog_consistency() {
if (UseGCLogFileRotation) {
if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) {
jio_fprintf(defaultStream::output_stream(),
"To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files>\n"
"where num_of_file > 0\n"
"GC log rotation is turned off\n");
UseGCLogFileRotation = false;
}
}
if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) {
FLAG_SET_CMDLINE(uintx, GCLogFileSize, 8*K);
jio_fprintf(defaultStream::output_stream(),
"GCLogFileSize changed to minimum 8K\n");
}
}
bool is_filename_valid(const char *file_name) {
const char* p = file_name;
char file_sep = os::file_separator()[0];
const char* cp;
for (cp = file_name; *cp != '\0'; cp++) {
if (*cp == '/' || *cp == file_sep) {
p = cp + 1;
}
}
int count_p = 0;
int count_t = 0;
while (*p != '\0') {
if ((*p >= '0' && *p <= '9') ||
(*p >= 'A' && *p <= 'Z') ||
(*p >= 'a' && *p <= 'z') ||
p++;
continue;
}
if (*p == '%') {
if(*(p + 1) == 'p') {
p += 2;
count_p ++;
continue;
}
if (*(p + 1) == 't') {
p += 2;
count_t ++;
continue;
}
}
return false;
}
return count_p < 2 && count_t < 2;
}
bool Arguments::verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio) {
if (!is_percentage(min_heap_free_ratio)) {
err_msg.print("MinHeapFreeRatio must have a value between 0 and 100");
return false;
}
if (min_heap_free_ratio > MaxHeapFreeRatio) {
err_msg.print("MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or "
"equal to MaxHeapFreeRatio (" UINTX_FORMAT ")", min_heap_free_ratio,
MaxHeapFreeRatio);
return false;
}
_min_heap_free_ratio = min_heap_free_ratio;
return true;
}
bool Arguments::verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio) {
if (!is_percentage(max_heap_free_ratio)) {
err_msg.print("MaxHeapFreeRatio must have a value between 0 and 100");
return false;
}
if (max_heap_free_ratio < MinHeapFreeRatio) {
err_msg.print("MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or "
"equal to MinHeapFreeRatio (" UINTX_FORMAT ")", max_heap_free_ratio,
MinHeapFreeRatio);
return false;
}
_max_heap_free_ratio = max_heap_free_ratio;
return true;
}
bool Arguments::check_gc_consistency() {
check_gclog_consistency();
bool status = true;
uint i = 0;
if (UseSerialGC) i++;
if (UseConcMarkSweepGC || UseParNewGC) i++;
if (UseParallelGC || UseParallelOldGC) i++;
if (UseG1GC) i++;
if (i > 1) {
jio_fprintf(defaultStream::error_stream(),
"Conflicting collector combinations in option list; "
"please refer to the release notes for the combinations "
"allowed\n");
status = false;
}
return status;
}
void Arguments::check_deprecated_gcs() {
if (UseConcMarkSweepGC && !UseParNewGC) {
warning("Using the DefNew young collector with the CMS collector is deprecated "
"and will likely be removed in a future release");
}
if (UseParNewGC && !UseConcMarkSweepGC) {
warning("Using the ParNew young collector with the Serial old collector is deprecated "
"and will likely be removed in a future release");
}
if (CMSIncrementalMode) {
warning("Using incremental CMS is deprecated and will likely be removed in a future release");
}
}
void Arguments::check_deprecated_gc_flags() {
if (FLAG_IS_CMDLINE(MaxGCMinorPauseMillis)) {
warning("Using MaxGCMinorPauseMillis as minor pause goal is deprecated"
"and will likely be removed in future release");
}
if (FLAG_IS_CMDLINE(DefaultMaxRAMFraction)) {
warning("DefaultMaxRAMFraction is deprecated and will likely be removed in a future release. "
"Use MaxRAMFraction instead.");
}
if (FLAG_IS_CMDLINE(UseCMSCompactAtFullCollection)) {
warning("UseCMSCompactAtFullCollection is deprecated and will likely be removed in a future release.");
}
if (FLAG_IS_CMDLINE(CMSFullGCsBeforeCompaction)) {
warning("CMSFullGCsBeforeCompaction is deprecated and will likely be removed in a future release.");
}
if (FLAG_IS_CMDLINE(UseCMSCollectionPassing)) {
warning("UseCMSCollectionPassing is deprecated and will likely be removed in a future release.");
}
}
bool Arguments::check_stack_pages()
{
bool status = true;
status = status && verify_min_value(StackYellowPages, 1, "StackYellowPages");
status = status && verify_min_value(StackRedPages, 1, "StackRedPages");
status = status && verify_interval(StackShadowPages, 1, 50, "StackShadowPages");
return status;
}
bool Arguments::check_vm_args_consistency() {
bool status = true;
#if (defined(PRODUCT) && defined(SOLARIS))
if (!UseBoundThreads && !UseStackBanging) {
jio_fprintf(defaultStream::error_stream(),
"-UseStackBanging conflicts with -UseBoundThreads\n");
status = false;
}
#endif
if (TLABRefillWasteFraction == 0) {
jio_fprintf(defaultStream::error_stream(),
"TLABRefillWasteFraction should be a denominator, "
"not " SIZE_FORMAT "\n",
TLABRefillWasteFraction);
status = false;
}
status = status && verify_interval(AdaptiveSizePolicyWeight, 0, 100,
"AdaptiveSizePolicyWeight");
status = status && verify_percentage(ThresholdTolerance, "ThresholdTolerance");
status = status && verify_interval(StringTableSize, minimumStringTableSize,
(max_uintx / StringTable::bucket_size()), "StringTable size");
status = status && verify_interval(SymbolTableSize, minimumSymbolTableSize,
(max_uintx / SymbolTable::bucket_size()), "SymbolTable size");
{
FormatBuffer<80> err_msg("%s","");
if (!verify_MinHeapFreeRatio(err_msg, MinHeapFreeRatio)) {
jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer());
status = false;
} else if (!verify_MaxHeapFreeRatio(err_msg, MaxHeapFreeRatio)) {
jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer());
status = false;
}
}
status = status && verify_percentage(MinMetaspaceFreeRatio, "MinMetaspaceFreeRatio");
status = status && verify_percentage(MaxMetaspaceFreeRatio, "MaxMetaspaceFreeRatio");
if (MinMetaspaceFreeRatio > MaxMetaspaceFreeRatio) {
jio_fprintf(defaultStream::error_stream(),
"MinMetaspaceFreeRatio (%s" UINTX_FORMAT ") must be less than or "
"equal to MaxMetaspaceFreeRatio (%s" UINTX_FORMAT ")\n",
FLAG_IS_DEFAULT(MinMetaspaceFreeRatio) ? "Default: " : "",
MinMetaspaceFreeRatio,
FLAG_IS_DEFAULT(MaxMetaspaceFreeRatio) ? "Default: " : "",
MaxMetaspaceFreeRatio);
status = false;
}
MinMetaspaceFreeRatio = MIN2(MinMetaspaceFreeRatio, (uintx) 99);
if (FullGCALot && FLAG_IS_DEFAULT(MarkSweepAlwaysCompactCount)) {
MarkSweepAlwaysCompactCount = 1; // Move objects every gc.
}
if (UseParallelOldGC && ParallelOldGCSplitALot) {
if (!FLAG_IS_CMDLINE(NewRatio)) {
FLAG_SET_CMDLINE(uintx, NewRatio, 2);
}
if (!FLAG_IS_CMDLINE(ScavengeBeforeFullGC)) {
FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
}
}
status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit");
status = status && verify_percentage(GCTimeLimit, "GCTimeLimit");
if (GCTimeLimit == 100) {
FLAG_SET_DEFAULT(UseGCOverheadLimit, false);
}
status = status && check_gc_consistency();
status = status && check_stack_pages();
if (CMSIncrementalMode) {
if (!UseConcMarkSweepGC) {
jio_fprintf(defaultStream::error_stream(),
"error: invalid argument combination.\n"
"The CMS collector (-XX:+UseConcMarkSweepGC) must be "
"selected in order\nto use CMSIncrementalMode.\n");
status = false;
} else {
status = status && verify_percentage(CMSIncrementalDutyCycle,
"CMSIncrementalDutyCycle");
status = status && verify_percentage(CMSIncrementalDutyCycleMin,
"CMSIncrementalDutyCycleMin");
status = status && verify_percentage(CMSIncrementalSafetyFactor,
"CMSIncrementalSafetyFactor");
status = status && verify_percentage(CMSIncrementalOffset,
"CMSIncrementalOffset");
status = status && verify_percentage(CMSExpAvgFactor,
"CMSExpAvgFactor");
if (CMSInitiatingOccupancyFraction < 0) {
FLAG_SET_DEFAULT(CMSInitiatingOccupancyFraction, 1);
}
}
}
if (UseConcMarkSweepGC && FLSVerifyAllHeapReferences) {
if (VerifyDuringStartup) {
warning("Heap verification at start-up disabled "
"(due to current incompatibility with FLSVerifyAllHeapReferences)");
VerifyDuringStartup = false; // Disable verification at start-up
}
if (VerifyBeforeExit) {
warning("Heap verification at shutdown disabled "
"(due to current incompatibility with FLSVerifyAllHeapReferences)");
VerifyBeforeExit = false; // Disable verification at shutdown
}
}
if (!UseAsyncConcMarkSweepGC &&
(ExplicitGCInvokesConcurrent ||
ExplicitGCInvokesConcurrentAndUnloadsClasses)) {
jio_fprintf(defaultStream::error_stream(),
"error: +ExplicitGCInvokesConcurrent[AndUnloadsClasses] conflicts"
" with -UseAsyncConcMarkSweepGC");
status = false;
}
status = status && verify_min_value(ParGCArrayScanChunk, 1, "ParGCArrayScanChunk");
#if INCLUDE_ALL_GCS
if (UseG1GC) {
status = status && verify_percentage(G1NewSizePercent, "G1NewSizePercent");
status = status && verify_percentage(G1MaxNewSizePercent, "G1MaxNewSizePercent");
status = status && verify_interval(G1NewSizePercent, 0, G1MaxNewSizePercent, "G1NewSizePercent");
status = status && verify_percentage(InitiatingHeapOccupancyPercent,
"InitiatingHeapOccupancyPercent");
status = status && verify_min_value(G1RefProcDrainInterval, 1,
"G1RefProcDrainInterval");
status = status && verify_min_value((intx)G1ConcMarkStepDurationMillis, 1,
"G1ConcMarkStepDurationMillis");
status = status && verify_interval(G1ConcRSHotCardLimit, 0, max_jubyte,
"G1ConcRSHotCardLimit");
status = status && verify_interval(G1ConcRSLogCacheSize, 0, 27,
"G1ConcRSLogCacheSize");
status = status && verify_interval(StringDeduplicationAgeThreshold, 1, markOopDesc::max_age,
"StringDeduplicationAgeThreshold");
}
if (UseConcMarkSweepGC) {
status = status && verify_min_value(CMSOldPLABNumRefills, 1, "CMSOldPLABNumRefills");
status = status && verify_min_value(CMSOldPLABToleranceFactor, 1, "CMSOldPLABToleranceFactor");
status = status && verify_min_value(CMSOldPLABMax, 1, "CMSOldPLABMax");
status = status && verify_interval(CMSOldPLABMin, 1, CMSOldPLABMax, "CMSOldPLABMin");
status = status && verify_min_value(CMSYoungGenPerWorker, 1, "CMSYoungGenPerWorker");
status = status && verify_min_value(CMSSamplingGrain, 1, "CMSSamplingGrain");
status = status && verify_interval(CMS_SweepWeight, 0, 100, "CMS_SweepWeight");
status = status && verify_interval(CMS_FLSWeight, 0, 100, "CMS_FLSWeight");
status = status && verify_interval(FLSCoalescePolicy, 0, 4, "FLSCoalescePolicy");
status = status && verify_min_value(CMSRescanMultiple, 1, "CMSRescanMultiple");
status = status && verify_min_value(CMSConcMarkMultiple, 1, "CMSConcMarkMultiple");
status = status && verify_interval(CMSPrecleanIter, 0, 9, "CMSPrecleanIter");
status = status && verify_min_value(CMSPrecleanDenominator, 1, "CMSPrecleanDenominator");
status = status && verify_interval(CMSPrecleanNumerator, 0, CMSPrecleanDenominator - 1, "CMSPrecleanNumerator");
status = status && verify_percentage(CMSBootstrapOccupancy, "CMSBootstrapOccupancy");
status = status && verify_min_value(CMSPrecleanThreshold, 100, "CMSPrecleanThreshold");
status = status && verify_percentage(CMSScheduleRemarkEdenPenetration, "CMSScheduleRemarkEdenPenetration");
status = status && verify_min_value(CMSScheduleRemarkSamplingRatio, 1, "CMSScheduleRemarkSamplingRatio");
status = status && verify_min_value(CMSBitMapYieldQuantum, 1, "CMSBitMapYieldQuantum");
status = status && verify_percentage(CMSTriggerRatio, "CMSTriggerRatio");
status = status && verify_percentage(CMSIsTooFullPercentage, "CMSIsTooFullPercentage");
}
if (UseParallelGC || UseParallelOldGC) {
status = status && verify_interval(ParallelOldDeadWoodLimiterMean, 0, 100, "ParallelOldDeadWoodLimiterMean");
status = status && verify_interval(ParallelOldDeadWoodLimiterStdDev, 0, 100, "ParallelOldDeadWoodLimiterStdDev");
status = status && verify_percentage(YoungGenerationSizeIncrement, "YoungGenerationSizeIncrement");
status = status && verify_percentage(TenuredGenerationSizeIncrement, "TenuredGenerationSizeIncrement");
status = status && verify_min_value(YoungGenerationSizeSupplementDecay, 1, "YoungGenerationSizeSupplementDecay");
status = status && verify_min_value(TenuredGenerationSizeSupplementDecay, 1, "TenuredGenerationSizeSupplementDecay");
status = status && verify_min_value(ParGCCardsPerStrideChunk, 1, "ParGCCardsPerStrideChunk");
status = status && verify_min_value(ParallelOldGCSplitInterval, 0, "ParallelOldGCSplitInterval");
}
#endif // INCLUDE_ALL_GCS
status = status && verify_interval(RefDiscoveryPolicy,
ReferenceProcessor::DiscoveryPolicyMin,
ReferenceProcessor::DiscoveryPolicyMax,
"RefDiscoveryPolicy");
status = status && verify_interval(TLABWasteTargetPercent,
1, 100, "TLABWasteTargetPercent");
status = status && verify_object_alignment();
status = status && verify_interval(CompressedClassSpaceSize, 1*M, 3*G,
"CompressedClassSpaceSize");
status = status && verify_interval(MarkStackSizeMax,
1, (max_jint - 1), "MarkStackSizeMax");
status = status && verify_interval(NUMAChunkResizeWeight, 0, 100, "NUMAChunkResizeWeight");
status = status && verify_min_value(LogEventsBufferEntries, 1, "LogEventsBufferEntries");
status = status && verify_min_value(HeapSizePerGCThread, (uintx) os::vm_page_size(), "HeapSizePerGCThread");
status = status && verify_min_value(GCTaskTimeStampEntries, 1, "GCTaskTimeStampEntries");
status = status && verify_percentage(ParallelGCBufferWastePct, "ParallelGCBufferWastePct");
status = status && verify_interval(TargetPLABWastePct, 1, 100, "TargetPLABWastePct");
status = status && verify_min_value(ParGCStridesPerThread, 1, "ParGCStridesPerThread");
status = status && verify_min_value(MinRAMFraction, 1, "MinRAMFraction");
status = status && verify_min_value(InitialRAMFraction, 1, "InitialRAMFraction");
status = status && verify_min_value(MaxRAMFraction, 1, "MaxRAMFraction");
status = status && verify_min_value(DefaultMaxRAMFraction, 1, "DefaultMaxRAMFraction");
status = status && verify_interval(AdaptiveTimeWeight, 0, 100, "AdaptiveTimeWeight");
status = status && verify_min_value(AdaptiveSizeDecrementScaleFactor, 1, "AdaptiveSizeDecrementScaleFactor");
status = status && verify_interval(TLABAllocationWeight, 0, 100, "TLABAllocationWeight");
status = status && verify_min_value(MinTLABSize, 1, "MinTLABSize");
status = status && verify_min_value(TLABRefillWasteFraction, 1, "TLABRefillWasteFraction");
status = status && verify_percentage(YoungGenerationSizeSupplement, "YoungGenerationSizeSupplement");
status = status && verify_percentage(TenuredGenerationSizeSupplement, "TenuredGenerationSizeSupplement");
status = status && verify_interval(MaxTenuringThreshold, 0, 15, "MaxTenuringThreshold");
status = status && verify_interval(InitialTenuringThreshold, 0, MaxTenuringThreshold, "MaxTenuringThreshold");
status = status && verify_percentage(TargetSurvivorRatio, "TargetSurvivorRatio");
status = status && verify_percentage(MarkSweepDeadRatio, "MarkSweepDeadRatio");
status = status && verify_min_value(MarkSweepAlwaysCompactCount, 1, "MarkSweepAlwaysCompactCount");
#ifdef COMPILER1
status = status && verify_min_value(ValueMapInitialSize, 1, "ValueMapInitialSize");
#endif
if (PrintNMTStatistics) {
#if INCLUDE_NMT
if (MemTracker::tracking_level() == NMT_off) {
#endif // INCLUDE_NMT
warning("PrintNMTStatistics is disabled, because native memory tracking is not enabled");
PrintNMTStatistics = false;
#if INCLUDE_NMT
}
#endif
}
if (ContendedPaddingWidth < 0 || ContendedPaddingWidth > 8192) {
jio_fprintf(defaultStream::error_stream(),
"ContendedPaddingWidth=" INTX_FORMAT " must be in between %d and %d\n",
ContendedPaddingWidth, 0, 8192);
status = false;
}
if ((ContendedPaddingWidth % BytesPerLong) != 0) {
jio_fprintf(defaultStream::error_stream(),
"ContendedPaddingWidth=" INTX_FORMAT " must be a multiple of %d\n",
ContendedPaddingWidth, BytesPerLong);
status = false;
}
uint min_code_cache_size = (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3)) + CodeCacheMinimumFreeSpace;
if (InitialCodeCacheSize < (uintx)os::vm_page_size()) {
jio_fprintf(defaultStream::error_stream(),
"Invalid InitialCodeCacheSize=%dK. Must be at least %dK.\n", InitialCodeCacheSize/K,
os::vm_page_size()/K);
status = false;
} else if (ReservedCodeCacheSize < InitialCodeCacheSize) {
jio_fprintf(defaultStream::error_stream(),
"Invalid ReservedCodeCacheSize: %dK. Must be at least InitialCodeCacheSize=%dK.\n",
ReservedCodeCacheSize/K, InitialCodeCacheSize/K);
status = false;
} else if (ReservedCodeCacheSize < min_code_cache_size) {
jio_fprintf(defaultStream::error_stream(),
"Invalid ReservedCodeCacheSize=%dK. Must be at least %uK.\n", ReservedCodeCacheSize/K,
min_code_cache_size/K);
status = false;
} else if (ReservedCodeCacheSize > 2*G) {
jio_fprintf(defaultStream::error_stream(),
"Invalid ReservedCodeCacheSize=%dM. Must be at most %uM.\n", ReservedCodeCacheSize/M,
(2*G)/M);
status = false;
}
status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction");
status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity");
if (!FLAG_IS_DEFAULT(CICompilerCount) && !FLAG_IS_DEFAULT(CICompilerCountPerCPU) && CICompilerCountPerCPU) {
warning("The VM option CICompilerCountPerCPU overrides CICompilerCount.");
}
#ifdef COMPILER1
status &= verify_interval(SafepointPollOffset, 0, os::vm_page_size() - BytesPerWord, "SafepointPollOffset");
#endif
int min_number_of_compiler_threads = get_min_number_of_compiler_threads();
assert(min_number_of_compiler_threads <= CI_COMPILER_COUNT, "minimum should be less or equal default number");
status &=verify_min_value(CICompilerCount, min_number_of_compiler_threads, "CICompilerCount");
return status;
}
bool Arguments::is_bad_option(const JavaVMOption* option, jboolean ignore,
const char* option_type) {
if (ignore) return false;
const char* spacer = " ";
if (option_type == NULL) {
option_type = ++spacer; // Set both to the empty string.
}
if (os::obsolete_option(option)) {
jio_fprintf(defaultStream::error_stream(),
"Obsolete %s%soption: %s\n", option_type, spacer,
option->optionString);
return false;
} else {
jio_fprintf(defaultStream::error_stream(),
"Unrecognized %s%soption: %s\n", option_type, spacer,
option->optionString);
return true;
}
}
static const char* user_assertion_options[] = {
"-da", "-ea", "-disableassertions", "-enableassertions", 0
};
static const char* system_assertion_options[] = {
"-dsa", "-esa", "-disablesystemassertions", "-enablesystemassertions", 0
};
static bool match_option(const JavaVMOption* option, const char** names, const char** tail,
bool tail_allowed) {
for (/* empty */; *names != NULL; ++names) {
if (match_option(option, *names, tail)) {
if (**tail == '\0' || tail_allowed && **tail == ':') {
return true;
}
}
}
return false;
}
bool Arguments::parse_uintx(const char* value,
uintx* uintx_arg,
uintx min_size) {
bool value_is_positive = !(*value == '-');
if (value_is_positive) {
julong n;
bool good_return = atomull(value, &n);
if (good_return) {
bool above_minimum = n >= min_size;
bool value_is_too_large = n > max_uintx;
if (above_minimum && !value_is_too_large) {
return true;
}
}
}
return false;
}
Arguments::ArgsRange Arguments::parse_memory_size(const char* s,
julong* long_arg,
julong min_size) {
if (!atomull(s, long_arg)) return arg_unreadable;
return check_memory_size(*long_arg, min_size);
}
jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) {
SysClassPath scp(Arguments::get_sysclasspath());
bool scp_assembly_required = false;
Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods;
Arguments::_UseOnStackReplacement = UseOnStackReplacement;
Arguments::_ClipInlining = ClipInlining;
Arguments::_BackgroundCompilation = BackgroundCompilation;
set_mode_flags(_mixed);
jint result = parse_java_tool_options_environment_variable(&scp, &scp_assembly_required);
if (result != JNI_OK) {
return result;
}
result = parse_each_vm_init_arg(args, &scp, &scp_assembly_required, Flag::COMMAND_LINE);
if (result != JNI_OK) {
return result;
}
result = parse_java_options_environment_variable(&scp, &scp_assembly_required);
if (result != JNI_OK) {
return result;
}
os::init_container_support();
result = finalize_vm_init_args(&scp, scp_assembly_required);
if (result != JNI_OK) {
return result;
}
return JNI_OK;
}
bool valid_hprof_or_jdwp_agent(char *name, bool is_path) {
char *_name;
const char *_hprof = "hprof", *_jdwp = "jdwp";
size_t _len_hprof, _len_jdwp, _len_prefix;
if (is_path) {
if ((_name = strrchr(name, (int) *os::file_separator())) == NULL) {
return false;
}
_name++; // skip past last path separator
_len_prefix = strlen(JNI_LIB_PREFIX);
if (strncmp(_name, JNI_LIB_PREFIX, _len_prefix) != 0) {
return false;
}
_name += _len_prefix;
_len_hprof = strlen(_hprof);
_len_jdwp = strlen(_jdwp);
if (strncmp(_name, _hprof, _len_hprof) == 0) {
_name += _len_hprof;
}
else if (strncmp(_name, _jdwp, _len_jdwp) == 0) {
_name += _len_jdwp;
}
else {
return false;
}
if (strcmp(_name, JNI_LIB_SUFFIX) != 0) {
return false;
}
return true;
}
if (strcmp(name, _hprof) == 0 || strcmp(name, _jdwp) == 0) {
return true;
}
return false;
}
jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
SysClassPath* scp_p,
bool* scp_assembly_required_p,
Flag::Flags origin) {
const char* tail;
for (int index = 0; index < args->nOptions; index++) {
bool is_absolute_path = false; // for -agentpath vs -agentlib
const JavaVMOption* option = args->options + index;
if (!match_option(option, "-Djava.class.path", &tail) &&
!match_option(option, "-Dsun.java.command", &tail) &&
!match_option(option, "-Dsun.java.launcher", &tail)) {
build_jvm_args(option->optionString);
}
if (match_option(option, "-verbose", &tail)) {
if (!strcmp(tail, ":class") || !strcmp(tail, "")) {
FLAG_SET_CMDLINE(bool, TraceClassLoading, true);
FLAG_SET_CMDLINE(bool, TraceClassUnloading, true);
} else if (!strcmp(tail, ":gc")) {
FLAG_SET_CMDLINE(bool, PrintGC, true);
} else if (!strcmp(tail, ":jni")) {
FLAG_SET_CMDLINE(bool, PrintJNIResolving, true);
}
} else if (match_option(option, user_assertion_options, &tail, true)) {
bool enable = option->optionString[1] == 'e'; // char after '-' is 'e'
if (*tail == '\0') {
JavaAssertions::setUserClassDefault(enable);
} else {
assert(*tail == ':', "bogus match by match_option()");
JavaAssertions::addOption(tail + 1, enable);
}
} else if (match_option(option, system_assertion_options, &tail, false)) {
bool enable = option->optionString[1] == 'e'; // char after '-' is 'e'
JavaAssertions::setSystemClassDefault(enable);
} else if (match_option(option, "-Xbootclasspath:", &tail)) {
scp_p->reset_path(tail);
} else if (match_option(option, "-Xbootclasspath/a:", &tail)) {
scp_p->add_suffix(tail);
} else if (match_option(option, "-Xbootclasspath/p:", &tail)) {
scp_p->add_prefix(tail);
} else if (match_option(option, "-Xrun", &tail)) {
if (tail != NULL) {
const char* pos = strchr(tail, ':');
size_t len = (pos == NULL) ? strlen(tail) : pos - tail;
char* name = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len + 1, mtInternal), tail, len);
name[len] = '\0';
char *options = NULL;
if(pos != NULL) {
size_t len2 = strlen(pos+1) + 1; // options start after ':'. Final zero must be copied.
options = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len2, mtInternal), pos+1, len2);
}
#if !INCLUDE_JVMTI
if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) {
jio_fprintf(defaultStream::error_stream(),
"Profiling and debugging agents are not supported in this VM\n");
return JNI_ERR;
}
#endif // !INCLUDE_JVMTI
add_init_library(name, options);
}
} else if (match_option(option, "-agentlib:", &tail) ||
(is_absolute_path = match_option(option, "-agentpath:", &tail))) {
if(tail != NULL) {
const char* pos = strchr(tail, '=');
size_t len = (pos == NULL) ? strlen(tail) : pos - tail;
char* name = strncpy(NEW_C_HEAP_ARRAY(char, len + 1, mtInternal), tail, len);
name[len] = '\0';
char *options = NULL;
if(pos != NULL) {
size_t length = strlen(pos + 1) + 1;
options = NEW_C_HEAP_ARRAY(char, length, mtInternal);
jio_snprintf(options, length, "%s", pos + 1);
}
#if !INCLUDE_JVMTI
if (valid_hprof_or_jdwp_agent(name, is_absolute_path)) {
jio_fprintf(defaultStream::error_stream(),
"Profiling and debugging agents are not supported in this VM\n");
return JNI_ERR;
}
#endif // !INCLUDE_JVMTI
add_init_agent(name, options, is_absolute_path);
}
} else if (match_option(option, "-javaagent:", &tail)) {
#if !INCLUDE_JVMTI
jio_fprintf(defaultStream::error_stream(),
"Instrumentation agents are not supported in this VM\n");
return JNI_ERR;
#else
if(tail != NULL) {
size_t length = strlen(tail) + 1;
char *options = NEW_C_HEAP_ARRAY(char, length, mtInternal);
jio_snprintf(options, length, "%s", tail);
add_init_agent("instrument", options, false);
}
#endif // !INCLUDE_JVMTI
} else if (match_option(option, "-Xnoclassgc", &tail)) {
FLAG_SET_CMDLINE(bool, ClassUnloading, false);
} else if (match_option(option, "-Xincgc", &tail)) {
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true);
FLAG_SET_CMDLINE(bool, CMSIncrementalMode, true);
} else if (match_option(option, "-Xnoincgc", &tail)) {
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false);
FLAG_SET_CMDLINE(bool, CMSIncrementalMode, false);
} else if (match_option(option, "-Xconcgc", &tail)) {
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true);
} else if (match_option(option, "-Xnoconcgc", &tail)) {
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false);
} else if (match_option(option, "-Xbatch", &tail)) {
FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
} else if (match_option(option, "-Xmn", &tail)) {
julong long_initial_young_size = 0;
ArgsRange errcode = parse_memory_size(tail, &long_initial_young_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid initial young generation size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, MaxNewSize, (uintx)long_initial_young_size);
FLAG_SET_CMDLINE(uintx, NewSize, (uintx)long_initial_young_size);
} else if (match_option(option, "-Xms", &tail)) {
julong long_initial_heap_size = 0;
ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 0);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid initial heap size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
set_min_heap_size((uintx)long_initial_heap_size);
FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size);
} else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) {
julong long_max_heap_size = 0;
ArgsRange errcode = parse_memory_size(tail, &long_max_heap_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid maximum heap size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, MaxHeapSize, (uintx)long_max_heap_size);
} else if (match_option(option, "-Xmaxf", &tail)) {
char* err;
int maxf = (int)(strtod(tail, &err) * 100);
if (*err != '\0' || *tail == '\0' || maxf < 0 || maxf > 100) {
jio_fprintf(defaultStream::error_stream(),
"Bad max heap free percentage size: %s\n",
option->optionString);
return JNI_EINVAL;
} else {
FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf);
}
} else if (match_option(option, "-Xminf", &tail)) {
char* err;
int minf = (int)(strtod(tail, &err) * 100);
if (*err != '\0' || *tail == '\0' || minf < 0 || minf > 100) {
jio_fprintf(defaultStream::error_stream(),
"Bad min heap free percentage size: %s\n",
option->optionString);
return JNI_EINVAL;
} else {
FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf);
}
} else if (match_option(option, "-Xss", &tail)) {
julong long_ThreadStackSize = 0;
ArgsRange errcode = parse_memory_size(tail, &long_ThreadStackSize, 1000);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid thread stack size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(intx, ThreadStackSize,
round_to((int)long_ThreadStackSize, K) / K);
} else if (match_option(option, "-Xoss", &tail)) {
} else if (match_option(option, "-XX:CodeCacheExpansionSize=", &tail)) {
julong long_CodeCacheExpansionSize = 0;
ArgsRange errcode = parse_memory_size(tail, &long_CodeCacheExpansionSize, os::vm_page_size());
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid argument: %s. Must be at least %luK.\n", option->optionString,
os::vm_page_size()/K);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, CodeCacheExpansionSize, (uintx)long_CodeCacheExpansionSize);
} else if (match_option(option, "-Xmaxjitcodesize", &tail) ||
match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) {
julong long_ReservedCodeCacheSize = 0;
ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid maximum code cache size: %s.\n", option->optionString);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize);
} else if (match_option(option, "-XX:IncreaseFirstTierCompileThresholdAt=", &tail)) {
uintx uint_IncreaseFirstTierCompileThresholdAt = 0;
if (!parse_uintx(tail, &uint_IncreaseFirstTierCompileThresholdAt, 0) || uint_IncreaseFirstTierCompileThresholdAt > 99) {
jio_fprintf(defaultStream::error_stream(),
"Invalid value for IncreaseFirstTierCompileThresholdAt: %s. Should be between 0 and 99.\n",
option->optionString);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, IncreaseFirstTierCompileThresholdAt, (uintx)uint_IncreaseFirstTierCompileThresholdAt);
} else if (match_option(option, "-green", &tail)) {
jio_fprintf(defaultStream::error_stream(),
"Green threads support not available\n");
return JNI_EINVAL;
} else if (match_option(option, "-native", &tail)) {
} else if (match_option(option, "-Xsqnopause", &tail)) {
} else if (match_option(option, "-Xrs", &tail)) {
FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true);
} else if (match_option(option, "-Xusealtsigs", &tail)) {
FLAG_SET_CMDLINE(bool, UseAltSigs, true);
} else if (match_option(option, "-Xoptimize", &tail)) {
} else if (match_option(option, "-Xprof", &tail)) {
#if INCLUDE_FPROF
_has_profile = true;
#else // INCLUDE_FPROF
jio_fprintf(defaultStream::error_stream(),
"Flat profiling is not supported in this VM.\n");
return JNI_ERR;
#endif // INCLUDE_FPROF
} else if (match_option(option, "-Xconcurrentio", &tail)) {
FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true);
FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
FLAG_SET_CMDLINE(intx, DeferThrSuspendLoopCount, 1);
FLAG_SET_CMDLINE(bool, UseTLAB, false);
FLAG_SET_CMDLINE(uintx, NewSizeThreadIncrease, 16 * K); // 20Kb per thread added to new generation
} else if (match_option(option, "-Xinternalversion", &tail)) {
jio_fprintf(defaultStream::output_stream(), "%s\n",
VM_Version::internal_vm_info_string());
vm_exit(0);
#ifndef PRODUCT
} else if (match_option(option, "-Xprintflags", &tail)) {
CommandLineFlags::printFlags(tty, false);
vm_exit(0);
#endif
} else if (match_option(option, "-D", &tail)) {
if (CheckEndorsedAndExtDirs) {
if (match_option(option, "-Djava.endorsed.dirs=", &tail)) {
jio_fprintf(defaultStream::output_stream(),
"-Djava.endorsed.dirs will not be supported in a future release.\n"
"Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n");
return JNI_EINVAL;
}
if (match_option(option, "-Djava.ext.dirs=", &tail)) {
jio_fprintf(defaultStream::output_stream(),
"-Djava.ext.dirs will not be supported in a future release.\n"
"Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n");
return JNI_EINVAL;
}
}
if (!add_property(tail)) {
return JNI_ENOMEM;
}
if (match_option(option, "-Dcom.sun.management", &tail)) {
#if INCLUDE_MANAGEMENT
FLAG_SET_CMDLINE(bool, ManagementServer, true);
#else
jio_fprintf(defaultStream::output_stream(),
"-Dcom.sun.management is not supported in this VM.\n");
return JNI_ERR;
#endif
}
} else if (match_option(option, "-Xint", &tail)) {
set_mode_flags(_int);
} else if (match_option(option, "-Xmixed", &tail)) {
set_mode_flags(_mixed);
} else if (match_option(option, "-Xcomp", &tail)) {
set_mode_flags(_comp);
} else if (match_option(option, "-Xshare:dump", &tail)) {
FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true);
set_mode_flags(_int); // Prevent compilation, which creates objects
} else if (match_option(option, "-Xshare:on", &tail)) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true);
} else if (match_option(option, "-Xshare:auto", &tail)) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false);
} else if (match_option(option, "-Xshare:off", &tail)) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, false);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false);
} else if (match_option(option, "-Xverify", &tail)) {
if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) {
FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true);
FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true);
} else if (strcmp(tail, ":remote") == 0) {
FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false);
FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true);
} else if (strcmp(tail, ":none") == 0) {
FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false);
FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false);
} else if (is_bad_option(option, args->ignoreUnrecognized, "verification")) {
return JNI_EINVAL;
}
} else if (match_option(option, "-Xdebug", &tail)) {
set_xdebug_mode(true);
} else if (match_option(option, "-Xnoagent", &tail)) {
} else if (match_option(option, "-Xboundthreads", &tail)) {
FLAG_SET_CMDLINE(bool, UseBoundThreads, true);
} else if (match_option(option, "-Xloggc:", &tail)) {
_gc_log_filename = strdup(tail);
if (!is_filename_valid(_gc_log_filename)) {
jio_fprintf(defaultStream::output_stream(),
"Invalid file name for use with -Xloggc: Filename can only contain the "
"characters [A-Z][a-z][0-9]-_.%%[p|t] but it has been %s\n"
"Note %%p or %%t can only be used once\n", _gc_log_filename);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(bool, PrintGC, true);
FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true);
} else if (match_option(option, "-Xcheck", &tail)) {
if (!strcmp(tail, ":jni")) {
#if !INCLUDE_JNI_CHECK
warning("JNI CHECKING is not supported in this VM");
#else
CheckJNICalls = true;
#endif // INCLUDE_JNI_CHECK
} else if (is_bad_option(option, args->ignoreUnrecognized,
"check")) {
return JNI_EINVAL;
}
} else if (match_option(option, "vfprintf", &tail)) {
_vfprintf_hook = CAST_TO_FN_PTR(vfprintf_hook_t, option->extraInfo);
} else if (match_option(option, "exit", &tail)) {
_exit_hook = CAST_TO_FN_PTR(exit_hook_t, option->extraInfo);
} else if (match_option(option, "abort", &tail)) {
_abort_hook = CAST_TO_FN_PTR(abort_hook_t, option->extraInfo);
} else if (match_option(option, "-XX:+NeverTenure", &tail)) {
FLAG_SET_CMDLINE(bool, AlwaysTenure, false);
FLAG_SET_CMDLINE(bool, NeverTenure, true);
} else if (match_option(option, "-XX:+AlwaysTenure", &tail)) {
FLAG_SET_CMDLINE(bool, NeverTenure, false);
FLAG_SET_CMDLINE(bool, AlwaysTenure, true);
} else if (match_option(option, "-XX:+CMSPermGenSweepingEnabled", &tail) ||
match_option(option, "-XX:-CMSPermGenSweepingEnabled", &tail)) {
jio_fprintf(defaultStream::error_stream(),
"Please use CMSClassUnloadingEnabled in place of "
"CMSPermGenSweepingEnabled in the future\n");
} else if (match_option(option, "-XX:+UseGCTimeLimit", &tail)) {
FLAG_SET_CMDLINE(bool, UseGCOverheadLimit, true);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:+UseGCOverheadLimit in place of "
"-XX:+UseGCTimeLimit in the future\n");
} else if (match_option(option, "-XX:-UseGCTimeLimit", &tail)) {
FLAG_SET_CMDLINE(bool, UseGCOverheadLimit, false);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:-UseGCOverheadLimit in place of "
"-XX:-UseGCTimeLimit in the future\n");
} else if (match_option(option, "-XX:MaxTLERatio=", &tail)) {
} else if (match_option(option, "-XX:+ResizeTLE", &tail)) {
FLAG_SET_CMDLINE(bool, ResizeTLAB, true);
} else if (match_option(option, "-XX:-ResizeTLE", &tail)) {
FLAG_SET_CMDLINE(bool, ResizeTLAB, false);
} else if (match_option(option, "-XX:+PrintTLE", &tail)) {
FLAG_SET_CMDLINE(bool, PrintTLAB, true);
} else if (match_option(option, "-XX:-PrintTLE", &tail)) {
FLAG_SET_CMDLINE(bool, PrintTLAB, false);
} else if (match_option(option, "-XX:TLEFragmentationRatio=", &tail)) {
} else if (match_option(option, "-XX:TLESize=", &tail)) {
julong long_tlab_size = 0;
ArgsRange errcode = parse_memory_size(tail, &long_tlab_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid TLAB size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, TLABSize, long_tlab_size);
} else if (match_option(option, "-XX:TLEThreadRatio=", &tail)) {
} else if (match_option(option, "-XX:+UseTLE", &tail)) {
FLAG_SET_CMDLINE(bool, UseTLAB, true);
} else if (match_option(option, "-XX:-UseTLE", &tail)) {
FLAG_SET_CMDLINE(bool, UseTLAB, false);
} else if (match_option(option, "-XX:+DisplayVMOutputToStderr", &tail)) {
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false);
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true);
} else if (match_option(option, "-XX:+DisplayVMOutputToStdout", &tail)) {
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false);
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true);
} else if (match_option(option, "-XX:+ErrorFileToStderr", &tail)) {
FLAG_SET_CMDLINE(bool, ErrorFileToStdout, false);
FLAG_SET_CMDLINE(bool, ErrorFileToStderr, true);
} else if (match_option(option, "-XX:+ErrorFileToStdout", &tail)) {
FLAG_SET_CMDLINE(bool, ErrorFileToStderr, false);
FLAG_SET_CMDLINE(bool, ErrorFileToStdout, true);
} else if (match_option(option, "-XX:+ExtendedDTraceProbes", &tail)) {
#if defined(DTRACE_ENABLED)
FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true);
FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true);
FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true);
FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true);
#else // defined(DTRACE_ENABLED)
jio_fprintf(defaultStream::error_stream(),
"ExtendedDTraceProbes flag is not applicable for this configuration\n");
return JNI_EINVAL;
#endif // defined(DTRACE_ENABLED)
#ifdef ASSERT
} else if (match_option(option, "-XX:+FullGCALot", &tail)) {
FLAG_SET_CMDLINE(bool, FullGCALot, true);
FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
#endif
} else if (match_option(option, "-XX:CMSParPromoteBlocksToClaim=", &tail)) {
julong cms_blocks_to_claim = (julong)atol(tail);
FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, cms_blocks_to_claim);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:OldPLABSize in place of "
"-XX:CMSParPromoteBlocksToClaim in the future\n");
} else if (match_option(option, "-XX:ParCMSPromoteBlocksToClaim=", &tail)) {
julong cms_blocks_to_claim = (julong)atol(tail);
FLAG_SET_CMDLINE(uintx, CMSParPromoteBlocksToClaim, cms_blocks_to_claim);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:OldPLABSize in place of "
"-XX:ParCMSPromoteBlocksToClaim in the future\n");
} else if (match_option(option, "-XX:ParallelGCOldGenAllocBufferSize=", &tail)) {
julong old_plab_size = 0;
ArgsRange errcode = parse_memory_size(tail, &old_plab_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid old PLAB size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, OldPLABSize, old_plab_size);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:OldPLABSize in place of "
"-XX:ParallelGCOldGenAllocBufferSize in the future\n");
} else if (match_option(option, "-XX:ParallelGCToSpaceAllocBufferSize=", &tail)) {
julong young_plab_size = 0;
ArgsRange errcode = parse_memory_size(tail, &young_plab_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid young PLAB size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, YoungPLABSize, young_plab_size);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:YoungPLABSize in place of "
"-XX:ParallelGCToSpaceAllocBufferSize in the future\n");
} else if (match_option(option, "-XX:CMSMarkStackSize=", &tail) ||
match_option(option, "-XX:G1MarkStackSize=", &tail)) {
julong stack_size = 0;
ArgsRange errcode = parse_memory_size(tail, &stack_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid mark stack size: %s\n", option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, MarkStackSize, stack_size);
} else if (match_option(option, "-XX:CMSMarkStackSizeMax=", &tail)) {
julong max_stack_size = 0;
ArgsRange errcode = parse_memory_size(tail, &max_stack_size, 1);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid maximum mark stack size: %s\n",
option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, MarkStackSizeMax, max_stack_size);
} else if (match_option(option, "-XX:ParallelMarkingThreads=", &tail) ||
match_option(option, "-XX:ParallelCMSThreads=", &tail)) {
uintx conc_threads = 0;
if (!parse_uintx(tail, &conc_threads, 1)) {
jio_fprintf(defaultStream::error_stream(),
"Invalid concurrent threads: %s\n", option->optionString);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, ConcGCThreads, conc_threads);
} else if (match_option(option, "-XX:MaxDirectMemorySize=", &tail)) {
julong max_direct_memory_size = 0;
ArgsRange errcode = parse_memory_size(tail, &max_direct_memory_size, 0);
if (errcode != arg_in_range) {
jio_fprintf(defaultStream::error_stream(),
"Invalid maximum direct memory size: %s\n",
option->optionString);
describe_range_error(errcode);
return JNI_EINVAL;
}
FLAG_SET_CMDLINE(uintx, MaxDirectMemorySize, max_direct_memory_size);
} else if (match_option(option, "-XX:+UseVMInterruptibleIO", &tail)) {
warning("-XX:+UseVMInterruptibleIO is obsolete and will be removed in a future release.");
FLAG_SET_CMDLINE(bool, UseVMInterruptibleIO, true);
#if !INCLUDE_MANAGEMENT
} else if (match_option(option, "-XX:+ManagementServer", &tail)) {
jio_fprintf(defaultStream::error_stream(),
"ManagementServer is not supported in this VM.\n");
return JNI_ERR;
#endif // INCLUDE_MANAGEMENT
#if INCLUDE_JFR
} else if (match_jfr_option(&option)) {
return JNI_EINVAL;
#endif
} else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
if (strncmp(tail, "Flags=", strlen("Flags=")) != 0) {
if (!process_argument(tail, args->ignoreUnrecognized, origin)) {
return JNI_EINVAL;
}
}
} else if (is_bad_option(option, args->ignoreUnrecognized)) {
return JNI_ERR;
}
}
if (PrintSharedArchiveAndExit) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true);
FLAG_SET_CMDLINE(bool, TraceClassPaths, true);
}
#ifdef LINUX
if (JDK_Version::current().compare_major(6) <= 0 &&
FLAG_IS_DEFAULT(UseLinuxPosixThreadCPUClocks)) {
FLAG_SET_DEFAULT(UseLinuxPosixThreadCPUClocks, false);
}
#endif // LINUX
fix_appclasspath();
return JNI_OK;
}
void Arguments::fix_appclasspath() {
if (IgnoreEmptyClassPaths) {
const char separator = *os::path_separator();
const char* src = _java_class_path->value();
while (*src == separator) {
src ++;
}
char* copy = os::strdup(src, mtInternal);
for (char* tail = copy + strlen(copy) - 1; tail >= copy && *tail == separator; tail--) {
}
char from[3] = {separator, separator, '\0'};
char to [2] = {separator, '\0'};
while (StringUtils::replace_no_expand(copy, from, to) > 0) {
}
_java_class_path->set_value(copy);
FreeHeap(copy); // a copy was made by set_value, so don't need this anymore
}
if (!PrintSharedArchiveAndExit) {
ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value());
}
}
static bool has_jar_files(const char* directory) {
DIR* dir = os::opendir(directory);
if (dir == NULL) return false;
struct dirent *entry;
bool hasJarFile = false;
while (!hasJarFile && (entry = os::readdir(dir)) != NULL) {
const char* name = entry->d_name;
const char* ext = name + strlen(name) - 4;
hasJarFile = ext > name && (os::file_name_strcmp(ext, ".jar") == 0);
}
os::closedir(dir);
return hasJarFile ;
}
static int check_non_empty_dirs(const char* path, const char* type, const char* skip) {
const char separator = *os::path_separator();
const char* const end = path + strlen(path);
int nonEmptyDirs = 0;
while (path < end) {
const char* tmp_end = strchr(path, separator);
if (tmp_end == NULL) {
if ((skip == NULL || strcmp(path, skip) != 0) && has_jar_files(path)) {
nonEmptyDirs++;
jio_fprintf(defaultStream::output_stream(),
"Non-empty %s directory: %s\n", type, path);
}
path = end;
} else {
char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal);
memcpy(dirpath, path, tmp_end - path);
dirpath[tmp_end - path] = '\0';
if ((skip == NULL || strcmp(dirpath, skip) != 0) && has_jar_files(dirpath)) {
nonEmptyDirs++;
jio_fprintf(defaultStream::output_stream(),
"Non-empty %s directory: %s\n", type, dirpath);
}
FREE_C_HEAP_ARRAY(char, dirpath, mtInternal);
path = tmp_end + 1;
}
}
return nonEmptyDirs;
}
static bool check_endorsed_and_ext_dirs() {
if (!CheckEndorsedAndExtDirs)
return true;
char endorsedDir[JVM_MAXPATHLEN];
char extDir[JVM_MAXPATHLEN];
const char* fileSep = os::file_separator();
jio_snprintf(endorsedDir, sizeof(endorsedDir), "%s%slib%sendorsed",
Arguments::get_java_home(), fileSep, fileSep);
jio_snprintf(extDir, sizeof(extDir), "%s%slib%sext",
Arguments::get_java_home(), fileSep, fileSep);
int nonEmptyDirs = check_non_empty_dirs(Arguments::get_endorsed_dir(), "endorsed", NULL);
nonEmptyDirs += check_non_empty_dirs(Arguments::get_ext_dirs(), "extension", extDir);
static const char* jdk_ext_jars[] = {
"access-bridge-32.jar",
"access-bridge-64.jar",
"access-bridge.jar",
"cldrdata.jar",
"dnsns.jar",
"jaccess.jar",
"jfxrt.jar",
"localedata.jar",
"nashorn.jar",
"sunec.jar",
"sunjce_provider.jar",
"sunmscapi.jar",
"sunpkcs11.jar",
"ucrypto.jar",
"zipfs.jar",
NULL
};
DIR* dir = os::opendir(extDir);
if (dir != NULL) {
int num_ext_jars = 0;
struct dirent *entry;
while ((entry = os::readdir(dir)) != NULL) {
const char* name = entry->d_name;
const char* ext = name + strlen(name) - 4;
if (ext > name && (os::file_name_strcmp(ext, ".jar") == 0)) {
bool is_jdk_jar = false;
const char* jarfile = NULL;
for (int i=0; (jarfile = jdk_ext_jars[i]) != NULL; i++) {
if (os::file_name_strcmp(name, jarfile) == 0) {
is_jdk_jar = true;
break;
}
}
if (!is_jdk_jar) {
jio_fprintf(defaultStream::output_stream(),
"%s installed in <JAVA_HOME>/lib/ext\n", name);
num_ext_jars++;
}
}
}
os::closedir(dir);
if (num_ext_jars > 0) {
nonEmptyDirs += 1;
}
}
dir = os::opendir(endorsedDir);
if (dir != NULL) {
jio_fprintf(defaultStream::output_stream(), "<JAVA_HOME>/lib/endorsed exists\n");
os::closedir(dir);
nonEmptyDirs += 1;
}
if (nonEmptyDirs > 0) {
jio_fprintf(defaultStream::output_stream(),
"Endorsed standards override mechanism and extension mechanism "
"will not be supported in a future release.\n"
"Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n");
return false;
}
return true;
}
jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required) {
scp_p->expand_endorsed();
if (scp_assembly_required || scp_p->get_endorsed() != NULL) {
Arguments::set_sysclasspath(scp_p->combined_path());
}
if (!check_endorsed_and_ext_dirs()) {
return JNI_ERR;
}
if (AggressiveHeap) {
jint result = set_aggressive_heap_flags();
if (result != JNI_OK) {
return result;
}
}
if (java_compiler() && !xdebug_mode()) {
set_mode_flags(_int);
}
if (CompileThreshold == 0) {
set_mode_flags(_int);
}
if (FLAG_IS_DEFAULT(InitialTenuringThreshold) && (InitialTenuringThreshold > MaxTenuringThreshold)) {
FLAG_SET_ERGO(uintx, InitialTenuringThreshold, MaxTenuringThreshold);
}
#ifndef COMPILER2
if (FLAG_IS_DEFAULT(UseLargePages) &&
MaxHeapSize < LargePageHeapSizeThreshold) {
FLAG_SET_DEFAULT(UseLargePages, false);
}
#else
if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) {
FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1);
}
#endif
#ifndef TIERED
UNSUPPORTED_OPTION(TieredCompilation, "TieredCompilation");
#endif
if (os::is_headless_jre()) {
const char* headless = Arguments::get_property("java.awt.headless");
if (headless == NULL) {
char envbuffer[128];
if (!os::getenv("JAVA_AWT_HEADLESS", envbuffer, sizeof(envbuffer))) {
if (!add_property("java.awt.headless=true")) {
return JNI_ENOMEM;
}
} else {
char buffer[256];
jio_snprintf(buffer, 256, "java.awt.headless=%s", envbuffer);
if (!add_property(buffer)) {
return JNI_ENOMEM;
}
}
}
}
if (!check_vm_args_consistency()) {
return JNI_ERR;
}
return JNI_OK;
}
jint Arguments::parse_java_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p) {
return parse_options_environment_variable("_JAVA_OPTIONS", scp_p,
scp_assembly_required_p);
}
jint Arguments::parse_java_tool_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p) {
return parse_options_environment_variable("JAVA_TOOL_OPTIONS", scp_p,
scp_assembly_required_p);
}
jint Arguments::parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p) {
const int N_MAX_OPTIONS = 64;
const int OPTION_BUFFER_SIZE = 1024;
char buffer[OPTION_BUFFER_SIZE];
if (os::getenv(name, buffer, sizeof(buffer)) &&
!os::have_special_privileges()) {
JavaVMOption options[N_MAX_OPTIONS]; // Construct option array
jio_fprintf(defaultStream::error_stream(),
"Picked up %s: %s\n", name, buffer);
char* rd = buffer; // pointer to the input string (rd)
int i;
for (i = 0; i < N_MAX_OPTIONS;) { // repeat for all options in the input string
while (isspace(*rd)) rd++; // skip whitespace
if (*rd == 0) break; // we re done when the input string is read completely
char* wrt = rd;
options[i++].optionString = wrt; // Fill in option
while (*rd != 0 && !isspace(*rd)) { // unquoted strings terminate with a space or NULL
if (*rd == '\'' || *rd == '"') { // handle a quoted string
int quote = *rd; // matching quote to look for
rd++; // don't copy open quote
while (*rd != quote) { // include everything (even spaces) up until quote
if (*rd == 0) { // string termination means unmatched string
jio_fprintf(defaultStream::error_stream(),
"Unmatched quote in %s\n", name);
return JNI_ERR;
}
}
rd++; // don't copy close quote
} else {
}
}
if (*rd++ == 0) {
break;
}
}
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = i;
vm_args.ignoreUnrecognized = IgnoreUnrecognizedVMOptions;
if (PrintVMOptions) {
const char* tail;
for (int i = 0; i < vm_args.nOptions; i++) {
const JavaVMOption *option = vm_args.options + i;
if (match_option(option, "-XX:", &tail)) {
logOption(tail);
}
}
}
return(parse_each_vm_init_arg(&vm_args, scp_p, scp_assembly_required_p, Flag::ENVIRON_VAR));
}
return JNI_OK;
}
void Arguments::set_shared_spaces_flags() {
if (DumpSharedSpaces) {
if (FailOverToOldVerifier) {
FLAG_SET_DEFAULT(FailOverToOldVerifier, false);
}
if (RequireSharedSpaces) {
warning("cannot dump shared archive while using shared archive");
}
UseSharedSpaces = false;
#ifdef _LP64
if (!UseCompressedOops || !UseCompressedClassPointers) {
vm_exit_during_initialization(
"Cannot dump shared archive when UseCompressedOops or UseCompressedClassPointers is off.", NULL);
}
} else {
if (!UseCompressedOops || !UseCompressedClassPointers) {
no_shared_spaces("UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces.");
}
#endif
}
}
#if !INCLUDE_ALL_GCS
static void force_serial_gc() {
FLAG_SET_DEFAULT(UseSerialGC, true);
FLAG_SET_DEFAULT(CMSIncrementalMode, false); // special CMS suboption
UNSUPPORTED_GC_OPTION(UseG1GC);
UNSUPPORTED_GC_OPTION(UseParallelGC);
UNSUPPORTED_GC_OPTION(UseParallelOldGC);
UNSUPPORTED_GC_OPTION(UseConcMarkSweepGC);
UNSUPPORTED_GC_OPTION(UseParNewGC);
}
#endif // INCLUDE_ALL_GCS
static char* get_shared_archive_path() {
char *shared_archive_path;
if (SharedArchiveFile == NULL) {
char jvm_path[JVM_MAXPATHLEN];
os::jvm_path(jvm_path, sizeof(jvm_path));
char *end = strrchr(jvm_path, *os::file_separator());
if (end != NULL) *end = '\0';
size_t jvm_path_len = strlen(jvm_path);
size_t file_sep_len = strlen(os::file_separator());
const size_t len = jvm_path_len + file_sep_len + 20;
shared_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal);
if (shared_archive_path != NULL) {
jio_snprintf(shared_archive_path, len, "%s%sclasses.jsa",
jvm_path, os::file_separator());
}
} else {
shared_archive_path = os::strdup(SharedArchiveFile, mtInternal);
}
return shared_archive_path;
}
#ifndef PRODUCT
static bool use_vm_log() {
if (LogCompilation || !FLAG_IS_DEFAULT(LogFile) ||
PrintCompilation || PrintInlining || PrintDependencies || PrintNativeNMethods ||
PrintDebugInfo || PrintRelocations || PrintNMethods || PrintExceptionHandlers ||
PrintAssembly || TraceDeoptimization || TraceDependencies ||
(VerifyDependencies && FLAG_IS_CMDLINE(VerifyDependencies))) {
return true;
}
#ifdef COMPILER1
if (PrintC1Statistics) {
return true;
}
#endif // COMPILER1
#ifdef COMPILER2
if (PrintOptoAssembly || PrintOptoStatistics) {
return true;
}
#endif // COMPILER2
return false;
}
#endif // PRODUCT
jint Arguments::parse(const JavaVMInitArgs* args) {
const char* tail;
const char* hotspotrc = ".hotspotrc";
bool settings_file_specified = false;
bool needs_hotspotrc_warning = false;
ArgumentsExt::process_options(args);
const char* flags_file;
int index;
for (index = 0; index < args->nOptions; index++) {
const JavaVMOption *option = args->options + index;
if (match_option(option, "-XX:Flags=", &tail)) {
flags_file = tail;
settings_file_specified = true;
}
if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
PrintVMOptions = true;
}
if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
PrintVMOptions = false;
}
if (match_option(option, "-XX:+IgnoreUnrecognizedVMOptions", &tail)) {
IgnoreUnrecognizedVMOptions = true;
}
if (match_option(option, "-XX:-IgnoreUnrecognizedVMOptions", &tail)) {
IgnoreUnrecognizedVMOptions = false;
}
if (match_option(option, "-XX:+PrintFlagsInitial", &tail)) {
CommandLineFlags::printFlags(tty, false);
vm_exit(0);
}
if (match_option(option, "-XX:NativeMemoryTracking", &tail)) {
#if INCLUDE_NMT
if (!MemTracker::check_launcher_nmt_support(tail)) {
warning("Native Memory Tracking did not setup properly, using wrong launcher?");
}
if (MemTracker::verify_nmt_option()) {
if (MemTracker::tracking_level() >= NMT_summary) {
MemTracker::init();
}
} else {
vm_exit_during_initialization("Syntax error, expecting -XX:NativeMemoryTracking=[off|summary|detail]", NULL);
}
#else
jio_fprintf(defaultStream::error_stream(),
"Native Memory Tracking is not supported in this VM\n");
return JNI_ERR;
#endif
}
#ifndef PRODUCT
if (match_option(option, "-XX:+PrintFlagsWithComments", &tail)) {
CommandLineFlags::printFlags(tty, true);
vm_exit(0);
}
#endif
}
if (IgnoreUnrecognizedVMOptions) {
}
if (settings_file_specified) {
if (!process_settings_file(flags_file, true, args->ignoreUnrecognized)) {
return JNI_EINVAL;
}
} else {
#ifdef ASSERT
if (!process_settings_file(".hotspotrc", false, args->ignoreUnrecognized)) {
return JNI_EINVAL;
}
#else
struct stat buf;
if (os::stat(hotspotrc, &buf) == 0) {
needs_hotspotrc_warning = true;
}
#endif
}
if (PrintVMOptions) {
for (index = 0; index < args->nOptions; index++) {
const JavaVMOption *option = args->options + index;
if (match_option(option, "-XX:", &tail)) {
logOption(tail);
}
}
}
jint result = parse_vm_init_args(args);
if (result != JNI_OK) {
return result;
}
SharedArchivePath = get_shared_archive_path();
if (SharedArchivePath == NULL) {
return JNI_ENOMEM;
}
if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) {
VerifySharedSpaces = true;
}
if (needs_hotspotrc_warning) {
warning("%s file is present but has been ignored. "
"Run with -XX:Flags=%s to load the file.",
hotspotrc, hotspotrc);
}
#ifdef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD.
UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages");
#endif
#if INCLUDE_ALL_GCS
#if (defined JAVASE_EMBEDDED || defined ARM)
UNSUPPORTED_OPTION(UseG1GC, "G1 GC");
#endif
#endif
#ifndef PRODUCT
if (TraceBytecodesAt != 0) {
TraceBytecodes = true;
}
if (CountCompiledCalls) {
if (UseCounterDecay) {
warning("UseCounterDecay disabled because CountCalls is set");
UseCounterDecay = false;
}
}
#endif // PRODUCT
if (!JDK_Version::is_gte_jdk17x_version()) {
if (EnableInvokeDynamic) {
if (!FLAG_IS_DEFAULT(EnableInvokeDynamic)) {
warning("JSR 292 is not supported before 1.7. Disabling support.");
}
EnableInvokeDynamic = false;
}
}
if (EnableInvokeDynamic && ScavengeRootsInCode == 0) {
if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) {
warning("forcing ScavengeRootsInCode non-zero because EnableInvokeDynamic is true");
}
ScavengeRootsInCode = 1;
}
if (PrintGCDetails) {
PrintGC = true;
}
if (!JDK_Version::is_gte_jdk18x_version()) {
if (FLAG_IS_DEFAULT(PrintGCCause)) {
FLAG_SET_DEFAULT(PrintGCCause, false);
}
}
set_object_alignment();
#if !INCLUDE_ALL_GCS
force_serial_gc();
#endif // INCLUDE_ALL_GCS
#if !INCLUDE_CDS
if (DumpSharedSpaces || RequireSharedSpaces) {
jio_fprintf(defaultStream::error_stream(),
"Shared spaces are not supported in this VM\n");
return JNI_ERR;
}
if ((UseSharedSpaces && FLAG_IS_CMDLINE(UseSharedSpaces)) || PrintSharedSpaces) {
warning("Shared spaces are not supported in this VM");
FLAG_SET_DEFAULT(UseSharedSpaces, false);
FLAG_SET_DEFAULT(PrintSharedSpaces, false);
}
no_shared_spaces("CDS Disabled");
#endif // INCLUDE_CDS
return JNI_OK;
}
jint Arguments::apply_ergo() {
set_ergonomics_flags();
set_shared_spaces_flags();
#if defined(SPARC)
if (FLAG_IS_DEFAULT(AssumeMP)) {
FLAG_SET_DEFAULT(AssumeMP, true);
}
#endif
if (!check_gc_consistency()) {
return JNI_EINVAL;
}
if (TieredCompilation) {
set_tiered_flags();
} else {
if (CompilationPolicyChoice >= 2) {
vm_exit_during_initialization(
"Incompatible compilation policy selected", NULL);
}
}
if (FLAG_IS_DEFAULT(NmethodSweepFraction)) {
FLAG_SET_DEFAULT(NmethodSweepFraction, 1 + ReservedCodeCacheSize / (16 * M));
}
set_heap_size();
ArgumentsExt::set_gc_specific_flags();
Metaspace::ergo_initialize();
set_bytecode_flags();
set_aggressive_opts_flags();
if (UseHeavyMonitors
#ifdef COMPILER1
|| !UseFastLocking
#endif // COMPILER1
) {
if (!FLAG_IS_DEFAULT(UseBiasedLocking) && UseBiasedLocking) {
warning("Biased Locking is not supported with locking debug flags"
"; ignoring UseBiasedLocking flag." );
}
UseBiasedLocking = false;
}
#ifdef ZERO
FLAG_SET_DEFAULT(ProfileInterpreter, false);
FLAG_SET_DEFAULT(UseBiasedLocking, false);
LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedOops, false));
LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedClassPointers, false));
#endif // CC_INTERP
#ifdef COMPILER2
if (!EliminateLocks) {
EliminateNestedLocks = false;
}
if (!Inline) {
IncrementalInline = false;
}
#ifndef PRODUCT
if (!IncrementalInline) {
AlwaysIncrementalInline = false;
}
#endif
if (IncrementalInline && FLAG_IS_DEFAULT(MaxNodeLimit)) {
FLAG_SET_DEFAULT(MaxNodeLimit, (intx)75000);
}
if (!UseTypeSpeculation && FLAG_IS_DEFAULT(TypeProfileLevel)) {
FLAG_SET_DEFAULT(TypeProfileLevel, 0);
}
#endif
if (PrintAssembly && FLAG_IS_DEFAULT(DebugNonSafepoints)) {
warning("PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output");
DebugNonSafepoints = true;
}
if (FLAG_IS_CMDLINE(CompressedClassSpaceSize) && !UseCompressedClassPointers) {
warning("Setting CompressedClassSpaceSize has no effect when compressed class pointers are not used");
}
if (UseOnStackReplacement && !UseLoopCounter) {
warning("On-stack-replacement requires loop counters; enabling loop counters");
FLAG_SET_DEFAULT(UseLoopCounter, true);
}
#ifndef PRODUCT
if (CompileTheWorld) {
if (FLAG_IS_DEFAULT(NmethodSweepFraction)) {
NmethodSweepFraction = 1;
}
}
if (!LogVMOutput && FLAG_IS_DEFAULT(LogVMOutput)) {
if (use_vm_log()) {
LogVMOutput = true;
}
}
#endif // PRODUCT
if (PrintCommandLineFlags) {
CommandLineFlags::printSetFlags(tty);
}
if (UseBiasedLocking) {
if (!VM_Version::use_biased_locking() &&
!(FLAG_IS_CMDLINE(UseBiasedLocking))) {
UseBiasedLocking = false;
}
}
#ifdef COMPILER2
if (!UseBiasedLocking || EmitSync != 0) {
UseOptoBiasInlining = false;
}
#endif
if (Arguments::created_by_gamma_launcher() && os::is_debugger_attached()) {
bool set = false;
CommandLineFlags::wasSetOnCmdline("PauseAtExit", &set);
if (!set) {
FLAG_SET_DEFAULT(PauseAtExit, true);
}
}
return JNI_OK;
}
jint Arguments::adjust_after_os() {
if (UseNUMA) {
if (UseParallelGC || UseParallelOldGC) {
if (FLAG_IS_DEFAULT(MinHeapDeltaBytes)) {
FLAG_SET_DEFAULT(MinHeapDeltaBytes, 64*M);
}
}
if (FLAG_IS_DEFAULT(UseNUMAInterleaving)) {
FLAG_SET_ERGO(bool, UseNUMAInterleaving, true);
}
}
return JNI_OK;
}
int Arguments::PropertyList_count(SystemProperty* pl) {
int count = 0;
while(pl != NULL) {
count++;
pl = pl->next();
}
return count;
}
const char* Arguments::PropertyList_get_value(SystemProperty *pl, const char* key) {
assert(key != NULL, "just checking");
SystemProperty* prop;
for (prop = pl; prop != NULL; prop = prop->next()) {
if (strcmp(key, prop->key()) == 0) return prop->value();
}
return NULL;
}
const char* Arguments::PropertyList_get_key_at(SystemProperty *pl, int index) {
int count = 0;
const char* ret_val = NULL;
while(pl != NULL) {
if(count >= index) {
ret_val = pl->key();
break;
}
count++;
pl = pl->next();
}
return ret_val;
}
char* Arguments::PropertyList_get_value_at(SystemProperty* pl, int index) {
int count = 0;
char* ret_val = NULL;
while(pl != NULL) {
if(count >= index) {
ret_val = pl->value();
break;
}
count++;
pl = pl->next();
}
return ret_val;
}
void Arguments::PropertyList_add(SystemProperty** plist, SystemProperty *new_p) {
SystemProperty* p = *plist;
if (p == NULL) {
} else {
while (p->next() != NULL) {
p = p->next();
}
p->set_next(new_p);
}
}
void Arguments::PropertyList_add(SystemProperty** plist, const char* k, char* v) {
if (plist == NULL)
return;
SystemProperty* new_p = new SystemProperty(k, v, true);
PropertyList_add(plist, new_p);
}
void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
if (plist == NULL)
return;
SystemProperty* prop;
for (prop = *plist; prop != NULL; prop = prop->next()) {
if (strcmp(k, prop->key()) == 0) {
if (append) {
prop->append_value(v);
} else {
prop->set_value(v);
}
return;
}
}
PropertyList_add(plist, k, v);
}
bool Arguments::copy_expand_pid(const char* src, size_t srclen,
char* buf, size_t buflen) {
const char* p = src;
char* b = buf;
const char* src_end = &src[srclen];
char* buf_end = &buf[buflen - 1];
while (p < src_end && b < buf_end) {
if (*p == '%') {
switch (*(++p)) {
case '%': // "%%" ==> "%"
break;
case 'p': { // "%p" ==> current process id
size_t buf_sz = buf_end - b + 1;
int ret = jio_snprintf(b, buf_sz, "%d", os::current_process_id());
if (ret < 0 || ret >= (int)buf_sz) {
return false;
} else {
b += ret;
assert(*b == '\0', "fail in copy_expand_pid");
if (p == src_end && b == buf_end + 1) {
return true;
}
}
p++;
break;
}
default :
}
} else {
}
}
return (p == src_end); // return false if not all of the source was copied
}
C:\hotspot-69087d08d473\src\share\vm/runtime/arguments.hpp
#ifndef SHARE_VM_RUNTIME_ARGUMENTS_HPP
#define SHARE_VM_RUNTIME_ARGUMENTS_HPP
#include "runtime/java.hpp"
#include "runtime/perfData.hpp"
#include "utilities/debug.hpp"
#include "utilities/top.hpp"
extern "C" {
typedef void (JNICALL *abort_hook_t)(void);
typedef void (JNICALL *exit_hook_t)(jint code);
typedef jint (JNICALL *vfprintf_hook_t)(FILE *fp, const char *format, va_list args) ATTRIBUTE_PRINTF(2, 0);
}
class SysClassPath;
class SystemProperty: public CHeapObj<mtInternal> {
private:
char* _key;
char* _value;
SystemProperty* _next;
bool _writeable;
bool writeable() { return _writeable; }
public:
const char* key() const { return _key; }
char* value() const { return _value; }
SystemProperty* next() const { return _next; }
void set_next(SystemProperty* next) { _next = next; }
bool set_value(char *value) {
if (writeable()) {
if (_value != NULL) {
FreeHeap(_value);
}
_value = AllocateHeap(strlen(value)+1, mtInternal);
if (_value != NULL) {
strcpy(_value, value);
}
return true;
}
return false;
}
void append_value(const char *value) {
char *sp;
size_t len = 0;
if (value != NULL) {
len = strlen(value);
if (_value != NULL) {
len += strlen(_value);
}
sp = AllocateHeap(len+2, mtInternal);
if (sp != NULL) {
if (_value != NULL) {
strcpy(sp, _value);
strcat(sp, os::path_separator());
strcat(sp, value);
FreeHeap(_value);
} else {
strcpy(sp, value);
}
_value = sp;
}
}
}
SystemProperty(const char* key, const char* value, bool writeable) {
if (key == NULL) {
_key = NULL;
} else {
_key = AllocateHeap(strlen(key)+1, mtInternal);
strcpy(_key, key);
}
if (value == NULL) {
_value = NULL;
} else {
_value = AllocateHeap(strlen(value)+1, mtInternal);
strcpy(_value, value);
}
_next = NULL;
_writeable = writeable;
}
};
class AgentLibrary : public CHeapObj<mtInternal> {
friend class AgentLibraryList;
public:
enum AgentState {
agent_invalid = 0,
agent_valid = 1
};
private:
char* _name;
char* _options;
void* _os_lib;
bool _is_absolute_path;
bool _is_static_lib;
AgentState _state;
AgentLibrary* _next;
public:
const char* name() const { return _name; }
char* options() const { return _options; }
bool is_absolute_path() const { return _is_absolute_path; }
void* os_lib() const { return _os_lib; }
void set_os_lib(void* os_lib) { _os_lib = os_lib; }
AgentLibrary* next() const { return _next; }
bool is_static_lib() const { return _is_static_lib; }
void set_static_lib(bool is_static_lib) { _is_static_lib = is_static_lib; }
bool valid() { return (_state == agent_valid); }
void set_valid() { _state = agent_valid; }
void set_invalid() { _state = agent_invalid; }
AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) {
_name = AllocateHeap(strlen(name)+1, mtInternal);
strcpy(_name, name);
if (options == NULL) {
_options = NULL;
} else {
_options = AllocateHeap(strlen(options)+1, mtInternal);
strcpy(_options, options);
}
_is_absolute_path = is_absolute_path;
_os_lib = os_lib;
_next = NULL;
_state = agent_invalid;
_is_static_lib = false;
}
};
class AgentLibraryList VALUE_OBJ_CLASS_SPEC {
private:
AgentLibrary* _first;
AgentLibrary* _last;
public:
bool is_empty() const { return _first == NULL; }
AgentLibrary* first() const { return _first; }
void add(AgentLibrary* lib) {
if (is_empty()) {
_first = _last = lib;
} else {
_last->_next = lib;
_last = lib;
}
lib->_next = NULL;
}
void remove(AgentLibrary* lib) {
AgentLibrary* curr;
AgentLibrary* prev = NULL;
for (curr = first(); curr != NULL; prev = curr, curr = curr->next()) {
if (curr == lib) {
break;
}
}
assert(curr != NULL, "always should be found");
if (curr != NULL) {
if (prev == NULL) {
_first = curr->_next;
} else {
prev->_next = curr->_next;
}
if (curr == _last) {
_last = prev;
}
curr->_next = NULL;
}
}
AgentLibraryList() {
_first = NULL;
_last = NULL;
}
};
class Arguments : AllStatic {
friend class VMStructs;
friend class JvmtiExport;
public:
enum Mode {
_int, // corresponds to -Xint
_mixed, // corresponds to -Xmixed
_comp // corresponds to -Xcomp
};
enum ArgsRange {
arg_unreadable = -3,
arg_too_small = -2,
arg_too_big = -1,
arg_in_range = 0
};
private:
static char** _jvm_flags_array;
static int _num_jvm_flags;
static char** _jvm_args_array;
static int _num_jvm_args;
static char* _java_command;
static SystemProperty* _system_properties;
static SystemProperty *_java_ext_dirs;
static SystemProperty *_java_endorsed_dirs;
static SystemProperty *_sun_boot_library_path;
static SystemProperty *_java_library_path;
static SystemProperty *_java_home;
static SystemProperty *_java_class_path;
static SystemProperty *_sun_boot_class_path;
static char* _meta_index_path;
static char* _meta_index_dir;
static const char* _java_vendor_url_bug;
static const char* _sun_java_launcher;
static int _sun_java_launcher_pid;
static bool _created_by_gamma_launcher;
static bool _has_profile;
static const char* _gc_log_filename;
static size_t _conservative_max_heap_alignment;
static uintx _min_heap_size;
static uintx _min_heap_free_ratio;
static uintx _max_heap_free_ratio;
static AgentLibraryList _libraryList;
static void add_init_library(const char* name, char* options)
{ _libraryList.add(new AgentLibrary(name, options, false, NULL)); }
static AgentLibraryList _agentList;
static void add_init_agent(const char* name, char* options, bool absolute_path)
{ _agentList.add(new AgentLibrary(name, options, absolute_path, NULL)); }
static void add_loaded_agent(AgentLibrary *agentLib)
{ _agentList.add(agentLib); }
static void add_loaded_agent(const char* name, char* options, bool absolute_path, void* os_lib)
{ _agentList.add(new AgentLibrary(name, options, absolute_path, os_lib)); }
static Mode _mode;
static void set_mode_flags(Mode mode);
static bool _java_compiler;
static void set_java_compiler(bool arg) { _java_compiler = arg; }
static bool java_compiler() { return _java_compiler; }
static bool _xdebug_mode;
static void set_xdebug_mode(bool arg) { _xdebug_mode = arg; }
static bool xdebug_mode() { return _xdebug_mode; }
static bool _AlwaysCompileLoopMethods;
static bool _UseOnStackReplacement;
static bool _BackgroundCompilation;
static bool _ClipInlining;
static bool _CIDynamicCompilePriority;
static void set_tiered_flags();
static int get_min_number_of_compiler_threads();
static void set_parnew_gc_flags();
static void set_cms_and_parnew_gc_flags();
static void set_parallel_gc_flags();
static void set_g1_gc_flags();
static void set_conservative_max_heap_alignment();
static void set_use_compressed_oops();
static void set_use_compressed_klass_ptrs();
static void select_gc();
static void set_ergonomics_flags();
static void set_shared_spaces_flags();
static julong limit_by_allocatable_memory(julong size);
static void set_heap_size();
static bool should_auto_select_low_pause_collector();
static void set_bytecode_flags();
static abort_hook_t _abort_hook;
static exit_hook_t _exit_hook;
static vfprintf_hook_t _vfprintf_hook;
static bool add_property(const char* prop);
static void set_aggressive_opts_flags();
static jint set_aggressive_heap_flags();
static void do_pd_flag_adjustments();
static bool parse_argument(const char* arg, Flag::Flags origin);
static bool process_argument(const char* arg, jboolean ignore_unrecognized, Flag::Flags origin);
static void process_java_launcher_argument(const char*, void*);
static void process_java_compiler_argument(char* arg);
static jint parse_options_environment_variable(const char* name, SysClassPath* scp_p, bool* scp_assembly_required_p);
static jint parse_java_tool_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p);
static jint parse_java_options_environment_variable(SysClassPath* scp_p, bool* scp_assembly_required_p);
static jint parse_vm_init_args(const JavaVMInitArgs* args);
static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, Flag::Flags origin);
static jint finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required);
static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type);
static bool is_bad_option(const JavaVMOption* option, jboolean ignore) {
return is_bad_option(option, ignore, NULL);
}
static bool is_percentage(uintx val) {
return val <= 100;
}
static bool verify_interval(uintx val, uintx min,
uintx max, const char* name);
static bool verify_min_value(intx val, intx min, const char* name);
static bool verify_percentage(uintx value, const char* name);
static void describe_range_error(ArgsRange errcode);
static ArgsRange check_memory_size(julong size, julong min_size);
static ArgsRange parse_memory_size(const char* s, julong* long_arg,
julong min_size);
static bool parse_uintx(const char* value, uintx* uintx_arg,
uintx min_size);
static void build_jvm_args(const char* arg);
static void build_jvm_flags(const char* arg);
static void add_string(char*** bldarray, int* count, const char* arg);
static const char* build_resource_string(char** args, int count);
static bool methodExists(
char* className, char* methodName,
int classesNum, char** classes, bool* allMethods,
int methodsNum, char** methods, bool* allClasses
);
static void parseOnlyLine(
const char* line,
short* classesNum, short* classesMax, char*** classes, bool** allMethods,
short* methodsNum, short* methodsMax, char*** methods, bool** allClasses
);
static bool is_newly_obsolete(const char* s, JDK_Version* buffer);
static short CompileOnlyClassesNum;
static short CompileOnlyClassesMax;
static char** CompileOnlyClasses;
static bool* CompileOnlyAllMethods;
static short CompileOnlyMethodsNum;
static short CompileOnlyMethodsMax;
static char** CompileOnlyMethods;
static bool* CompileOnlyAllClasses;
static short InterpretOnlyClassesNum;
static short InterpretOnlyClassesMax;
static char** InterpretOnlyClasses;
static bool* InterpretOnlyAllMethods;
static bool CheckCompileOnly;
static char* SharedArchivePath;
public:
static jint parse(const JavaVMInitArgs* args);
static jint apply_ergo();
static jint adjust_after_os();
static void set_gc_specific_flags();
static inline bool gc_selected(); // whether a gc has been selected
static void select_gc_ergonomically();
static bool verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio);
static bool verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio);
static bool check_gc_consistency(); // Check user-selected gc
static void check_deprecated_gcs();
static void check_deprecated_gc_flags();
static bool check_vm_args_consistency();
static bool check_stack_pages();
static bool process_settings_file(const char* file_name, bool should_exist, jboolean ignore_unrecognized);
static size_t conservative_max_heap_alignment() { return _conservative_max_heap_alignment; }
static size_t max_heap_for_compressed_oops();
static char** jvm_flags_array() { return _jvm_flags_array; }
static char** jvm_args_array() { return _jvm_args_array; }
static int num_jvm_flags() { return _num_jvm_flags; }
static int num_jvm_args() { return _num_jvm_args; }
static const char* java_command() { return _java_command; }
static void print_on(outputStream* st);
static const char* jvm_flags() { return build_resource_string(_jvm_flags_array, _num_jvm_flags); }
static const char* jvm_args() { return build_resource_string(_jvm_args_array, _num_jvm_args); }
static void print_jvm_flags_on(outputStream* st);
static void print_jvm_args_on(outputStream* st);
static SystemProperty* system_properties() { return _system_properties; }
static const char* get_property(const char* key);
static const char* java_vendor_url_bug() { return _java_vendor_url_bug; }
static const char* sun_java_launcher() { return _sun_java_launcher; }
static bool created_by_java_launcher();
static bool created_by_gamma_launcher();
static int sun_java_launcher_pid() { return _sun_java_launcher_pid; }
static const char* gc_log_filename() { return _gc_log_filename; }
static bool has_profile() { return _has_profile; }
static uintx min_heap_size() { return _min_heap_size; }
static void set_min_heap_size(uintx v) { _min_heap_size = v; }
static uintx min_heap_free_ratio() { return _min_heap_free_ratio; }
static uintx max_heap_free_ratio() { return _max_heap_free_ratio; }
static AgentLibrary* libraries() { return _libraryList.first(); }
static bool init_libraries_at_startup() { return !_libraryList.is_empty(); }
static void convert_library_to_agent(AgentLibrary* lib)
{ _libraryList.remove(lib);
_agentList.add(lib); }
static AgentLibrary* agents() { return _agentList.first(); }
static bool init_agents_at_startup() { return !_agentList.is_empty(); }
static abort_hook_t abort_hook() { return _abort_hook; }
static exit_hook_t exit_hook() { return _exit_hook; }
static vfprintf_hook_t vfprintf_hook() { return _vfprintf_hook; }
static bool GetCheckCompileOnly () { return CheckCompileOnly; }
static const char* GetSharedArchivePath() { return SharedArchivePath; }
static bool CompileMethod(char* className, char* methodName) {
return
methodExists(
className, methodName,
CompileOnlyClassesNum, CompileOnlyClasses, CompileOnlyAllMethods,
CompileOnlyMethodsNum, CompileOnlyMethods, CompileOnlyAllClasses
);
}
static void process_sun_java_launcher_properties(JavaVMInitArgs* args);
static void init_system_properties();
static void init_version_specific_system_properties();
static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
PropertyList_unique_add(plist, k, v, false);
}
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append);
static const char* PropertyList_get_value(SystemProperty* plist, const char* key);
static int PropertyList_count(SystemProperty* pl);
static const char* PropertyList_get_key_at(SystemProperty* pl,int index);
static char* PropertyList_get_value_at(SystemProperty* pl,int index);
static void set_dll_dir(char *value) { _sun_boot_library_path->set_value(value); }
static void set_java_home(char *value) { _java_home->set_value(value); }
static void set_library_path(char *value) { _java_library_path->set_value(value); }
static void set_ext_dirs(char *value) { _java_ext_dirs->set_value(value); }
static void set_endorsed_dirs(char *value) { _java_endorsed_dirs->set_value(value); }
static void set_sysclasspath(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_meta_index_path(char* meta_index_path, char* meta_index_dir) {
_meta_index_path = meta_index_path;
_meta_index_dir = meta_index_dir;
}
static char* get_java_home() { return _java_home->value(); }
static char* get_dll_dir() { return _sun_boot_library_path->value(); }
static char* get_endorsed_dir() { return _java_endorsed_dirs->value(); }
static char* get_sysclasspath() { return _sun_boot_class_path->value(); }
static char* get_meta_index_path() { return _meta_index_path; }
static char* get_meta_index_dir() { return _meta_index_dir; }
static char* get_ext_dirs() { return _java_ext_dirs->value(); }
static char* get_appclasspath() { return _java_class_path->value(); }
static void fix_appclasspath();
static Mode mode() { return _mode; }
static bool is_interpreter_only() { return mode() == _int; }
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);
};
bool Arguments::gc_selected() {
return UseConcMarkSweepGC || UseG1GC || UseParallelGC || UseParallelOldGC ||
UseParNewGC || UseSerialGC;
}
#endif // SHARE_VM_RUNTIME_ARGUMENTS_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/arguments_ext.hpp
#ifndef SHARE_VM_RUNTIME_ARGUMENTS_EXT_HPP
#define SHARE_VM_RUNTIME_ARGUMENTS_EXT_HPP
#include "memory/allocation.hpp"
#include "runtime/arguments.hpp"
class ArgumentsExt: AllStatic {
public:
static inline void set_gc_specific_flags();
static void process_options(const JavaVMInitArgs* args) {}
};
void ArgumentsExt::set_gc_specific_flags() {
Arguments::set_gc_specific_flags();
}
#endif // SHARE_VM_RUNTIME_ARGUMENTS_EXT_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/atomic.cpp
#include "precompiled.hpp"
#include "runtime/atomic.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_aix
# include "os_aix.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
#include "runtime/atomic.inline.hpp"
jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
assert(sizeof(jbyte) == 1, "assumption.");
uintptr_t dest_addr = (uintptr_t)dest;
uintptr_t offset = dest_addr % sizeof(jint);
volatile jint* dest_int = (volatile jint*)(dest_addr - offset);
jint cur = *dest_int;
jbyte* cur_as_bytes = (jbyte*)(&cur);
jint new_val = cur;
jbyte* new_val_as_bytes = (jbyte*)(&new_val);
new_val_as_bytes[offset] = exchange_value;
while (cur_as_bytes[offset] == compare_value) {
jint res = cmpxchg(new_val, dest_int, cur);
if (res == cur) break;
cur = res;
new_val = cur;
new_val_as_bytes[offset] = exchange_value;
}
return cur_as_bytes[offset];
}
unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) {
assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest);
}
unsigned Atomic::cmpxchg(unsigned int exchange_value,
volatile unsigned int* dest, unsigned int compare_value) {
assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
(jint)compare_value);
}
jlong Atomic::add(jlong add_value, volatile jlong* dest) {
jlong old = load(dest);
jlong new_value = old + add_value;
while (old != cmpxchg(new_value, dest, old)) {
old = load(dest);
new_value = old + add_value;
}
return old;
}
void Atomic::inc(volatile short* dest) {
#ifdef VM_LITTLE_ENDIAN
assert((intx(dest) & 0x03) == 0x02, "wrong alignment");
(void)Atomic::add(0x10000, (volatile int*)(dest-1));
#else
assert((intx(dest) & 0x03) == 0x00, "wrong alignment");
(void)Atomic::add(0x10000, (volatile int*)(dest));
#endif
}
void Atomic::dec(volatile short* dest) {
#ifdef VM_LITTLE_ENDIAN
assert((intx(dest) & 0x03) == 0x02, "wrong alignment");
(void)Atomic::add(-0x10000, (volatile int*)(dest-1));
#else
assert((intx(dest) & 0x03) == 0x00, "wrong alignment");
(void)Atomic::add(-0x10000, (volatile int*)(dest));
#endif
}
C:\hotspot-69087d08d473\src\share\vm/runtime/atomic.hpp
#ifndef SHARE_VM_RUNTIME_ATOMIC_HPP
#define SHARE_VM_RUNTIME_ATOMIC_HPP
#include "memory/allocation.hpp"
class Atomic : AllStatic {
public:
inline static void store (jbyte store_value, jbyte* dest);
inline static void store (jshort store_value, jshort* dest);
inline static void store (jint store_value, jint* dest);
inline static void store (jlong store_value, jlong* dest);
inline static void store_ptr(intptr_t store_value, intptr_t* dest);
inline static void store_ptr(void* store_value, void* dest);
inline static void store (jbyte store_value, volatile jbyte* dest);
inline static void store (jshort store_value, volatile jshort* dest);
inline static void store (jint store_value, volatile jint* dest);
inline static void store (jlong store_value, volatile jlong* dest);
inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest);
inline static void store_ptr(void* store_value, volatile void* dest);
inline static jlong load(volatile jlong* src);
inline static jint add (jint add_value, volatile jint* dest);
inline static intptr_t add_ptr(intptr_t add_value, volatile intptr_t* dest);
inline static void* add_ptr(intptr_t add_value, volatile void* dest);
static jlong add (jlong add_value, volatile jlong* dest);
inline static void inc (volatile jint* dest);
static void inc (volatile jshort* dest);
inline static void inc_ptr(volatile intptr_t* dest);
inline static void inc_ptr(volatile void* dest);
inline static void dec (volatile jint* dest);
static void dec (volatile jshort* dest);
inline static void dec_ptr(volatile intptr_t* dest);
inline static void dec_ptr(volatile void* dest);
inline static jint xchg(jint exchange_value, volatile jint* dest);
static unsigned int xchg(unsigned int exchange_value, volatile unsigned int* dest);
inline static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest);
inline static void* xchg_ptr(void* exchange_value, volatile void* dest);
static jbyte cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value);
inline static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value);
inline static jlong cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value);
static unsigned int cmpxchg(unsigned int exchange_value,
volatile unsigned int* dest,
unsigned int compare_value);
inline static intptr_t cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value);
inline static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value);
};
#ifdef VM_LITTLE_ENDIAN
#define ATOMIC_SHORT_PAIR(atomic_decl, non_atomic_decl) \
non_atomic_decl; \
atomic_decl
#else
#define ATOMIC_SHORT_PAIR(atomic_decl, non_atomic_decl) \
atomic_decl ; \
non_atomic_decl
#endif
#endif // SHARE_VM_RUNTIME_ATOMIC_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/atomic.inline.hpp
#ifndef SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP
#define SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP
#include "runtime/atomic.hpp"
#ifdef TARGET_OS_ARCH_linux_x86
# include "atomic_linux_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_sparc
# include "atomic_linux_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_zero
# include "atomic_linux_zero.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_arm
# include "atomic_linux_arm.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_ppc
# include "atomic_linux_ppc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_aarch64
# include "atomic_linux_aarch64.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_x86
# include "atomic_solaris_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_sparc
# include "atomic_solaris_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_windows_x86
# include "atomic_windows_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_aix_ppc
# include "atomic_aix_ppc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_x86
# include "atomic_bsd_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_zero
# include "atomic_bsd_zero.inline.hpp"
#endif
#endif // SHARE_VM_RUNTIME_ATOMIC_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/basicLock.cpp
#include "precompiled.hpp"
#include "runtime/basicLock.hpp"
#include "runtime/synchronizer.hpp"
void BasicLock::print_on(outputStream* st) const {
st->print("monitor");
markOop moop = displaced_header();
if (moop != NULL)
moop->print_on(st);
}
void BasicLock::move_to(oop obj, BasicLock* dest) {
if (displaced_header()->is_neutral()) {
ObjectSynchronizer::inflate_helper(obj);
} else {
}
intptr_t dh = (intptr_t) displaced_header();
dest->set_displaced_header(displaced_header());
}
C:\hotspot-69087d08d473\src\share\vm/runtime/basicLock.hpp
#ifndef SHARE_VM_RUNTIME_BASICLOCK_HPP
#define SHARE_VM_RUNTIME_BASICLOCK_HPP
#include "oops/markOop.hpp"
#include "runtime/handles.hpp"
#include "utilities/top.hpp"
class BasicLock VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
volatile markOop _displaced_header;
public:
markOop displaced_header() const { return _displaced_header; }
void set_displaced_header(markOop header) { _displaced_header = header; }
void print_on(outputStream* st) const;
void move_to(oop obj, BasicLock* dest);
static int displaced_header_offset_in_bytes() { return offset_of(BasicLock, _displaced_header); }
};
class BasicObjectLock VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
BasicLock _lock; // the lock, must be double word aligned
oop _obj; // object holds the lock;
public:
oop obj() const { return _obj; }
void set_obj(oop obj) { _obj = obj; }
BasicLock* lock() { return &_lock; }
static int size() { return sizeof(BasicObjectLock)/wordSize; }
void oops_do(OopClosure* f) { f->do_oop(&_obj); }
static int obj_offset_in_bytes() { return offset_of(BasicObjectLock, _obj); }
static int lock_offset_in_bytes() { return offset_of(BasicObjectLock, _lock); }
};
#endif // SHARE_VM_RUNTIME_BASICLOCK_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/biasedLocking.cpp
#include "precompiled.hpp"
#include "oops/klass.inline.hpp"
#include "oops/markOop.hpp"
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/task.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "jfr/jfrEvents.hpp"
static bool _biased_locking_enabled = false;
BiasedLockingCounters BiasedLocking::_counters;
static GrowableArray<Handle>* _preserved_oop_stack = NULL;
static GrowableArray<markOop>* _preserved_mark_stack = NULL;
static void enable_biased_locking(Klass* k) {
k->set_prototype_header(markOopDesc::biased_locking_prototype());
}
class VM_EnableBiasedLocking: public VM_Operation {
private:
bool _is_cheap_allocated;
public:
VM_EnableBiasedLocking(bool is_cheap_allocated) { _is_cheap_allocated = is_cheap_allocated; }
VMOp_Type type() const { return VMOp_EnableBiasedLocking; }
Mode evaluation_mode() const { return _is_cheap_allocated ? _async_safepoint : _safepoint; }
bool is_cheap_allocated() const { return _is_cheap_allocated; }
void doit() {
SystemDictionary::classes_do(enable_biased_locking);
_biased_locking_enabled = true;
if (TraceBiasedLocking) {
tty->print_cr("Biased locking enabled");
}
}
bool allow_nested_vm_operations() const { return false; }
};
class EnableBiasedLockingTask : public PeriodicTask {
public:
EnableBiasedLockingTask(size_t interval_time) : PeriodicTask(interval_time) {}
virtual void task() {
VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking(true);
VMThread::execute(op);
delete this;
}
};
void BiasedLocking::init() {
if (UseBiasedLocking) {
if (BiasedLockingStartupDelay > 0) {
EnableBiasedLockingTask* task = new EnableBiasedLockingTask(BiasedLockingStartupDelay);
task->enroll();
} else {
VM_EnableBiasedLocking op(false);
VMThread::execute(&op);
}
}
}
bool BiasedLocking::enabled() {
return _biased_locking_enabled;
}
static GrowableArray<MonitorInfo*>* get_or_compute_monitor_info(JavaThread* thread) {
GrowableArray<MonitorInfo*>* info = thread->cached_monitor_info();
if (info != NULL) {
return info;
}
info = new GrowableArray<MonitorInfo*>();
if (thread->has_last_Java_frame()) {
RegisterMap rm(thread);
for (javaVFrame* vf = thread->last_java_vframe(&rm); vf != NULL; vf = vf->java_sender()) {
GrowableArray<MonitorInfo*> *monitors = vf->monitors();
if (monitors != NULL) {
int len = monitors->length();
for (int i = len - 1; i >= 0; i--) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->eliminated()) continue;
oop owner = mon_info->owner();
if (owner != NULL) {
info->append(mon_info);
}
}
}
}
}
thread->set_cached_monitor_info(info);
return info;
}
static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread, JavaThread** biased_locker) {
markOop mark = obj->mark();
if (!mark->has_bias_pattern()) {
if (TraceBiasedLocking) {
ResourceMark rm;
tty->print_cr(" (Skipping revocation of object of type %s because it's no longer biased)",
obj->klass()->external_name());
}
return BiasedLocking::NOT_BIASED;
}
uint age = mark->age();
markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age);
markOop unbiased_prototype = markOopDesc::prototype()->set_age(age);
if (TraceBiasedLocking && (Verbose || !is_bulk)) {
ResourceMark rm;
tty->print_cr("Revoking bias of object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s , prototype header " INTPTR_FORMAT " , allow rebias %d , requesting thread " INTPTR_FORMAT,
p2i((void *)obj), (intptr_t) mark, obj->klass()->external_name(), (intptr_t) obj->klass()->prototype_header(), (allow_rebias ? 1 : 0), (intptr_t) requesting_thread);
}
JavaThread* biased_thread = mark->biased_locker();
if (biased_thread == NULL) {
if (!allow_rebias) {
obj->set_mark(unbiased_prototype);
}
if (TraceBiasedLocking && (Verbose || !is_bulk)) {
tty->print_cr(" Revoked bias of anonymously-biased object");
}
return BiasedLocking::BIAS_REVOKED;
}
bool thread_is_alive = false;
if (requesting_thread == biased_thread) {
thread_is_alive = true;
} else {
for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {
if (cur_thread == biased_thread) {
thread_is_alive = true;
break;
}
}
}
if (!thread_is_alive) {
if (allow_rebias) {
obj->set_mark(biased_prototype);
} else {
obj->set_mark(unbiased_prototype);
}
if (TraceBiasedLocking && (Verbose || !is_bulk)) {
tty->print_cr(" Revoked bias of object biased toward dead thread");
}
return BiasedLocking::BIAS_REVOKED;
}
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(biased_thread);
BasicLock* highest_lock = NULL;
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
if (mon_info->owner() == obj) {
if (TraceBiasedLocking && Verbose) {
tty->print_cr(" mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")",
p2i((void *) mon_info->owner()),
p2i((void *) obj));
}
markOop mark = markOopDesc::encode((BasicLock*) NULL);
highest_lock = mon_info->lock();
highest_lock->set_displaced_header(mark);
} else {
if (TraceBiasedLocking && Verbose) {
tty->print_cr(" mon_info->owner (" PTR_FORMAT ") != obj (" PTR_FORMAT ")",
p2i((void *) mon_info->owner()),
p2i((void *) obj));
}
}
}
if (highest_lock != NULL) {
highest_lock->set_displaced_header(unbiased_prototype);
obj->release_set_mark(markOopDesc::encode(highest_lock));
assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit");
if (TraceBiasedLocking && (Verbose || !is_bulk)) {
tty->print_cr(" Revoked bias of currently-locked object");
}
} else {
if (TraceBiasedLocking && (Verbose || !is_bulk)) {
tty->print_cr(" Revoked bias of currently-unlocked object");
}
if (allow_rebias) {
obj->set_mark(biased_prototype);
} else {
obj->set_mark(unbiased_prototype);
}
}
#if INCLUDE_JFR
if (biased_locker != NULL) {
}
#endif // INCLUDE_JFR
return BiasedLocking::BIAS_REVOKED;
}
enum HeuristicsResult {
HR_NOT_BIASED = 1,
HR_SINGLE_REVOKE = 2,
HR_BULK_REBIAS = 3,
HR_BULK_REVOKE = 4
};
static HeuristicsResult update_heuristics(oop o, bool allow_rebias) {
markOop mark = o->mark();
if (!mark->has_bias_pattern()) {
return HR_NOT_BIASED;
}
Klass* k = o->klass();
jlong cur_time = os::javaTimeMillis();
jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time();
int revocation_count = k->biased_lock_revocation_count();
if ((revocation_count >= BiasedLockingBulkRebiasThreshold) &&
(revocation_count < BiasedLockingBulkRevokeThreshold) &&
(last_bulk_revocation_time != 0) &&
(cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) {
k->set_biased_lock_revocation_count(0);
revocation_count = 0;
}
if (revocation_count <= BiasedLockingBulkRevokeThreshold) {
revocation_count = k->atomic_incr_biased_lock_revocation_count();
}
if (revocation_count == BiasedLockingBulkRevokeThreshold) {
return HR_BULK_REVOKE;
}
if (revocation_count == BiasedLockingBulkRebiasThreshold) {
return HR_BULK_REBIAS;
}
return HR_SINGLE_REVOKE;
}
static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,
bool bulk_rebias,
bool attempt_rebias_of_object,
JavaThread* requesting_thread) {
assert(SafepointSynchronize::is_at_safepoint(), "must be done at safepoint");
if (TraceBiasedLocking) {
tty->print_cr("* Beginning bulk revocation (kind == %s) because of object "
INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",
(bulk_rebias ? "rebias" : "revoke"),
p2i((void *) o), (intptr_t) o->mark(), o->klass()->external_name());
}
jlong cur_time = os::javaTimeMillis();
o->klass()->set_last_biased_lock_bulk_revocation_time(cur_time);
Klass* k_o = o->klass();
Klass* klass = k_o;
if (bulk_rebias) {
if (klass->prototype_header()->has_bias_pattern()) {
int prev_epoch = klass->prototype_header()->bias_epoch();
klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());
int cur_epoch = klass->prototype_header()->bias_epoch();
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
oop owner = mon_info->owner();
markOop mark = owner->mark();
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");
owner->set_mark(mark->set_bias_epoch(cur_epoch));
}
}
}
}
revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);
} else {
if (TraceBiasedLocking) {
ResourceMark rm;
tty->print_cr("* Disabling biased locking for type %s", klass->external_name());
}
klass->set_prototype_header(markOopDesc::prototype());
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);
for (int i = 0; i < cached_monitor_info->length(); i++) {
MonitorInfo* mon_info = cached_monitor_info->at(i);
oop owner = mon_info->owner();
markOop mark = owner->mark();
if ((owner->klass() == k_o) && mark->has_bias_pattern()) {
revoke_bias(owner, false, true, requesting_thread, NULL);
}
}
}
revoke_bias(o, false, true, requesting_thread, NULL);
}
if (TraceBiasedLocking) {
tty->print_cr("* Ending bulk revocation");
}
BiasedLocking::Condition status_code = BiasedLocking::BIAS_REVOKED;
if (attempt_rebias_of_object &&
o->mark()->has_bias_pattern() &&
klass->prototype_header()->has_bias_pattern()) {
markOop new_mark = markOopDesc::encode(requesting_thread, o->mark()->age(),
klass->prototype_header()->bias_epoch());
o->set_mark(new_mark);
status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED;
if (TraceBiasedLocking) {
tty->print_cr(" Rebiased object toward thread " INTPTR_FORMAT, (intptr_t) requesting_thread);
}
}
assert(!o->mark()->has_bias_pattern() ||
(attempt_rebias_of_object && (o->mark()->biased_locker() == requesting_thread)),
"bug in bulk bias revocation");
return status_code;
}
static void clean_up_cached_monitor_info() {
for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {
thr->set_cached_monitor_info(NULL);
}
}
class VM_RevokeBias : public VM_Operation {
protected:
Handle* _obj;
GrowableArray<Handle>* _objs;
JavaThread* _requesting_thread;
BiasedLocking::Condition _status_code;
traceid _biased_locker_id;
public:
VM_RevokeBias(Handle* obj, JavaThread* requesting_thread)
: _obj(obj)
, _objs(NULL)
, _requesting_thread(requesting_thread)
, _status_code(BiasedLocking::NOT_BIASED)
, _biased_locker_id(0) {}
VM_RevokeBias(GrowableArray<Handle>* objs, JavaThread* requesting_thread)
: _obj(NULL)
, _objs(objs)
, _requesting_thread(requesting_thread)
, _status_code(BiasedLocking::NOT_BIASED)
, _biased_locker_id(0) {}
virtual VMOp_Type type() const { return VMOp_RevokeBias; }
virtual bool doit_prologue() {
if (_obj != NULL) {
markOop mark = (*_obj)()->mark();
if (mark->has_bias_pattern()) {
return true;
}
} else {
for ( int i = 0 ; i < _objs->length(); i++ ) {
markOop mark = (_objs->at(i))()->mark();
if (mark->has_bias_pattern()) {
return true;
}
}
}
return false;
}
virtual void doit() {
if (_obj != NULL) {
if (TraceBiasedLocking) {
tty->print_cr("Revoking bias with potentially per-thread safepoint:");
}
JavaThread* biased_locker = NULL;
_status_code = revoke_bias((*_obj)(), false, false, _requesting_thread, &biased_locker);
#if INCLUDE_JFR
if (biased_locker != NULL) {
_biased_locker_id = JFR_THREAD_ID(biased_locker);
}
#endif // INCLUDE_JFR
clean_up_cached_monitor_info();
return;
} else {
if (TraceBiasedLocking) {
tty->print_cr("Revoking bias with global safepoint:");
}
BiasedLocking::revoke_at_safepoint(_objs);
}
}
BiasedLocking::Condition status_code() const {
return _status_code;
}
traceid biased_locker() const {
return _biased_locker_id;
}
};
class VM_BulkRevokeBias : public VM_RevokeBias {
private:
bool _bulk_rebias;
bool _attempt_rebias_of_object;
public:
VM_BulkRevokeBias(Handle* obj, JavaThread* requesting_thread,
bool bulk_rebias,
bool attempt_rebias_of_object)
: VM_RevokeBias(obj, requesting_thread)
, _bulk_rebias(bulk_rebias)
, _attempt_rebias_of_object(attempt_rebias_of_object) {}
virtual VMOp_Type type() const { return VMOp_BulkRevokeBias; }
virtual bool doit_prologue() { return true; }
virtual void doit() {
_status_code = bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread);
clean_up_cached_monitor_info();
}
};
BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {
assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
markOop mark = obj->mark();
if (mark->is_biased_anonymously() && !attempt_rebias) {
markOop biased_value = mark;
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
return BIAS_REVOKED;
}
} else if (mark->has_bias_pattern()) {
Klass* k = obj->klass();
markOop prototype_header = k->prototype_header();
if (!prototype_header->has_bias_pattern()) {
markOop biased_value = mark;
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);
assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked");
return BIAS_REVOKED;
} else if (prototype_header->bias_epoch() != mark->bias_epoch()) {
if (attempt_rebias) {
assert(THREAD->is_Java_thread(), "");
markOop biased_value = mark;
markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
return BIAS_REVOKED_AND_REBIASED;
}
} else {
markOop biased_value = mark;
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);
if (res_mark == biased_value) {
return BIAS_REVOKED;
}
}
}
}
HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias);
if (heuristics == HR_NOT_BIASED) {
return NOT_BIASED;
} else if (heuristics == HR_SINGLE_REVOKE) {
Klass *k = obj->klass();
markOop prototype_header = k->prototype_header();
if (mark->biased_locker() == THREAD &&
prototype_header->bias_epoch() == mark->bias_epoch()) {
ResourceMark rm;
if (TraceBiasedLocking) {
tty->print_cr("Revoking bias by walking my own stack:");
}
EventBiasedLockSelfRevocation event;
BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD, NULL);
((JavaThread*) THREAD)->set_cached_monitor_info(NULL);
assert(cond == BIAS_REVOKED, "why not?");
if (event.should_commit()) {
event.set_lockClass(k);
event.commit();
}
return cond;
} else {
EventBiasedLockRevocation event;
VM_RevokeBias revoke(&obj, (JavaThread*) THREAD);
VMThread::execute(&revoke);
if (event.should_commit() && (revoke.status_code() != NOT_BIASED)) {
event.set_lockClass(k);
event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
event.set_previousOwner(revoke.biased_locker());
event.commit();
}
return revoke.status_code();
}
}
assert((heuristics == HR_BULK_REVOKE) ||
(heuristics == HR_BULK_REBIAS), "?");
EventBiasedLockClassRevocation event;
VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD,
(heuristics == HR_BULK_REBIAS),
attempt_rebias);
VMThread::execute(&bulk_revoke);
if (event.should_commit()) {
event.set_revokedClass(obj->klass());
event.set_disableBiasing((heuristics != HR_BULK_REBIAS));
event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
event.commit();
}
return bulk_revoke.status_code();
}
void BiasedLocking::revoke(GrowableArray<Handle>* objs) {
assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");
if (objs->length() == 0) {
return;
}
VM_RevokeBias revoke(objs, JavaThread::current());
VMThread::execute(&revoke);
}
void BiasedLocking::revoke_at_safepoint(Handle h_obj) {
assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");
oop obj = h_obj();
HeuristicsResult heuristics = update_heuristics(obj, false);
if (heuristics == HR_SINGLE_REVOKE) {
revoke_bias(obj, false, false, NULL, NULL);
} else if ((heuristics == HR_BULK_REBIAS) ||
(heuristics == HR_BULK_REVOKE)) {
bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL);
}
clean_up_cached_monitor_info();
}
void BiasedLocking::revoke_at_safepoint(GrowableArray<Handle>* objs) {
assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");
int len = objs->length();
for (int i = 0; i < len; i++) {
oop obj = (objs->at(i))();
HeuristicsResult heuristics = update_heuristics(obj, false);
if (heuristics == HR_SINGLE_REVOKE) {
revoke_bias(obj, false, false, NULL, NULL);
} else if ((heuristics == HR_BULK_REBIAS) ||
(heuristics == HR_BULK_REVOKE)) {
bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL);
}
}
clean_up_cached_monitor_info();
}
void BiasedLocking::preserve_marks() {
if (!UseBiasedLocking)
return;
assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");
assert(_preserved_oop_stack == NULL, "double initialization");
assert(_preserved_mark_stack == NULL, "double initialization");
_preserved_mark_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<markOop>(10, true);
_preserved_oop_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Handle>(10, true);
ResourceMark rm;
Thread* cur = Thread::current();
for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) {
if (thread->has_last_Java_frame()) {
RegisterMap rm(thread);
for (javaVFrame* vf = thread->last_java_vframe(&rm); vf != NULL; vf = vf->java_sender()) {
GrowableArray<MonitorInfo*> *monitors = vf->monitors();
if (monitors != NULL) {
int len = monitors->length();
for (int i = len - 1; i >= 0; i--) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->owner_is_scalar_replaced()) continue;
oop owner = mon_info->owner();
if (owner != NULL) {
markOop mark = owner->mark();
if (mark->has_bias_pattern()) {
_preserved_oop_stack->push(Handle(cur, owner));
_preserved_mark_stack->push(mark);
}
}
}
}
}
}
}
}
void BiasedLocking::restore_marks() {
if (!UseBiasedLocking)
return;
assert(_preserved_oop_stack != NULL, "double free");
assert(_preserved_mark_stack != NULL, "double free");
int len = _preserved_oop_stack->length();
for (int i = 0; i < len; i++) {
Handle owner = _preserved_oop_stack->at(i);
markOop mark = _preserved_mark_stack->at(i);
owner->set_mark(mark);
}
delete _preserved_oop_stack;
_preserved_oop_stack = NULL;
delete _preserved_mark_stack;
_preserved_mark_stack = NULL;
}
int* BiasedLocking::total_entry_count_addr() { return _counters.total_entry_count_addr(); }
int* BiasedLocking::biased_lock_entry_count_addr() { return _counters.biased_lock_entry_count_addr(); }
int* BiasedLocking::anonymously_biased_lock_entry_count_addr() { return _counters.anonymously_biased_lock_entry_count_addr(); }
int* BiasedLocking::rebiased_lock_entry_count_addr() { return _counters.rebiased_lock_entry_count_addr(); }
int* BiasedLocking::revoked_lock_entry_count_addr() { return _counters.revoked_lock_entry_count_addr(); }
int* BiasedLocking::fast_path_entry_count_addr() { return _counters.fast_path_entry_count_addr(); }
int* BiasedLocking::slow_path_entry_count_addr() { return _counters.slow_path_entry_count_addr(); }
int BiasedLockingCounters::slow_path_entry_count() {
if (_slow_path_entry_count != 0) {
return _slow_path_entry_count;
}
int sum = _biased_lock_entry_count + _anonymously_biased_lock_entry_count +
_rebiased_lock_entry_count + _revoked_lock_entry_count +
_fast_path_entry_count;
return _total_entry_count - sum;
}
void BiasedLockingCounters::print_on(outputStream* st) {
tty->print_cr("# total entries: %d", _total_entry_count);
tty->print_cr("# biased lock entries: %d", _biased_lock_entry_count);
tty->print_cr("# anonymously biased lock entries: %d", _anonymously_biased_lock_entry_count);
tty->print_cr("# rebiased lock entries: %d", _rebiased_lock_entry_count);
tty->print_cr("# revoked lock entries: %d", _revoked_lock_entry_count);
tty->print_cr("# fast path lock entries: %d", _fast_path_entry_count);
tty->print_cr("# slow path lock entries: %d", slow_path_entry_count());
}
C:\hotspot-69087d08d473\src\share\vm/runtime/biasedLocking.hpp
#ifndef SHARE_VM_RUNTIME_BIASEDLOCKING_HPP
#define SHARE_VM_RUNTIME_BIASEDLOCKING_HPP
#include "runtime/handles.hpp"
#include "utilities/growableArray.hpp"
class BiasedLockingCounters VALUE_OBJ_CLASS_SPEC {
private:
int _total_entry_count;
int _biased_lock_entry_count;
int _anonymously_biased_lock_entry_count;
int _rebiased_lock_entry_count;
int _revoked_lock_entry_count;
int _fast_path_entry_count;
int _slow_path_entry_count;
public:
BiasedLockingCounters() :
_total_entry_count(0),
_biased_lock_entry_count(0),
_anonymously_biased_lock_entry_count(0),
_rebiased_lock_entry_count(0),
_revoked_lock_entry_count(0),
_fast_path_entry_count(0),
_slow_path_entry_count(0) {}
int slow_path_entry_count(); // Compute this field if necessary
int* total_entry_count_addr() { return &_total_entry_count; }
int* biased_lock_entry_count_addr() { return &_biased_lock_entry_count; }
int* anonymously_biased_lock_entry_count_addr() { return &_anonymously_biased_lock_entry_count; }
int* rebiased_lock_entry_count_addr() { return &_rebiased_lock_entry_count; }
int* revoked_lock_entry_count_addr() { return &_revoked_lock_entry_count; }
int* fast_path_entry_count_addr() { return &_fast_path_entry_count; }
int* slow_path_entry_count_addr() { return &_slow_path_entry_count; }
bool nonzero() { return _total_entry_count > 0; }
void print_on(outputStream* st);
void print() { print_on(tty); }
};
class BiasedLocking : AllStatic {
private:
static BiasedLockingCounters _counters;
public:
static int* total_entry_count_addr();
static int* biased_lock_entry_count_addr();
static int* anonymously_biased_lock_entry_count_addr();
static int* rebiased_lock_entry_count_addr();
static int* revoked_lock_entry_count_addr();
static int* fast_path_entry_count_addr();
static int* slow_path_entry_count_addr();
enum Condition {
NOT_BIASED = 1,
BIAS_REVOKED = 2,
BIAS_REVOKED_AND_REBIASED = 3
};
static void init();
static bool enabled();
static Condition revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS);
static void revoke(GrowableArray<Handle>* objs);
static void revoke_at_safepoint(Handle obj);
static void revoke_at_safepoint(GrowableArray<Handle>* objs);
static void print_counters() { _counters.print(); }
static BiasedLockingCounters* counters() { return &_counters; }
static void preserve_marks();
static void restore_marks();
};
#endif // SHARE_VM_RUNTIME_BIASEDLOCKING_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/compilationPolicy.cpp
#include "precompiled.hpp"
#include "code/compiledIC.hpp"
#include "code/nmethod.hpp"
#include "code/scopeDesc.hpp"
#include "compiler/compilerOracle.hpp"
#include "interpreter/interpreter.hpp"
#include "oops/methodData.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/advancedThresholdPolicy.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/frame.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/rframe.hpp"
#include "runtime/simpleThresholdPolicy.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.hpp"
#include "runtime/timer.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vm_operations.hpp"
#include "utilities/events.hpp"
#include "utilities/globalDefinitions.hpp"
CompilationPolicy* CompilationPolicy::_policy;
elapsedTimer CompilationPolicy::_accumulated_time;
bool CompilationPolicy::_in_vm_startup;
void compilationPolicy_init() {
CompilationPolicy::set_in_vm_startup(DelayCompilationDuringStartup);
switch(CompilationPolicyChoice) {
case 0:
CompilationPolicy::set_policy(new SimpleCompPolicy());
break;
case 1:
#ifdef COMPILER2
CompilationPolicy::set_policy(new StackWalkCompPolicy());
#else
Unimplemented();
#endif
break;
case 2:
#ifdef TIERED
CompilationPolicy::set_policy(new SimpleThresholdPolicy());
#else
Unimplemented();
#endif
break;
case 3:
#ifdef TIERED
CompilationPolicy::set_policy(new AdvancedThresholdPolicy());
#else
Unimplemented();
#endif
break;
default:
fatal("CompilationPolicyChoice must be in the range: [0-3]");
}
CompilationPolicy::policy()->initialize();
}
void CompilationPolicy::completed_vm_startup() {
if (TraceCompilationPolicy) {
tty->print("CompilationPolicy: completed vm startup.\n");
}
_in_vm_startup = false;
}
bool CompilationPolicy::must_be_compiled(methodHandle m, int comp_level) {
if (ReplayCompiles) return false;
if (m->has_compiled_code()) return false; // already compiled
if (!can_be_compiled(m, comp_level)) return false;
return !UseInterpreter || // must compile all methods
(UseCompiler && AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods
}
bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) {
assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
if (m->is_abstract()) return false;
if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
if (!AbstractInterpreter::can_be_compiled(m)) {
return false;
}
if (comp_level == CompLevel_all) {
if (TieredCompilation) {
return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization);
} else {
return !m->is_not_compilable(CompLevel_highest_tier);
}
} else if (is_compile(comp_level)) {
return !m->is_not_compilable(comp_level);
}
return false;
}
bool CompilationPolicy::can_be_osr_compiled(methodHandle m, int comp_level) {
bool result = false;
if (comp_level == CompLevel_all) {
if (TieredCompilation) {
result = !m->is_not_osr_compilable(CompLevel_simple) || !m->is_not_osr_compilable(CompLevel_full_optimization);
} else {
result = !m->is_not_osr_compilable(CompLevel_highest_tier);
}
} else if (is_compile(comp_level)) {
result = !m->is_not_osr_compilable(comp_level);
}
return (result && can_be_compiled(m, comp_level));
}
bool CompilationPolicy::is_compilation_enabled() {
return !delay_compilation_during_startup() && CompileBroker::should_compile_new_jobs();
}
#ifndef PRODUCT
void CompilationPolicy::print_time() {
tty->print_cr ("Accumulated compilationPolicy times:");
tty->print_cr ("---------------------------");
tty->print_cr (" Total: %3.3f sec.", _accumulated_time.seconds());
}
void NonTieredCompPolicy::trace_osr_completion(nmethod* osr_nm) {
if (TraceOnStackReplacement) {
if (osr_nm == NULL) tty->print_cr("compilation failed");
else tty->print_cr("nmethod " INTPTR_FORMAT, p2i(osr_nm));
}
}
#endif // !PRODUCT
void NonTieredCompPolicy::initialize() {
if (CICompilerCountPerCPU) {
_compiler_count = MAX2(log2_int(os::active_processor_count())-1,1);
FLAG_SET_ERGO(intx, CICompilerCount, _compiler_count);
} else {
_compiler_count = CICompilerCount;
}
}
int NonTieredCompPolicy::compiler_count(CompLevel comp_level) {
assert(!TieredCompilation, "This policy should not be used with TieredCompilation");
#ifdef COMPILER2
if (is_c2_compile(comp_level)) {
return _compiler_count;
} else {
return 0;
}
#endif
#ifdef COMPILER1
if (is_c1_compile(comp_level)) {
return _compiler_count;
} else {
return 0;
}
#endif
return 0;
}
void NonTieredCompPolicy::reset_counter_for_invocation_event(methodHandle m) {
MethodCounters* mcs = m->method_counters();
assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
mcs->invocation_counter()->set_carry();
mcs->backedge_counter()->set_carry();
assert(!m->was_never_executed(), "don't reset to 0 -- could be mistaken for never-executed");
}
void NonTieredCompPolicy::reset_counter_for_back_branch_event(methodHandle m) {
MethodCounters* mcs = m->method_counters();
assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
InvocationCounter* i = mcs->invocation_counter();
InvocationCounter* b = mcs->backedge_counter();
i->set(i->state(), CompileThreshold);
b->set(b->state(), CompileThreshold / 2);
}
class CounterDecay : public AllStatic {
static jlong _last_timestamp;
static void do_method(Method* m) {
MethodCounters* mcs = m->method_counters();
if (mcs != NULL) {
mcs->invocation_counter()->decay();
}
}
public:
static void decay();
static bool is_decay_needed() {
return (os::javaTimeMillis() - _last_timestamp) > CounterDecayMinIntervalLength;
}
};
jlong CounterDecay::_last_timestamp = 0;
void CounterDecay::decay() {
_last_timestamp = os::javaTimeMillis();
assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint");
int nclasses = SystemDictionary::number_of_classes();
double classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
CounterHalfLifeTime);
for (int i = 0; i < classes_per_tick; i++) {
Klass* k = SystemDictionary::try_get_next_class();
if (k != NULL && k->oop_is_instance()) {
InstanceKlass::cast(k)->methods_do(do_method);
}
}
}
void NonTieredCompPolicy::do_safepoint_work() {
if(UseCounterDecay && CounterDecay::is_decay_needed()) {
CounterDecay::decay();
}
}
void NonTieredCompPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) {
ScopeDesc* sd = trap_scope;
MethodCounters* mcs;
InvocationCounter* c;
for (; !sd->is_top(); sd = sd->sender()) {
mcs = sd->method()->method_counters();
if (mcs != NULL) {
mcs->invocation_counter()->reset();
}
}
mcs = sd->method()->method_counters();
if (mcs != NULL) {
c = mcs->invocation_counter();
if (is_osr) {
c->set(c->state(), CompileThreshold);
} else {
c->reset();
}
mcs->backedge_counter()->reset();
}
}
void NonTieredCompPolicy::delay_compilation(Method* method) {
MethodCounters* mcs = method->method_counters();
if (mcs != NULL) {
mcs->invocation_counter()->decay();
mcs->backedge_counter()->decay();
}
}
void NonTieredCompPolicy::disable_compilation(Method* method) {
MethodCounters* mcs = method->method_counters();
if (mcs != NULL) {
mcs->invocation_counter()->set_state(InvocationCounter::wait_for_nothing);
mcs->backedge_counter()->set_state(InvocationCounter::wait_for_nothing);
}
}
CompileTask* NonTieredCompPolicy::select_task(CompileQueue* compile_queue) {
return compile_queue->first();
}
bool NonTieredCompPolicy::is_mature(Method* method) {
MethodData* mdo = method->method_data();
assert(mdo != NULL, "Should be");
uint current = mdo->mileage_of(method);
uint initial = mdo->creation_mileage();
if (current < initial)
return true; // some sort of overflow
uint target;
if (ProfileMaturityPercentage <= 0)
target = (uint) -ProfileMaturityPercentage; // absolute value
else
target = (uint)( (ProfileMaturityPercentage * CompileThreshold) / 100 );
return (current >= initial + target);
}
nmethod* NonTieredCompPolicy::event(methodHandle method, methodHandle inlinee, int branch_bci,
int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread) {
assert(comp_level == CompLevel_none, "This should be only called from the interpreter");
NOT_PRODUCT(trace_frequency_counter_overflow(method, branch_bci, bci));
if (JvmtiExport::can_post_interpreter_events() && thread->is_interp_only_mode()) {
if (bci != InvocationEntryBci) {
reset_counter_for_back_branch_event(method);
return NULL;
}
}
if (CompileTheWorld || ReplayCompiles) {
if (bci == InvocationEntryBci) {
reset_counter_for_invocation_event(method);
} else {
reset_counter_for_back_branch_event(method);
}
return NULL;
}
if (bci == InvocationEntryBci) {
if (!method->has_compiled_code() && UseCompiler) {
method_invocation_event(method, thread);
} else {
reset_counter_for_invocation_event(method);
}
return NULL;
} else {
nmethod* osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true);
NOT_PRODUCT(trace_osr_request(method, osr_nm, bci));
if (osr_nm == NULL && UseCompiler) {
method_back_branch_event(method, bci, thread);
osr_nm = method->lookup_osr_nmethod_for(bci, CompLevel_highest_tier, true);
}
if (osr_nm == NULL) {
reset_counter_for_back_branch_event(method);
return NULL;
}
return osr_nm;
}
return NULL;
}
#ifndef PRODUCT
PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL
void NonTieredCompPolicy::trace_frequency_counter_overflow(methodHandle m, int branch_bci, int bci) {
if (TraceInvocationCounterOverflow) {
MethodCounters* mcs = m->method_counters();
assert(mcs != NULL, "MethodCounters cannot be NULL for profiling");
InvocationCounter* ic = mcs->invocation_counter();
InvocationCounter* bc = mcs->backedge_counter();
ResourceMark rm;
const char* msg =
bci == InvocationEntryBci
? "comp-policy cntr ovfl @ %d in entry of "
: "comp-policy cntr ovfl @ %d in loop of ";
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL
tty->print(msg, bci);
PRAGMA_DIAG_POP
m->print_value();
tty->cr();
ic->print();
bc->print();
if (ProfileInterpreter) {
if (bci != InvocationEntryBci) {
MethodData* mdo = m->method_data();
if (mdo != NULL) {
int count = mdo->bci_to_data(branch_bci)->as_JumpData()->taken();
tty->print_cr("back branch count = %d", count);
}
}
}
}
}
void NonTieredCompPolicy::trace_osr_request(methodHandle method, nmethod* osr, int bci) {
if (TraceOnStackReplacement) {
ResourceMark rm;
tty->print(osr != NULL ? "Reused OSR entry for " : "Requesting OSR entry for ");
method->print_short_name(tty);
tty->print_cr(" at bci %d", bci);
}
}
#endif // !PRODUCT
void SimpleCompPolicy::method_invocation_event(methodHandle m, JavaThread* thread) {
const int comp_level = CompLevel_highest_tier;
const int hot_count = m->invocation_count();
reset_counter_for_invocation_event(m);
const char* comment = "count";
if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
nmethod* nm = m->code();
if (nm == NULL ) {
CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, comment, thread);
}
}
}
void SimpleCompPolicy::method_back_branch_event(methodHandle m, int bci, JavaThread* thread) {
const int comp_level = CompLevel_highest_tier;
const int hot_count = m->backedge_count();
const char* comment = "backedge_count";
if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) {
CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
}
}
#ifdef COMPILER2
const char* StackWalkCompPolicy::_msg = NULL;
void StackWalkCompPolicy::method_invocation_event(methodHandle m, JavaThread* thread) {
const int comp_level = CompLevel_highest_tier;
const int hot_count = m->invocation_count();
reset_counter_for_invocation_event(m);
const char* comment = "count";
if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m, comp_level)) {
ResourceMark rm(thread);
frame fr = thread->last_frame();
assert(fr.is_interpreted_frame(), "must be interpreted");
assert(fr.interpreter_frame_method() == m(), "bad method");
if (TraceCompilationPolicy) {
tty->print("method invocation trigger: ");
m->print_short_name(tty);
tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", p2i((address)m()), m->code_size());
}
RegisterMap reg_map(thread, false);
javaVFrame* triggerVF = thread->last_java_vframe(®_map);
RFrame* first = new InterpretedRFrame(triggerVF->fr(), thread, m);
if (first->top_method()->code() != NULL) {
if (TraceCompilationPolicy) tty->print_cr(" --> " INTPTR_FORMAT, p2i(first->top_method()->code()));
} else {
if (TimeCompilationPolicy) accumulated_time()->start();
GrowableArray<RFrame*>* stack = new GrowableArray<RFrame*>(50);
stack->push(first);
RFrame* top = findTopInlinableFrame(stack);
if (TimeCompilationPolicy) accumulated_time()->stop();
assert(top != NULL, "findTopInlinableFrame returned null");
if (TraceCompilationPolicy) top->print();
CompileBroker::compile_method(top->top_method(), InvocationEntryBci, comp_level,
m, hot_count, comment, thread);
}
}
}
void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int bci, JavaThread* thread) {
const int comp_level = CompLevel_highest_tier;
const int hot_count = m->backedge_count();
const char* comment = "backedge_count";
if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) {
CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
}
}
RFrame* StackWalkCompPolicy::findTopInlinableFrame(GrowableArray<RFrame*>* stack) {
RFrame* current = stack->at(0); // current choice for stopping
assert( current && !current->is_compiled(), "" );
const char* msg = NULL;
while (1) {
RFrame* next = senderOf(current, stack);
if( !next ) // No next frame up the stack?
break; // Then compile with current frame
methodHandle m = current->top_method();
methodHandle next_m = next->top_method();
if (TraceCompilationPolicy && Verbose) {
tty->print("[caller: ");
next_m->print_short_name(tty);
tty->print("] ");
}
if( !Inline ) { // Inlining turned off
msg = "Inlining turned off";
break;
}
if (next_m->is_not_compilable()) { // Did fail to compile this before/
msg = "caller not compilable";
break;
}
if (next->num() > MaxRecompilationSearchLength) {
msg = "don't go up any further: > MaxRecompilationSearchLength";
break;
}
if (next->distance() > MaxInterpretedSearchLength) {
msg = "don't go up any further: next > MaxInterpretedSearchLength";
break;
}
if (next->is_compiled()) {
msg = "not going up into optimized code";
break;
}
if( current->is_interpreted() && next_m->has_compiled_code() ) {
msg = "not going up -- already compiled caller";
break;
}
int invcnt = 0; // Caller counts
if (ProfileInterpreter) {
invcnt = next_m->interpreter_invocation_count();
}
int cnt = 0; // Call site counts
if (ProfileInterpreter && next_m->method_data() != NULL) {
ResourceMark rm;
int bci = next->top_vframe()->bci();
ProfileData* data = next_m->method_data()->bci_to_data(bci);
if (data != NULL && data->is_CounterData())
cnt = data->as_CounterData()->count();
}
int freq = (invcnt) ? cnt/invcnt : cnt;
if ((msg = shouldInline(m, freq, cnt)) != NULL) {
break;
}
if ((msg = shouldNotInline(m)) != NULL) {
break;
}
if (!can_be_compiled(next_m, CompLevel_any)) {
msg = "caller cannot be compiled";
break;
}
if( next_m->name() == vmSymbols::class_initializer_name() ) {
msg = "do not compile class initializer (OSR ok)";
break;
}
if (TraceCompilationPolicy && Verbose) {
tty->print("\n\t check caller: ");
next_m->print_short_name(tty);
tty->print(" ( interpreted " INTPTR_FORMAT ", size=%d ) ", p2i((address)next_m()), next_m->code_size());
}
current = next;
}
assert( !current || !current->is_compiled(), "" );
if (TraceCompilationPolicy && msg) tty->print("(%s)\n", msg);
return current;
}
RFrame* StackWalkCompPolicy::senderOf(RFrame* rf, GrowableArray<RFrame*>* stack) {
RFrame* sender = rf->caller();
if (sender && sender->num() == stack->length()) stack->push(sender);
return sender;
}
const char* StackWalkCompPolicy::shouldInline(methodHandle m, float freq, int cnt) {
int max_size = MaxInlineSize;
int cost = m->code_size();
if (m->interpreter_throwout_count() > InlineThrowCount && cost < InlineThrowMaxSize ) {
return NULL;
}
if ((freq >= InlineFrequencyRatio) || (cnt >= InlineFrequencyCount)) {
if (TraceFrequencyInlining) {
tty->print("(Inlined frequent method)\n");
m->print();
}
max_size = FreqInlineSize;
}
if (cost > max_size) {
return (_msg = "too big");
}
return NULL;
}
const char* StackWalkCompPolicy::shouldNotInline(methodHandle m) {
if (m->is_abstract()) return (_msg = "abstract method");
if (!m->method_holder()->is_initialized()) return (_msg = "method holder not initialized");
if (m->is_native()) return (_msg = "native method");
nmethod* m_code = m->code();
if (m_code != NULL && m_code->code_size() > InlineSmallCode)
return (_msg = "already compiled into a big method");
if (m->code_size() <= MaxTrivialSize) return NULL;
if (UseInterpreter) { // don't use counts with -Xcomp
if ((m->code() == NULL) && m->was_never_executed()) return (_msg = "never executed");
if (!m->was_executed_more_than(MIN2(MinInliningThreshold, CompileThreshold >> 1))) return (_msg = "executed < MinInliningThreshold times");
}
if (Method::has_unloaded_classes_in_signature(m, JavaThread::current())) return (_msg = "unloaded signature classes");
return NULL;
}
#endif // COMPILER2
C:\hotspot-69087d08d473\src\share\vm/runtime/compilationPolicy.hpp
#ifndef SHARE_VM_RUNTIME_COMPILATIONPOLICY_HPP
#define SHARE_VM_RUNTIME_COMPILATIONPOLICY_HPP
#include "code/nmethod.hpp"
#include "compiler/compileBroker.hpp"
#include "memory/allocation.hpp"
#include "runtime/vm_operations.hpp"
#include "utilities/growableArray.hpp"
class CompileTask;
class CompileQueue;
class CompilationPolicy : public CHeapObj<mtCompiler> {
static CompilationPolicy* _policy;
static elapsedTimer _accumulated_time;
static bool _in_vm_startup;
public:
static void set_in_vm_startup(bool in_vm_startup) { _in_vm_startup = in_vm_startup; }
static void completed_vm_startup();
static bool delay_compilation_during_startup() { return _in_vm_startup; }
static bool must_be_compiled(methodHandle m, int comp_level = CompLevel_all);
static bool can_be_compiled(methodHandle m, int comp_level = CompLevel_all);
static bool can_be_osr_compiled(methodHandle m, int comp_level = CompLevel_all);
static bool is_compilation_enabled();
static void set_policy(CompilationPolicy* policy) { _policy = policy; }
static CompilationPolicy* policy() { return _policy; }
elapsedTimer* accumulated_time() { return &_accumulated_time; }
void print_time() PRODUCT_RETURN;
virtual CompLevel initial_compile_level() = 0;
virtual int compiler_count(CompLevel comp_level) = 0;
virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread) = 0;
virtual void do_safepoint_work() = 0;
virtual void reprofile(ScopeDesc* trap_scope, bool is_osr) = 0;
virtual void delay_compilation(Method* method) = 0;
virtual void disable_compilation(Method* method) = 0;
virtual CompileTask* select_task(CompileQueue* compile_queue) = 0;
virtual bool is_mature(Method* method) = 0;
virtual void initialize() = 0;
virtual bool should_not_inline(ciEnv* env, ciMethod* method) { return false; }
};
class NonTieredCompPolicy : public CompilationPolicy {
int _compiler_count;
protected:
static void trace_frequency_counter_overflow(methodHandle m, int branch_bci, int bci);
static void trace_osr_request(methodHandle method, nmethod* osr, int bci);
static void trace_osr_completion(nmethod* osr_nm);
void reset_counter_for_invocation_event(methodHandle method);
void reset_counter_for_back_branch_event(methodHandle method);
public:
NonTieredCompPolicy() : _compiler_count(0) { }
virtual CompLevel initial_compile_level() { return CompLevel_highest_tier; }
virtual int compiler_count(CompLevel comp_level);
virtual void do_safepoint_work();
virtual void reprofile(ScopeDesc* trap_scope, bool is_osr);
virtual void delay_compilation(Method* method);
virtual void disable_compilation(Method* method);
virtual bool is_mature(Method* method);
virtual void initialize();
virtual CompileTask* select_task(CompileQueue* compile_queue);
virtual nmethod* event(methodHandle method, methodHandle inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, JavaThread* thread);
virtual void method_invocation_event(methodHandle m, JavaThread* thread) = 0;
virtual void method_back_branch_event(methodHandle m, int bci, JavaThread* thread) = 0;
};
class SimpleCompPolicy : public NonTieredCompPolicy {
public:
virtual void method_invocation_event(methodHandle m, JavaThread* thread);
virtual void method_back_branch_event(methodHandle m, int bci, JavaThread* thread);
};
#ifdef COMPILER2
class StackWalkCompPolicy : public NonTieredCompPolicy {
public:
virtual void method_invocation_event(methodHandle m, JavaThread* thread);
virtual void method_back_branch_event(methodHandle m, int bci, JavaThread* thread);
private:
RFrame* findTopInlinableFrame(GrowableArray<RFrame*>* stack);
RFrame* senderOf(RFrame* rf, GrowableArray<RFrame*>* stack);
static const char* _msg; // reason for not inlining
static const char* shouldInline (methodHandle callee, float frequency, int cnt);
static const char* shouldNotInline(methodHandle callee);
};
#endif
#endif // SHARE_VM_RUNTIME_COMPILATIONPOLICY_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/deoptimization.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/debugInfoRec.hpp"
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
#include "code/scopeDesc.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vframeArray.hpp"
#include "runtime/vframe_hp.hpp"
#include "utilities/events.hpp"
#include "utilities/xmlstream.hpp"
#ifdef TARGET_ARCH_x86
# include "vmreg_x86.inline.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "vmreg_aarch64.inline.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "vmreg_sparc.inline.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "vmreg_zero.inline.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "vmreg_arm.inline.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "vmreg_ppc.inline.hpp"
#endif
#ifdef COMPILER2
#if defined AD_MD_HPP
# include AD_MD_HPP
#elif defined TARGET_ARCH_MODEL_x86_32
# include "adfiles/ad_x86_32.hpp"
#elif defined TARGET_ARCH_MODEL_x86_64
# include "adfiles/ad_x86_64.hpp"
#elif defined TARGET_ARCH_MODEL_aarch64
# include "adfiles/ad_aarch64.hpp"
#elif defined TARGET_ARCH_MODEL_sparc
# include "adfiles/ad_sparc.hpp"
#elif defined TARGET_ARCH_MODEL_zero
# include "adfiles/ad_zero.hpp"
#elif defined TARGET_ARCH_MODEL_ppc_64
# include "adfiles/ad_ppc_64.hpp"
#endif
#endif // COMPILER2
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
bool DeoptimizationMarker::_is_active = false;
Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame,
int caller_adjustment,
int caller_actual_parameters,
int number_of_frames,
intptr_t* frame_sizes,
address* frame_pcs,
BasicType return_type) {
_size_of_deoptimized_frame = size_of_deoptimized_frame;
_caller_adjustment = caller_adjustment;
_caller_actual_parameters = caller_actual_parameters;
_number_of_frames = number_of_frames;
_frame_sizes = frame_sizes;
_frame_pcs = frame_pcs;
_register_block = NEW_C_HEAP_ARRAY(intptr_t, RegisterMap::reg_count * 2, mtCompiler);
_return_type = return_type;
_initial_info = 0;
_counter_temp = 0;
_unpack_kind = 0;
_sender_sp_temp = 0;
_total_frame_sizes = size_of_frames();
}
Deoptimization::UnrollBlock::~UnrollBlock() {
FREE_C_HEAP_ARRAY(intptr_t, _frame_sizes, mtCompiler);
FREE_C_HEAP_ARRAY(intptr_t, _frame_pcs, mtCompiler);
FREE_C_HEAP_ARRAY(intptr_t, _register_block, mtCompiler);
}
intptr_t* Deoptimization::UnrollBlock::value_addr_at(int register_number) const {
assert(register_number < RegisterMap::reg_count, "checking register number");
return &_register_block[register_number * 2];
}
int Deoptimization::UnrollBlock::size_of_frames() const {
int result = _caller_adjustment;
for (int index = 0; index < number_of_frames(); index++) {
result += frame_sizes()[index];
}
return result;
}
void Deoptimization::UnrollBlock::print() {
ttyLocker ttyl;
tty->print_cr("UnrollBlock");
tty->print_cr(" size_of_deoptimized_frame = %d", _size_of_deoptimized_frame);
tty->print( " frame_sizes: ");
for (int index = 0; index < number_of_frames(); index++) {
tty->print("%d ", frame_sizes()[index]);
}
tty->cr();
}
JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(JavaThread* thread))
thread->inc_in_deopt_handler();
return fetch_unroll_info_helper(thread);
JRT_END
Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread) {
DeoptResourceMark* dmark = new DeoptResourceMark(thread);
assert(thread->deopt_mark() == NULL, "Pending deopt!");
thread->set_deopt_mark(dmark);
frame stub_frame = thread->last_frame(); // Makes stack walkable as side effect
RegisterMap map(thread, true);
RegisterMap dummy_map(thread, false);
frame deoptee = stub_frame.sender(&map);
assert(thread->deopt_nmethod() == NULL, "Pending deopt!");
thread->set_deopt_nmethod(deoptee.cb()->as_nmethod_or_null());
if (VerifyStack) {
thread->validate_frame_layout();
}
assert(deoptee.is_compiled_frame(), "Wrong frame type");
GrowableArray<compiledVFrame*>* chunk = new GrowableArray<compiledVFrame*>(10);
vframe* vf = vframe::new_vframe(&deoptee, &map, thread);
while (!vf->is_top()) {
assert(vf->is_compiled_frame(), "Wrong frame type");
chunk->push(compiledVFrame::cast(vf));
vf = vf->sender();
}
assert(vf->is_compiled_frame(), "Wrong frame type");
chunk->push(compiledVFrame::cast(vf));
bool realloc_failures = false;
#ifdef COMPILER2
if (DoEscapeAnalysis || EliminateNestedLocks) {
if (EliminateAllocations) {
assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames");
GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution();
Handle return_value;
if (save_oop_result) {
oop result = deoptee.saved_oop_result(&map);
assert(result == NULL || result->is_oop(), "must be oop");
return_value = Handle(thread, result);
assert(Universe::heap()->is_in_or_null(result), "must be heap pointer");
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread);
}
}
if (objects != NULL) {
JRT_BLOCK
realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
JRT_END
reassign_fields(&deoptee, &map, objects, realloc_failures);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
print_objects(objects, realloc_failures);
}
#endif
}
if (save_oop_result) {
deoptee.set_saved_oop_result(&map, return_value());
}
}
if (EliminateLocks) {
#ifndef PRODUCT
bool first = true;
#endif
for (int i = 0; i < chunk->length(); i++) {
compiledVFrame* cvf = chunk->at(i);
assert (cvf->scope() != NULL,"expect only compiled java frames");
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
if (monitors->is_nonempty()) {
relock_objects(monitors, thread, realloc_failures);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
for (int j = 0; j < monitors->length(); j++) {
MonitorInfo* mi = monitors->at(j);
if (mi->eliminated()) {
if (first) {
first = false;
tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread);
}
if (mi->owner_is_scalar_replaced()) {
Klass* k = java_lang_Class::as_Klass(mi->owner_klass());
tty->print_cr(" failed reallocation for klass %s", k->external_name());
} else {
tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner());
}
}
}
}
#endif
}
}
}
}
#endif // COMPILER2
No_Safepoint_Verifier no_safepoint;
vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures);
#ifdef COMPILER2
if (realloc_failures) {
pop_frames_failed_reallocs(thread, array);
}
#endif
assert(thread->vframe_array_head() == NULL, "Pending deopt!");
thread->set_vframe_array_head(array);
if (thread->deferred_locals() != NULL) {
GrowableArray<jvmtiDeferredLocalVariableSet*>* list = thread->deferred_locals();
int i = 0;
do {
if (list->at(i)->id() == array->original().id()) {
jvmtiDeferredLocalVariableSet* dlv = list->at(i);
list->remove_at(i);
delete dlv;
} else {
i++;
}
} while ( i < list->length() );
if (list->length() == 0) {
thread->set_deferred_locals(NULL);
delete list;
}
}
#ifndef SHARK
CodeBlob* cb = stub_frame.cb();
assert(cb->frame_size() >= 0, "Unexpected frame size");
intptr_t* unpack_sp = stub_frame.sp() + cb->frame_size();
nmethod* deoptee_nm = deoptee.cb()->as_nmethod_or_null();
if (deoptee_nm != NULL && deoptee_nm->is_method_handle_return(deoptee.pc()))
unpack_sp = deoptee.unextended_sp();
#ifdef ASSERT
assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking");
#endif
#else
intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp();
#endif // !SHARK
guarantee(array->unextended_sp() == unpack_sp, "vframe_array_head must contain the vframeArray to unpack");
int number_of_frames = array->frames();
intptr_t* frame_sizes = NEW_C_HEAP_ARRAY(intptr_t, number_of_frames, mtCompiler);
address* frame_pcs = NEW_C_HEAP_ARRAY(address, number_of_frames + 1, mtCompiler);
int popframe_extra_args = 0;
frame_pcs[number_of_frames] = Interpreter::deopt_entry(vtos, 0);
if (JvmtiExport::can_pop_frame() && thread->popframe_forcing_deopt_reexecution()) {
popframe_extra_args = in_words(thread->popframe_preserved_args_size_in_words());
}
frame deopt_sender = stub_frame.sender(&dummy_map); // First is the deoptee frame
deopt_sender = deopt_sender.sender(&dummy_map); // Now deoptee caller
bool caller_was_method_handle = false;
if (deopt_sender.is_interpreted_frame()) {
methodHandle method = deopt_sender.interpreter_frame_method();
Bytecode_invoke cur = Bytecode_invoke_check(method, deopt_sender.interpreter_frame_bci());
if (cur.is_invokedynamic() || cur.is_invokehandle()) {
caller_was_method_handle = true;
}
}
int callee_parameters = 0;
int callee_locals = 0;
for (int index = 0; index < array->frames(); index++ ) {
frame_sizes[number_of_frames - 1 - index] = BytesPerWord * array->element(index)->on_stack_size(callee_parameters,
callee_locals,
index == 0,
popframe_extra_args);
frame_pcs[number_of_frames - 1 - index ] = Interpreter::deopt_entry(vtos, 0) - frame::pc_return_offset;
callee_parameters = array->element(index)->method()->size_of_parameters();
callee_locals = array->element(index)->method()->max_locals();
popframe_extra_args = 0;
}
BasicType return_type;
{
HandleMark hm;
methodHandle method(thread, array->element(0)->method());
Bytecode_invoke invoke = Bytecode_invoke_check(method, array->element(0)->bci());
return_type = invoke.is_valid() ? invoke.result_type() : T_ILLEGAL;
}
int caller_adjustment = 0;
if (deopt_sender.is_compiled_frame() || caller_was_method_handle) {
caller_adjustment = last_frame_adjust(0, callee_locals);
} else if (callee_locals > callee_parameters) {
caller_adjustment = last_frame_adjust(callee_parameters, callee_locals);
}
frame_pcs[0] = deopt_sender.raw_pc();
#ifndef SHARK
assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc");
#endif // SHARK
UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord,
caller_adjustment * BytesPerWord,
caller_was_method_handle ? 0 : callee_parameters,
number_of_frames,
frame_sizes,
frame_pcs,
return_type);
info->set_initial_info((intptr_t) array->sender().initial_deoptimization_info());
if (array->frames() > 1) {
if (VerifyStack && TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("Deoptimizing method containing inlining");
}
}
array->set_unroll_block(info);
return info;
}
void Deoptimization::cleanup_deopt_info(JavaThread *thread,
vframeArray *array) {
if (array == NULL) {
array = thread->vframe_array_head();
}
thread->set_vframe_array_head(NULL);
vframeArray* old_array = thread->vframe_array_last();
thread->set_vframe_array_last(array);
if (old_array != NULL) {
UnrollBlock* old_info = old_array->unroll_block();
old_array->set_unroll_block(NULL);
delete old_info;
delete old_array;
}
delete thread->deopt_mark();
thread->set_deopt_mark(NULL);
thread->set_deopt_nmethod(NULL);
if (JvmtiExport::can_pop_frame()) {
#ifndef CC_INTERP
thread->clear_popframe_condition();
#else
if (thread->popframe_forcing_deopt_reexecution())
thread->clear_popframe_condition();
#endif /* CC_INTERP */
}
thread->dec_in_deopt_handler();
}
JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_mode))
ResetNoHandleMark rnhm; // No-op in release/product versions
HandleMark hm;
frame stub_frame = thread->last_frame();
vframeArray* array = thread->vframe_array_head();
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("DEOPT UNPACKING thread " INTPTR_FORMAT " vframeArray " INTPTR_FORMAT " mode %d", thread, array, exec_mode);
}
#endif
Events::log(thread, "DEOPT UNPACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT " mode %d",
stub_frame.pc(), stub_frame.sp(), exec_mode);
UnrollBlock* info = array->unroll_block();
array->unpack_to_stack(stub_frame, exec_mode, info->caller_actual_parameters());
BasicType bt = info->return_type();
if (exec_mode == Unpack_exception)
bt = T_OBJECT;
cleanup_deopt_info(thread, array);
#ifndef PRODUCT
if (VerifyStack) {
ResourceMark res_mark;
thread->validate_frame_layout();
vframeArray* cur_array = thread->vframe_array_last();
RegisterMap rm(thread, false);
rm.set_include_argument_oops(false);
bool is_top_frame = true;
int callee_size_of_parameters = 0;
int callee_max_locals = 0;
for (int i = 0; i < cur_array->frames(); i++) {
vframeArrayElement* el = cur_array->element(i);
frame* iframe = el->iframe();
guarantee(iframe->is_interpreted_frame(), "Wrong frame type");
InterpreterOopMap mask;
int cur_invoke_parameter_size = 0;
bool try_next_mask = false;
int next_mask_expression_stack_size = -1;
int top_frame_expression_stack_adjustment = 0;
methodHandle mh(thread, iframe->interpreter_frame_method());
OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask);
BytecodeStream str(mh);
str.set_start(iframe->interpreter_frame_bci());
int max_bci = mh->code_size();
assert(str.bci() < max_bci, "bci in interpreter frame out of bounds");
Bytecodes::Code cur_code = str.next();
if (cur_code == Bytecodes::_invokevirtual ||
cur_code == Bytecodes::_invokespecial ||
cur_code == Bytecodes::_invokestatic ||
cur_code == Bytecodes::_invokeinterface ||
cur_code == Bytecodes::_invokedynamic) {
Bytecode_invoke invoke(mh, iframe->interpreter_frame_bci());
Symbol* signature = invoke.signature();
ArgumentSizeComputer asc(signature);
cur_invoke_parameter_size = asc.size();
if (invoke.has_receiver()) {
++cur_invoke_parameter_size;
}
if (i != 0 && !invoke.is_invokedynamic() && MethodHandles::has_member_arg(invoke.klass(), invoke.name())) {
callee_size_of_parameters++;
}
}
if (str.bci() < max_bci) {
Bytecodes::Code bc = str.next();
if (bc >= 0) {
switch (cur_code) {
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokeinterface:
case Bytecodes::_invokedynamic:
case Bytecodes::_athrow:
break;
default: {
InterpreterOopMap next_mask;
OopMapCache::compute_one_oop_map(mh, str.bci(), &next_mask);
next_mask_expression_stack_size = next_mask.expression_stack_size();
BasicType bytecode_result_type = Bytecodes::result_type(cur_code);
if (bytecode_result_type != T_ILLEGAL) {
top_frame_expression_stack_adjustment = type2size[bytecode_result_type];
}
assert(top_frame_expression_stack_adjustment >= 0, "");
try_next_mask = true;
break;
}
}
}
}
if (!(
(iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + callee_size_of_parameters) ||
(iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + callee_max_locals) ||
(try_next_mask &&
(iframe->interpreter_frame_expression_stack_size() == (next_mask_expression_stack_size -
top_frame_expression_stack_adjustment))) ||
(is_top_frame && (exec_mode == Unpack_exception) && iframe->interpreter_frame_expression_stack_size() == 0) ||
(is_top_frame && (exec_mode == Unpack_uncommon_trap || exec_mode == Unpack_reexecute || el->should_reexecute()) &&
(iframe->interpreter_frame_expression_stack_size() == mask.expression_stack_size() + cur_invoke_parameter_size))
)) {
ttyLocker ttyl;
tty->print_cr("Wrong number of expression stack elements during deoptimization");
tty->print_cr(" Error occurred while verifying frame %d (0..%d, 0 is topmost)", i, cur_array->frames() - 1);
tty->print_cr(" Fabricated interpreter frame had %d expression stack elements",
iframe->interpreter_frame_expression_stack_size());
tty->print_cr(" Interpreter oop map had %d expression stack elements", mask.expression_stack_size());
tty->print_cr(" try_next_mask = %d", try_next_mask);
tty->print_cr(" next_mask_expression_stack_size = %d", next_mask_expression_stack_size);
tty->print_cr(" callee_size_of_parameters = %d", callee_size_of_parameters);
tty->print_cr(" callee_max_locals = %d", callee_max_locals);
tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment);
tty->print_cr(" exec_mode = %d", exec_mode);
tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size);
tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = " UINTX_FORMAT, thread, thread->osthread()->thread_id());
tty->print_cr(" Interpreted frames:");
for (int k = 0; k < cur_array->frames(); k++) {
vframeArrayElement* el = cur_array->element(k);
tty->print_cr(" %s (bci %d)", el->method()->name_and_sig_as_C_string(), el->bci());
}
cur_array->print_on_2(tty);
guarantee(false, "wrong number of expression stack elements during deopt");
}
VerifyOopClosure verify;
iframe->oops_interpreted_do(&verify, NULL, &rm, false);
callee_size_of_parameters = mh->size_of_parameters();
callee_max_locals = mh->max_locals();
is_top_frame = false;
}
}
#endif /* !PRODUCT */
return bt;
JRT_END
int Deoptimization::deoptimize_dependents() {
Threads::deoptimized_wrt_marked_nmethods();
return 0;
}
#ifdef COMPILER2
bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS) {
Handle pending_exception(thread->pending_exception());
const char* exception_file = thread->exception_file();
int exception_line = thread->exception_line();
thread->clear_pending_exception();
bool failures = false;
for (int i = 0; i < objects->length(); i++) {
assert(objects->at(i)->is_object(), "invalid debug information");
ObjectValue* sv = (ObjectValue*) objects->at(i);
KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()));
oop obj = NULL;
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k());
obj = ik->allocate_instance(THREAD);
} else if (k->oop_is_typeArray()) {
TypeArrayKlass* ak = TypeArrayKlass::cast(k());
assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length");
int len = sv->field_size() / type2size[ak->element_type()];
obj = ak->allocate(len, THREAD);
} else if (k->oop_is_objArray()) {
ObjArrayKlass* ak = ObjArrayKlass::cast(k());
obj = ak->allocate(sv->field_size(), THREAD);
}
if (obj == NULL) {
failures = true;
}
assert(sv->value().is_null(), "redundant reallocation");
assert(obj != NULL || HAS_PENDING_EXCEPTION, "allocation should succeed or we should get an exception");
CLEAR_PENDING_EXCEPTION;
sv->set_value(obj);
}
if (failures) {
THROW_OOP_(Universe::out_of_memory_error_realloc_objects(), failures);
} else if (pending_exception.not_null()) {
thread->set_pending_exception(pending_exception(), exception_file, exception_line);
}
return failures;
}
class FieldReassigner: public FieldClosure {
frame* _fr;
RegisterMap* _reg_map;
ObjectValue* _sv;
InstanceKlass* _ik;
oop _obj;
int _i;
public:
FieldReassigner(frame* fr, RegisterMap* reg_map, ObjectValue* sv, oop obj) :
_fr(fr), _reg_map(reg_map), _sv(sv), _obj(obj), _i(0) {}
int i() const { return _i; }
void do_field(fieldDescriptor* fd) {
intptr_t val;
StackValue* value =
StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i()));
int offset = fd->offset();
switch (fd->field_type()) {
case T_OBJECT: case T_ARRAY:
assert(value->type() == T_OBJECT, "Agreement.");
_obj->obj_field_put(offset, value->get_obj()());
break;
case T_LONG: case T_DOUBLE: {
assert(value->type() == T_INT, "Agreement.");
StackValue* low =
StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i));
#ifdef _LP64
jlong res = (jlong)low->get_int();
#else
#ifdef SPARC
jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int());
#else
jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int());
#endif //SPARC
#endif
_obj->long_field_put(offset, res);
break;
}
case T_INT: case T_FLOAT: // 4 bytes.
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
_obj->int_field_put(offset, (jint)*((jint*)&val));
break;
case T_SHORT:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
_obj->short_field_put(offset, (jshort)*((jint*)&val));
break;
case T_CHAR:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
_obj->char_field_put(offset, (jchar)*((jint*)&val));
break;
case T_BYTE:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
_obj->byte_field_put(offset, (jbyte)*((jint*)&val));
break;
case T_BOOLEAN:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
_obj->bool_field_put(offset, (jboolean)*((jint*)&val));
break;
default:
ShouldNotReachHere();
}
_i++;
}
};
void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) {
int index = 0;
intptr_t val;
for (int i = 0; i < sv->field_size(); i++) {
StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(i));
switch(type) {
case T_LONG: case T_DOUBLE: {
assert(value->type() == T_INT, "Agreement.");
StackValue* low =
StackValue::create_stack_value(fr, reg_map, sv->field_at(++i));
#ifdef _LP64
jlong res = (jlong)low->get_int();
#else
#ifdef SPARC
jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int());
#else
jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int());
#endif //SPARC
#endif
obj->long_at_put(index, res);
break;
}
case T_INT: case T_FLOAT: // 4 bytes.
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
obj->int_at_put(index, (jint)*((jint*)&val));
break;
case T_SHORT:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
obj->short_at_put(index, (jshort)*((jint*)&val));
break;
case T_CHAR:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
obj->char_at_put(index, (jchar)*((jint*)&val));
break;
case T_BYTE:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
obj->byte_at_put(index, (jbyte)*((jint*)&val));
break;
case T_BOOLEAN:
assert(value->type() == T_INT, "Agreement.");
val = value->get_int();
obj->bool_at_put(index, (jboolean)*((jint*)&val));
break;
default:
ShouldNotReachHere();
}
index++;
}
}
void Deoptimization::reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj) {
for (int i = 0; i < sv->field_size(); i++) {
StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(i));
assert(value->type() == T_OBJECT, "object element expected");
obj->obj_at_put(i, value->get_obj()());
}
}
void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
for (int i = 0; i < objects->length(); i++) {
ObjectValue* sv = (ObjectValue*) objects->at(i);
KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()));
Handle obj = sv->value();
assert(obj.not_null() || realloc_failures, "reallocation was missed");
if (obj.is_null()) {
continue;
}
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k());
FieldReassigner reassign(fr, reg_map, sv, obj());
ik->do_nonstatic_fields(&reassign);
} else if (k->oop_is_typeArray()) {
TypeArrayKlass* ak = TypeArrayKlass::cast(k());
reassign_type_array_elements(fr, reg_map, sv, (typeArrayOop) obj(), ak->element_type());
} else if (k->oop_is_objArray()) {
reassign_object_array_elements(fr, reg_map, sv, (objArrayOop) obj());
}
}
}
void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures) {
for (int i = 0; i < monitors->length(); i++) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->eliminated()) {
assert(!mon_info->owner_is_scalar_replaced() || realloc_failures, "reallocation was missed");
if (!mon_info->owner_is_scalar_replaced()) {
Handle obj = Handle(mon_info->owner());
markOop mark = obj->mark();
if (UseBiasedLocking && mark->has_bias_pattern()) {
assert(mark->is_biased_anonymously() ||
mark->biased_locker() == thread, "should be locked to current thread");
markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
obj->set_mark(unbiased_prototype);
}
BasicLock* lock = mon_info->lock();
ObjectSynchronizer::slow_enter(obj, lock, thread);
assert(mon_info->owner()->is_locked(), "object must be locked now");
}
}
}
}
#ifndef PRODUCT
void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
fieldDescriptor fd;
for (int i = 0; i < objects->length(); i++) {
ObjectValue* sv = (ObjectValue*) objects->at(i);
KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()));
Handle obj = sv->value();
tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()());
k->print_value();
assert(obj.not_null() || realloc_failures, "reallocation was missed");
if (obj.is_null()) {
tty->print(" allocation failed");
} else {
tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize);
}
tty->cr();
if (Verbose && !obj.is_null()) {
k->oop_print_on(obj(), tty);
}
}
}
#endif
#endif // COMPILER2
vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) {
Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp());
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", thread);
fr.print_on(tty);
tty->print_cr(" Virtual frames (innermost first):");
for (int index = 0; index < chunk->length(); index++) {
compiledVFrame* vf = chunk->at(index);
tty->print(" %2d - ", index);
vf->print_value();
int bci = chunk->at(index)->raw_bci();
const char* code_name;
if (bci == SynchronizationEntryBCI) {
code_name = "sync entry";
} else {
Bytecodes::Code code = vf->method()->code_at(bci);
code_name = Bytecodes::name(code);
}
tty->print(" - %s", code_name);
tty->print_cr(" @ bci %d ", bci);
if (Verbose) {
vf->print();
tty->cr();
}
}
}
#endif
frame caller = fr.sender(reg_map);
int frame_size = caller.sp() - fr.sp();
frame sender = caller;
vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr, realloc_failures);
assert(array->structural_compare(thread, chunk), "just checking");
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr(" Created vframeArray " INTPTR_FORMAT, array);
}
#endif // PRODUCT
return array;
}
#ifdef COMPILER2
void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) {
assert(thread->frames_to_pop_failed_realloc() == 0, "missed frames to pop?");
thread->set_frames_to_pop_failed_realloc(array->frames());
for (int i = 0; i < array->frames(); i++) {
MonitorChunk* monitors = array->element(i)->monitors();
if (monitors != NULL) {
for (int j = 0; j < monitors->number_of_monitors(); j++) {
BasicObjectLock* src = monitors->at(j);
if (src->obj() != NULL) {
ObjectSynchronizer::fast_exit(src->obj(), src->lock(), thread);
}
}
array->element(i)->free_monitors(thread);
#ifdef ASSERT
array->element(i)->set_removed_monitors();
#endif
}
}
}
#endif
static void collect_monitors(compiledVFrame* cvf, GrowableArray<Handle>* objects_to_revoke) {
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
for (int i = 0; i < monitors->length(); i++) {
MonitorInfo* mon_info = monitors->at(i);
if (!mon_info->eliminated() && mon_info->owner() != NULL) {
objects_to_revoke->append(Handle(mon_info->owner()));
}
}
}
void Deoptimization::revoke_biases_of_monitors(JavaThread* thread, frame fr, RegisterMap* map) {
if (!UseBiasedLocking) {
return;
}
GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
if (map == NULL || !map->update_map()) {
StackFrameStream sfs(thread, true);
bool found = false;
while (!found && !sfs.is_done()) {
frame* cur = sfs.current();
sfs.next();
found = cur->id() == fr.id();
}
assert(found, "frame to be deoptimized not found on target thread's stack");
map = sfs.register_map();
}
vframe* vf = vframe::new_vframe(&fr, map, thread);
compiledVFrame* cvf = compiledVFrame::cast(vf);
while (!cvf->is_top()) {
collect_monitors(cvf, objects_to_revoke);
cvf = compiledVFrame::cast(cvf->sender());
}
collect_monitors(cvf, objects_to_revoke);
if (SafepointSynchronize::is_at_safepoint()) {
BiasedLocking::revoke_at_safepoint(objects_to_revoke);
} else {
BiasedLocking::revoke(objects_to_revoke);
}
}
void Deoptimization::revoke_biases_of_monitors(CodeBlob* cb) {
if (!UseBiasedLocking) {
return;
}
assert(SafepointSynchronize::is_at_safepoint(), "must only be called from safepoint");
GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
for (JavaThread* jt = Threads::first(); jt != NULL ; jt = jt->next()) {
if (jt->has_last_Java_frame()) {
StackFrameStream sfs(jt, true);
while (!sfs.is_done()) {
frame* cur = sfs.current();
if (cb->contains(cur->pc())) {
vframe* vf = vframe::new_vframe(cur, sfs.register_map(), jt);
compiledVFrame* cvf = compiledVFrame::cast(vf);
while (!cvf->is_top()) {
collect_monitors(cvf, objects_to_revoke);
cvf = compiledVFrame::cast(cvf->sender());
}
collect_monitors(cvf, objects_to_revoke);
}
sfs.next();
}
}
}
BiasedLocking::revoke_at_safepoint(objects_to_revoke);
}
void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) {
assert(fr.can_be_deoptimized(), "checking frame type");
gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal);
fr.deoptimize(thread);
}
void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) {
if (!fr.is_compiled_frame() || fr.is_deoptimized_frame()) {
return;
}
ResourceMark rm;
DeoptimizationMarker dm;
if (UseBiasedLocking) {
revoke_biases_of_monitors(thread, fr, map);
}
deoptimize_single_frame(thread, fr);
}
void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) {
assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(),
"can only deoptimize other thread at a safepoint");
RegisterMap reg_map(thread, UseBiasedLocking);
frame fr = thread->last_frame();
while (fr.id() != id) {
fr = fr.sender(®_map);
}
deoptimize(thread, fr, ®_map);
}
void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) {
if (thread == Thread::current()) {
Deoptimization::deoptimize_frame_internal(thread, id);
} else {
VM_DeoptimizeFrame deopt(thread, id);
VMThread::execute(&deopt);
}
}
JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address))
{
thread->popframe_preserve_args(in_ByteSize(bytes_to_save), start_address);
}
JRT_END
#if defined(COMPILER2) || defined(SHARK)
void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) {
if (constant_pool->tag_at(index).is_unresolved_klass()) {
Klass* tk = constant_pool->klass_at(index, CHECK);
return;
}
if (!constant_pool->tag_at(index).is_symbol()) return;
Handle class_loader (THREAD, constant_pool->pool_holder()->class_loader());
Symbol* symbol = constant_pool->symbol_at(index);
if (symbol->byte_at(0) != '(') {
Handle protection_domain (THREAD, constant_pool->pool_holder()->protection_domain());
SystemDictionary::resolve_or_null(symbol, class_loader, protection_domain, CHECK);
return;
}
ResourceMark rm(THREAD);
for (SignatureStream ss(symbol); !ss.is_done(); ss.next()) {
if (ss.is_object()) {
Symbol* class_name = ss.as_symbol(CHECK);
Handle protection_domain (THREAD, constant_pool->pool_holder()->protection_domain());
SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK);
}
}
}
void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index) {
EXCEPTION_MARK;
load_class_by_index(constant_pool, index, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
assert(THREAD->is_Java_thread(), "only a java thread can be here");
JavaThread* thread = (JavaThread*)THREAD;
bool guard_pages_enabled = thread->stack_yellow_zone_enabled();
if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack();
assert(guard_pages_enabled, "stack banging in uncommon trap blob may cause crash");
}
}
JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint trap_request)) {
HandleMark hm;
thread->inc_in_deopt_handler();
RegisterMap reg_map(thread, UseBiasedLocking);
frame stub_frame = thread->last_frame();
frame fr = stub_frame.sender(®_map);
nmethodLocker nl(fr.pc());
Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT,
trap_request, fr.pc());
{
ResourceMark rm;
revoke_biases_of_monitors(thread, fr, ®_map);
DeoptReason reason = trap_request_reason(trap_request);
DeoptAction action = trap_request_action(trap_request);
jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1
vframe* vf = vframe::new_vframe(&fr, ®_map, thread);
compiledVFrame* cvf = compiledVFrame::cast(vf);
nmethod* nm = cvf->code();
ScopeDesc* trap_scope = cvf->scope();
methodHandle trap_method = trap_scope->method();
int trap_bci = trap_scope->bci();
Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci);
gather_statistics(reason, action, trap_bc);
bool create_if_missing = ProfileTraps RTM_OPT_ONLY( || UseRTMLocking );
MethodData* trap_mdo =
get_method_data(thread, trap_method, create_if_missing);
Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d",
trap_reason_name(reason), trap_action_name(action), fr.pc(),
trap_method->name_and_sig_as_C_string(), trap_bci);
if (TraceDeoptimization || LogCompilation) {
ResourceMark rm;
ttyLocker ttyl;
char buf[100];
if (xtty != NULL) {
xtty->begin_head("uncommon_trap thread='" UINTX_FORMAT "' %s",
os::current_thread_id(),
format_trap_request(buf, sizeof(buf), trap_request));
nm->log_identity(xtty);
}
Symbol* class_name = NULL;
bool unresolved = false;
if (unloaded_class_index >= 0) {
constantPoolHandle constants (THREAD, trap_method->constants());
if (constants->tag_at(unloaded_class_index).is_unresolved_klass()) {
class_name = constants->klass_name_at(unloaded_class_index);
unresolved = true;
if (xtty != NULL)
xtty->print(" unresolved='1'");
} else if (constants->tag_at(unloaded_class_index).is_symbol()) {
class_name = constants->symbol_at(unloaded_class_index);
}
if (xtty != NULL)
xtty->name(class_name);
}
if (xtty != NULL && trap_mdo != NULL) {
int dcnt = trap_mdo->trap_count(reason);
if (dcnt != 0)
xtty->print(" count='%d'", dcnt);
ProfileData* pdata = trap_mdo->bci_to_data(trap_bci);
int dos = (pdata == NULL)? 0: pdata->trap_state();
if (dos != 0) {
xtty->print(" state='%s'", format_trap_state(buf, sizeof(buf), dos));
if (trap_state_is_recompiled(dos)) {
int recnt2 = trap_mdo->overflow_recompile_count();
if (recnt2 != 0)
xtty->print(" recompiles2='%d'", recnt2);
}
}
}
if (xtty != NULL) {
xtty->stamp();
xtty->end_head();
}
if (TraceDeoptimization) { // make noise on the tty
tty->print("Uncommon trap occurred in");
nm->method()->print_short_name(tty);
tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d",
fr.pc(),
os::current_thread_id(),
trap_reason_name(reason),
trap_action_name(action),
unloaded_class_index);
if (class_name != NULL) {
tty->print(unresolved ? " unresolved class: " : " symbol: ");
class_name->print_symbol_on(tty);
}
tty->cr();
}
if (xtty != NULL) {
for (ScopeDesc* sd = trap_scope; ; sd = sd->sender()) {
xtty->begin_elem("jvms bci='%d'", sd->bci());
xtty->method(sd->method());
xtty->end_elem();
if (sd->is_top()) break;
}
xtty->tail("uncommon_trap");
}
}
if (unloaded_class_index >= 0) {
constantPoolHandle constants(THREAD, trap_method->constants());
load_class_by_index(constants, unloaded_class_index);
}
bool injected_profile_trap = trap_method->has_injected_profile() &&
(reason == Reason_intrinsic || reason == Reason_unreached);
bool update_trap_state = !injected_profile_trap;
bool make_not_entrant = false;
bool make_not_compilable = false;
bool reprofile = false;
switch (action) {
case Action_none:
update_trap_state = false;
break;
case Action_maybe_recompile:
break;
case Action_reinterpret:
make_not_entrant = true;
reprofile = true;
break;
case Action_make_not_entrant:
make_not_entrant = true;
break;
case Action_make_not_compilable:
make_not_entrant = true;
make_not_compilable = true;
break;
default:
ShouldNotReachHere();
}
bool inc_recompile_count = false;
ProfileData* pdata = NULL;
if (ProfileTraps && update_trap_state && trap_mdo != NULL) {
assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity");
uint this_trap_count = 0;
bool maybe_prior_trap = false;
bool maybe_prior_recompile = false;
pdata = query_update_method_data(trap_mdo, trap_bci, reason,
nm->method(),
this_trap_count,
maybe_prior_trap,
maybe_prior_recompile);
DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason);
if (per_bc_reason != Reason_none) {
if (maybe_prior_trap
&& this_trap_count >= (uint)PerBytecodeTrapLimit) {
make_not_entrant = true;
}
if (make_not_entrant && maybe_prior_recompile) {
inc_recompile_count = maybe_prior_trap;
}
} else {
make_not_entrant = true;
}
if (this_trap_count >= per_method_trap_limit(reason)) {
make_not_entrant = true;
}
if (make_not_entrant && maybe_prior_recompile && maybe_prior_trap) {
reprofile = true;
}
}
if (make_not_entrant) {
if (!nm->make_not_entrant()) {
return; // the call did not change nmethod's state
}
if (pdata != NULL) {
int tstate0 = pdata->trap_state();
int tstate1 = trap_state_set_recompiled(tstate0, true);
if (tstate1 != tstate0)
pdata->set_trap_state(tstate1);
}
#if INCLUDE_RTM_OPT
if ((reason != Reason_rtm_state_change) && (trap_mdo != NULL) &&
UseRTMDeopt && (nm->rtm_state() != ProfileRTM)) {
trap_mdo->atomic_set_rtm_state(ProfileRTM);
}
#endif
}
if (inc_recompile_count) {
trap_mdo->inc_overflow_recompile_count();
if ((uint)trap_mdo->overflow_recompile_count() >
(uint)PerBytecodeRecompilationCutoff) {
if (trap_method() == nm->method()) {
make_not_compilable = true;
} else {
trap_method->set_not_compilable(CompLevel_full_optimization, true, "overflow_recompile_count > PerBytecodeRecompilationCutoff");
}
}
}
if (reprofile) {
CompilationPolicy::policy()->reprofile(trap_scope, nm->is_osr_method());
}
if (make_not_compilable && !nm->method()->is_not_compilable(CompLevel_full_optimization)) {
assert(make_not_entrant, "consistent");
nm->method()->set_not_compilable(CompLevel_full_optimization);
}
} // Free marked resources
}
JRT_END
MethodData*
Deoptimization::get_method_data(JavaThread* thread, methodHandle m,
bool create_if_missing) {
Thread* THREAD = thread;
MethodData* mdo = m()->method_data();
if (mdo == NULL && create_if_missing && !HAS_PENDING_EXCEPTION) {
Method::build_interpreter_method_data(m, THREAD);
if (HAS_PENDING_EXCEPTION) {
assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here");
CLEAR_PENDING_EXCEPTION;
}
mdo = m()->method_data();
}
return mdo;
}
ProfileData*
Deoptimization::query_update_method_data(MethodData* trap_mdo,
int trap_bci,
Deoptimization::DeoptReason reason,
Method* compiled_method,
uint& ret_this_trap_count,
bool& ret_maybe_prior_trap,
bool& ret_maybe_prior_recompile) {
uint prior_trap_count = trap_mdo->trap_count(reason);
uint this_trap_count = trap_mdo->inc_trap_count(reason);
bool maybe_prior_trap = (prior_trap_count != 0);
bool maybe_prior_recompile = (trap_mdo->decompile_count() != 0);
ProfileData* pdata = NULL;
DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason);
if (per_bc_reason != Reason_none) {
pdata = trap_mdo->allocate_bci_to_data(trap_bci, reason_is_speculate(reason) ? compiled_method : NULL);
if (pdata != NULL) {
if (reason_is_speculate(reason) && !pdata->is_SpeculativeTrapData()) {
if (LogCompilation && xtty != NULL) {
ttyLocker ttyl;
xtty->elem("speculative_traps_oom");
}
}
int tstate0 = pdata->trap_state();
if (!trap_state_has_reason(tstate0, per_bc_reason))
maybe_prior_trap = false;
if (!trap_state_is_recompiled(tstate0))
maybe_prior_recompile = false;
int tstate1 = tstate0;
tstate1 = trap_state_add_reason(tstate1, per_bc_reason);
if (tstate1 != tstate0)
pdata->set_trap_state(tstate1);
} else {
if (LogCompilation && xtty != NULL) {
ttyLocker ttyl;
xtty->elem("missing_mdp bci='%d'", trap_bci);
}
}
}
ret_this_trap_count = this_trap_count;
ret_maybe_prior_trap = maybe_prior_trap;
ret_maybe_prior_recompile = maybe_prior_recompile;
return pdata;
}
void
Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int trap_bci, int reason) {
ResourceMark rm;
uint ignore_this_trap_count;
bool ignore_maybe_prior_trap;
bool ignore_maybe_prior_recompile;
assert(!reason_is_speculate(reason), "reason speculate only used by compiler");
query_update_method_data(trap_mdo, trap_bci,
(DeoptReason)reason,
NULL,
ignore_this_trap_count,
ignore_maybe_prior_trap,
ignore_maybe_prior_recompile);
}
Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) {
{
uncommon_trap_inner(thread, trap_request);
}
return fetch_unroll_info_helper(thread);
}
const int DS_REASON_MASK = DataLayout::trap_mask >> 1;
const int DS_RECOMPILE_BIT = DataLayout::trap_mask - DS_REASON_MASK;
Deoptimization::DeoptReason
Deoptimization::trap_state_reason(int trap_state) {
assert(DS_REASON_MASK >= Reason_RECORDED_LIMIT, "enough bits");
int recompile_bit = (trap_state & DS_RECOMPILE_BIT);
trap_state -= recompile_bit;
if (trap_state == DS_REASON_MASK) {
return Reason_many;
} else {
assert((int)Reason_none == 0, "state=0 => Reason_none");
return (DeoptReason)trap_state;
}
}
int Deoptimization::trap_state_has_reason(int trap_state, int reason) {
assert(reason_is_recorded_per_bytecode((DeoptReason)reason), "valid reason");
assert(DS_REASON_MASK >= Reason_RECORDED_LIMIT, "enough bits");
int recompile_bit = (trap_state & DS_RECOMPILE_BIT);
trap_state -= recompile_bit;
if (trap_state == DS_REASON_MASK) {
return -1; // true, unspecifically (bottom of state lattice)
} else if (trap_state == reason) {
return 1; // true, definitely
} else if (trap_state == 0) {
return 0; // false, definitely (top of state lattice)
} else {
return 0; // false, definitely
}
}
int Deoptimization::trap_state_add_reason(int trap_state, int reason) {
assert(reason_is_recorded_per_bytecode((DeoptReason)reason) || reason == Reason_many, "valid reason");
int recompile_bit = (trap_state & DS_RECOMPILE_BIT);
trap_state -= recompile_bit;
if (trap_state == DS_REASON_MASK) {
return trap_state + recompile_bit; // already at state lattice bottom
} else if (trap_state == reason) {
return trap_state + recompile_bit; // the condition is already true
} else if (trap_state == 0) {
return reason + recompile_bit; // no condition has yet been true
} else {
return DS_REASON_MASK + recompile_bit; // fall to state lattice bottom
}
}
bool Deoptimization::trap_state_is_recompiled(int trap_state) {
return (trap_state & DS_RECOMPILE_BIT) != 0;
}
int Deoptimization::trap_state_set_recompiled(int trap_state, bool z) {
if (z) return trap_state | DS_RECOMPILE_BIT;
else return trap_state & ~DS_RECOMPILE_BIT;
}
const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
int trap_state) {
DeoptReason reason = trap_state_reason(trap_state);
bool recomp_flag = trap_state_is_recompiled(trap_state);
int decoded_state = 0;
if (reason_is_recorded_per_bytecode(reason) || reason == Reason_many)
decoded_state = trap_state_add_reason(decoded_state, reason);
if (recomp_flag)
decoded_state = trap_state_set_recompiled(decoded_state, recomp_flag);
size_t len;
if (decoded_state != trap_state) {
len = jio_snprintf(buf, buflen, "#%d", trap_state);
} else {
len = jio_snprintf(buf, buflen, "%s%s",
trap_reason_name(reason),
recomp_flag ? " recompiled" : "");
}
return buf;
}
Deoptimization::DeoptAction Deoptimization::_unloaded_action
= Deoptimization::Action_reinterpret;
const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = {
"none",
"null_check",
"null_assert",
"range_check",
"class_check",
"array_check",
"intrinsic",
"bimorphic",
"unloaded",
"uninitialized",
"unreached",
"unhandled",
"constraint",
"div0_check",
"age",
"predicate",
"loop_limit_check",
"speculate_class_check",
"rtm_state_change",
"unstable_if"
};
const char* Deoptimization::_trap_action_name[Action_LIMIT] = {
"none",
"maybe_recompile",
"reinterpret",
"make_not_entrant",
"make_not_compilable"
};
const char* Deoptimization::trap_reason_name(int reason) {
if (reason == Reason_many) return "many";
if ((uint)reason < Reason_LIMIT)
return _trap_reason_name[reason];
static char buf[20];
sprintf(buf, "reason%d", reason);
return buf;
}
const char* Deoptimization::trap_action_name(int action) {
if ((uint)action < Action_LIMIT)
return _trap_action_name[action];
static char buf[20];
sprintf(buf, "action%d", action);
return buf;
}
const char* Deoptimization::format_trap_request(char* buf, size_t buflen,
int trap_request) {
jint unloaded_class_index = trap_request_index(trap_request);
const char* reason = trap_reason_name(trap_request_reason(trap_request));
const char* action = trap_action_name(trap_request_action(trap_request));
size_t len;
if (unloaded_class_index < 0) {
len = jio_snprintf(buf, buflen, "reason='%s' action='%s'",
reason, action);
} else {
len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'",
reason, action, unloaded_class_index);
}
return buf;
}
juint Deoptimization::_deoptimization_hist
[Deoptimization::Reason_LIMIT]
[1 + Deoptimization::Action_LIMIT]
[Deoptimization::BC_CASE_LIMIT]
= {0};
enum {
LSB_BITS = 8,
LSB_MASK = right_n_bits(LSB_BITS)
};
void Deoptimization::gather_statistics(DeoptReason reason, DeoptAction action,
Bytecodes::Code bc) {
assert(reason >= 0 && reason < Reason_LIMIT, "oob");
assert(action >= 0 && action < Action_LIMIT, "oob");
_deoptimization_hist[Reason_none][0][0] += 1; // total
_deoptimization_hist[reason][0][0] += 1; // per-reason total
juint* cases = _deoptimization_hist[reason][1+action];
juint* bc_counter_addr = NULL;
juint bc_counter = 0;
if (bc != Bytecodes::_illegal) {
for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
juint* counter_addr = &cases[bc_case];
juint counter = *counter_addr;
if ((counter == 0 && bc_counter_addr == NULL)
|| (Bytecodes::Code)(counter & LSB_MASK) == bc) {
bc_counter_addr = counter_addr;
bc_counter = counter | bc;
}
}
}
if (bc_counter_addr == NULL) {
bc_counter_addr = &cases[BC_CASE_LIMIT-1];
bc_counter = (*bc_counter_addr & ~LSB_MASK); // clear LSB
}
}
jint Deoptimization::total_deoptimization_count() {
return _deoptimization_hist[Reason_none][0][0];
}
jint Deoptimization::deoptimization_count(DeoptReason reason) {
assert(reason >= 0 && reason < Reason_LIMIT, "oob");
return _deoptimization_hist[reason][0][0];
}
void Deoptimization::print_statistics() {
juint total = total_deoptimization_count();
juint account = total;
if (total != 0) {
ttyLocker ttyl;
if (xtty != NULL) xtty->head("statistics type='deoptimization'");
tty->print_cr("Deoptimization traps recorded:");
#define PRINT_STAT_LINE(name, r) \
tty->print_cr(" %4d (%4.1f%%) %s", (int)(r), ((r) * 100.0) / total, name);
PRINT_STAT_LINE("total", total);
for (int reason = 0; reason < Reason_LIMIT; reason++) {
for (int action = 0; action < Action_LIMIT; action++) {
juint* cases = _deoptimization_hist[reason][1+action];
for (int bc_case = 0; bc_case < BC_CASE_LIMIT; bc_case++) {
juint counter = cases[bc_case];
if (counter != 0) {
char name[1*K];
Bytecodes::Code bc = (Bytecodes::Code)(counter & LSB_MASK);
if (bc_case == BC_CASE_LIMIT && (int)bc == 0)
bc = Bytecodes::_illegal;
sprintf(name, "%s/%s/%s",
trap_reason_name(reason),
trap_action_name(action),
Bytecodes::is_defined(bc)? Bytecodes::name(bc): "other");
juint r = counter >> LSB_BITS;
tty->print_cr(" %40s: " UINT32_FORMAT " (%.1f%%)", name, r, (r * 100.0) / total);
account -= r;
}
}
}
}
if (account != 0) {
PRINT_STAT_LINE("unaccounted", account);
}
#undef PRINT_STAT_LINE
if (xtty != NULL) xtty->tail("statistics");
}
}
#else // COMPILER2 || SHARK
bool Deoptimization::trap_state_is_recompiled(int trap_state) {
return false;
}
const char* Deoptimization::trap_reason_name(int reason) {
return "unknown";
}
void Deoptimization::print_statistics() {
}
void
Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int trap_bci, int reason) {
}
int Deoptimization::trap_state_has_reason(int trap_state, int reason) {
return 0;
}
void Deoptimization::gather_statistics(DeoptReason reason, DeoptAction action,
Bytecodes::Code bc) {
}
const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
int trap_state) {
jio_snprintf(buf, buflen, "#%d", trap_state);
return buf;
}
ssssssss70
最新推荐文章于 2024-09-06 00:29:50 发布