mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
Merge
This commit is contained in:
commit
edd3f7ca77
42 changed files with 567 additions and 493 deletions
|
@ -109,8 +109,7 @@
|
||||||
JVM_GetPrimitiveArrayElement;
|
JVM_GetPrimitiveArrayElement;
|
||||||
JVM_GetProtectionDomain;
|
JVM_GetProtectionDomain;
|
||||||
JVM_GetStackAccessControlContext;
|
JVM_GetStackAccessControlContext;
|
||||||
JVM_GetStackTraceDepth;
|
JVM_GetStackTraceElements;
|
||||||
JVM_GetStackTraceElement;
|
|
||||||
JVM_GetSystemPackage;
|
JVM_GetSystemPackage;
|
||||||
JVM_GetSystemPackages;
|
JVM_GetSystemPackages;
|
||||||
JVM_GetTemporaryDirectory;
|
JVM_GetTemporaryDirectory;
|
||||||
|
|
|
@ -1439,6 +1439,12 @@ void java_lang_ThreadGroup::compute_offsets() {
|
||||||
compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature());
|
compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void java_lang_Throwable::compute_offsets() {
|
||||||
|
Klass* k = SystemDictionary::Throwable_klass();
|
||||||
|
compute_offset(depth_offset, k, vmSymbols::depth_name(), vmSymbols::int_signature());
|
||||||
|
}
|
||||||
|
|
||||||
oop java_lang_Throwable::unassigned_stacktrace() {
|
oop java_lang_Throwable::unassigned_stacktrace() {
|
||||||
InstanceKlass* ik = SystemDictionary::Throwable_klass();
|
InstanceKlass* ik = SystemDictionary::Throwable_klass();
|
||||||
address addr = ik->static_field_addr(static_unassigned_stacktrace_offset);
|
address addr = ik->static_field_addr(static_unassigned_stacktrace_offset);
|
||||||
|
@ -1458,11 +1464,13 @@ void java_lang_Throwable::set_backtrace(oop throwable, oop value) {
|
||||||
throwable->release_obj_field_put(backtrace_offset, value);
|
throwable->release_obj_field_put(backtrace_offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int java_lang_Throwable::depth(oop throwable) {
|
||||||
oop java_lang_Throwable::message(oop throwable) {
|
return throwable->int_field(depth_offset);
|
||||||
return throwable->obj_field(detailMessage_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void java_lang_Throwable::set_depth(oop throwable, int value) {
|
||||||
|
throwable->int_field_put(depth_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
oop java_lang_Throwable::message(Handle throwable) {
|
oop java_lang_Throwable::message(Handle throwable) {
|
||||||
return throwable->obj_field(detailMessage_offset);
|
return throwable->obj_field(detailMessage_offset);
|
||||||
|
@ -1512,10 +1520,12 @@ static inline bool version_matches(Method* method, int version) {
|
||||||
return method != NULL && (method->constants()->version() == version);
|
return method != NULL && (method->constants()->version() == version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This class provides a simple wrapper over the internal structure of
|
// This class provides a simple wrapper over the internal structure of
|
||||||
// exception backtrace to insulate users of the backtrace from needing
|
// exception backtrace to insulate users of the backtrace from needing
|
||||||
// to know what it looks like.
|
// to know what it looks like.
|
||||||
class BacktraceBuilder: public StackObj {
|
class BacktraceBuilder: public StackObj {
|
||||||
|
friend class BacktraceIterator;
|
||||||
private:
|
private:
|
||||||
Handle _backtrace;
|
Handle _backtrace;
|
||||||
objArrayOop _head;
|
objArrayOop _head;
|
||||||
|
@ -1526,8 +1536,6 @@ class BacktraceBuilder: public StackObj {
|
||||||
int _index;
|
int _index;
|
||||||
NoSafepointVerifier _nsv;
|
NoSafepointVerifier _nsv;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
trace_methods_offset = java_lang_Throwable::trace_methods_offset,
|
trace_methods_offset = java_lang_Throwable::trace_methods_offset,
|
||||||
trace_bcis_offset = java_lang_Throwable::trace_bcis_offset,
|
trace_bcis_offset = java_lang_Throwable::trace_bcis_offset,
|
||||||
|
@ -1560,6 +1568,8 @@ class BacktraceBuilder: public StackObj {
|
||||||
return cprefs;
|
return cprefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
// constructor for new backtrace
|
// constructor for new backtrace
|
||||||
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) {
|
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) {
|
||||||
expand(CHECK);
|
expand(CHECK);
|
||||||
|
@ -1645,9 +1655,68 @@ class BacktraceBuilder: public StackObj {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BacktraceElement : public StackObj {
|
||||||
|
int _method_id;
|
||||||
|
int _bci;
|
||||||
|
int _version;
|
||||||
|
int _cpref;
|
||||||
|
Handle _mirror;
|
||||||
|
BacktraceElement(Handle mirror, int mid, int version, int bci, int cpref) :
|
||||||
|
_mirror(mirror), _method_id(mid), _version(version), _bci(bci), _cpref(cpref) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BacktraceIterator : public StackObj {
|
||||||
|
int _index;
|
||||||
|
objArrayHandle _result;
|
||||||
|
objArrayHandle _mirrors;
|
||||||
|
typeArrayHandle _methods;
|
||||||
|
typeArrayHandle _bcis;
|
||||||
|
typeArrayHandle _cprefs;
|
||||||
|
|
||||||
|
void init(objArrayHandle result, Thread* thread) {
|
||||||
|
// Get method id, bci, version and mirror from chunk
|
||||||
|
_result = result;
|
||||||
|
if (_result.not_null()) {
|
||||||
|
_methods = typeArrayHandle(thread, BacktraceBuilder::get_methods(_result));
|
||||||
|
_bcis = typeArrayHandle(thread, BacktraceBuilder::get_bcis(_result));
|
||||||
|
_mirrors = objArrayHandle(thread, BacktraceBuilder::get_mirrors(_result));
|
||||||
|
_cprefs = typeArrayHandle(thread, BacktraceBuilder::get_cprefs(_result));
|
||||||
|
_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
BacktraceIterator(objArrayHandle result, Thread* thread) {
|
||||||
|
init(result, thread);
|
||||||
|
assert(_methods->length() == java_lang_Throwable::trace_chunk_size, "lengths don't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
BacktraceElement next(Thread* thread) {
|
||||||
|
BacktraceElement e (Handle(thread, _mirrors->obj_at(_index)),
|
||||||
|
_methods->short_at(_index),
|
||||||
|
Backtrace::version_at(_bcis->int_at(_index)),
|
||||||
|
Backtrace::bci_at(_bcis->int_at(_index)),
|
||||||
|
_cprefs->short_at(_index));
|
||||||
|
_index++;
|
||||||
|
|
||||||
|
if (_index >= java_lang_Throwable::trace_chunk_size) {
|
||||||
|
int next_offset = java_lang_Throwable::trace_next_offset;
|
||||||
|
// Get next chunk
|
||||||
|
objArrayHandle result (thread, objArrayOop(_result->obj_at(next_offset)));
|
||||||
|
init(result, thread);
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool repeat() {
|
||||||
|
return _result.not_null() && _mirrors->obj_at(_index) != NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Print stack trace element to resource allocated buffer
|
// Print stack trace element to resource allocated buffer
|
||||||
char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror,
|
static void print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id,
|
||||||
int method_id, int version, int bci, int cpref) {
|
int version, int bci, int cpref) {
|
||||||
|
ResourceMark rm;
|
||||||
|
|
||||||
// Get strings and string lengths
|
// Get strings and string lengths
|
||||||
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
|
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
|
||||||
|
@ -1698,26 +1767,16 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror,
|
|
||||||
int method_id, int version, int bci, int cpref) {
|
|
||||||
ResourceMark rm;
|
|
||||||
char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref);
|
|
||||||
st->print_cr("%s", buf);
|
st->print_cr("%s", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void java_lang_Throwable::print_stack_element(outputStream *st, const methodHandle& method, int bci) {
|
void java_lang_Throwable::print_stack_element(outputStream *st, const methodHandle& method, int bci) {
|
||||||
Handle mirror = method->method_holder()->java_mirror();
|
Handle mirror = method->method_holder()->java_mirror();
|
||||||
int method_id = method->orig_method_idnum();
|
int method_id = method->orig_method_idnum();
|
||||||
int version = method->constants()->version();
|
int version = method->constants()->version();
|
||||||
int cpref = method->name_index();
|
int cpref = method->name_index();
|
||||||
print_stack_element(st, mirror, method_id, version, bci, cpref);
|
print_stack_element_to_stream(st, mirror, method_id, version, bci, cpref);
|
||||||
}
|
|
||||||
|
|
||||||
const char* java_lang_Throwable::no_stack_trace_message() {
|
|
||||||
return "\t<<no stack trace available>>";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1734,32 +1793,17 @@ void java_lang_Throwable::print_stack_trace(Handle throwable, outputStream* st)
|
||||||
while (throwable.not_null()) {
|
while (throwable.not_null()) {
|
||||||
objArrayHandle result (THREAD, objArrayOop(backtrace(throwable())));
|
objArrayHandle result (THREAD, objArrayOop(backtrace(throwable())));
|
||||||
if (result.is_null()) {
|
if (result.is_null()) {
|
||||||
st->print_raw_cr(no_stack_trace_message());
|
st->print_raw_cr("\t<<no stack trace available>>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
BacktraceIterator iter(result, THREAD);
|
||||||
|
|
||||||
while (result.not_null()) {
|
while (iter.repeat()) {
|
||||||
// Get method id, bci, version and mirror from chunk
|
BacktraceElement bte = iter.next(THREAD);
|
||||||
typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result));
|
print_stack_element_to_stream(st, bte._mirror, bte._method_id, bte._version, bte._bci, bte._cpref);
|
||||||
typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result));
|
|
||||||
objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result));
|
|
||||||
typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result));
|
|
||||||
|
|
||||||
int length = methods()->length();
|
|
||||||
for (int index = 0; index < length; index++) {
|
|
||||||
Handle mirror(THREAD, mirrors->obj_at(index));
|
|
||||||
// NULL mirror means end of stack trace
|
|
||||||
if (mirror.is_null()) goto handle_cause;
|
|
||||||
int method = methods->short_at(index);
|
|
||||||
int version = Backtrace::version_at(bcis->int_at(index));
|
|
||||||
int bci = Backtrace::bci_at(bcis->int_at(index));
|
|
||||||
int cpref = cprefs->short_at(index);
|
|
||||||
print_stack_element(st, mirror, method, version, bci, cpref);
|
|
||||||
}
|
}
|
||||||
result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset)));
|
|
||||||
}
|
|
||||||
handle_cause:
|
|
||||||
{
|
{
|
||||||
|
// Call getCause() which doesn't necessarily return the _cause field.
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
JavaValue cause(T_OBJECT);
|
JavaValue cause(T_OBJECT);
|
||||||
JavaCalls::call_virtual(&cause,
|
JavaCalls::call_virtual(&cause,
|
||||||
|
@ -1811,6 +1855,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand
|
||||||
|
|
||||||
int max_depth = MaxJavaStackTraceDepth;
|
int max_depth = MaxJavaStackTraceDepth;
|
||||||
JavaThread* thread = (JavaThread*)THREAD;
|
JavaThread* thread = (JavaThread*)THREAD;
|
||||||
|
|
||||||
BacktraceBuilder bt(CHECK);
|
BacktraceBuilder bt(CHECK);
|
||||||
|
|
||||||
// If there is no Java frame just return the method that was being called
|
// If there is no Java frame just return the method that was being called
|
||||||
|
@ -1818,6 +1863,8 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand
|
||||||
if (!thread->has_last_Java_frame()) {
|
if (!thread->has_last_Java_frame()) {
|
||||||
if (max_depth >= 1 && method() != NULL) {
|
if (max_depth >= 1 && method() != NULL) {
|
||||||
bt.push(method(), 0, CHECK);
|
bt.push(method(), 0, CHECK);
|
||||||
|
log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1);
|
||||||
|
set_depth(throwable(), 1);
|
||||||
set_backtrace(throwable(), bt.backtrace());
|
set_backtrace(throwable(), bt.backtrace());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -1925,8 +1972,11 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand
|
||||||
total_count++;
|
total_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), total_count);
|
||||||
|
|
||||||
// Put completed stack trace into throwable object
|
// Put completed stack trace into throwable object
|
||||||
set_backtrace(throwable(), bt.backtrace());
|
set_backtrace(throwable(), bt.backtrace());
|
||||||
|
set_depth(throwable(), total_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHandle& method) {
|
void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHandle& method) {
|
||||||
|
@ -1980,94 +2030,60 @@ void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle t
|
||||||
// methods as preallocated errors aren't created by "java" code.
|
// methods as preallocated errors aren't created by "java" code.
|
||||||
|
|
||||||
// fill in as much stack trace as possible
|
// fill in as much stack trace as possible
|
||||||
typeArrayOop methods = BacktraceBuilder::get_methods(backtrace);
|
|
||||||
int max_chunks = MIN2(methods->length(), (int)MaxJavaStackTraceDepth);
|
|
||||||
int chunk_count = 0;
|
int chunk_count = 0;
|
||||||
|
|
||||||
for (;!st.at_end(); st.next()) {
|
for (;!st.at_end(); st.next()) {
|
||||||
bt.push(st.method(), st.bci(), CHECK);
|
bt.push(st.method(), st.bci(), CHECK);
|
||||||
chunk_count++;
|
chunk_count++;
|
||||||
|
|
||||||
// Bail-out for deep stacks
|
// Bail-out for deep stacks
|
||||||
if (chunk_count >= max_chunks) break;
|
if (chunk_count >= trace_chunk_size) break;
|
||||||
}
|
}
|
||||||
|
set_depth(throwable(), chunk_count);
|
||||||
|
log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), chunk_count);
|
||||||
|
|
||||||
// We support the Throwable immutability protocol defined for Java 7.
|
// We support the Throwable immutability protocol defined for Java 7.
|
||||||
java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace());
|
java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace());
|
||||||
assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized");
|
assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void java_lang_Throwable::get_stack_trace_elements(Handle throwable,
|
||||||
|
objArrayHandle stack_trace_array_h, TRAPS) {
|
||||||
|
|
||||||
int java_lang_Throwable::get_stack_trace_depth(oop throwable, TRAPS) {
|
if (throwable.is_null() || stack_trace_array_h.is_null()) {
|
||||||
if (throwable == NULL) {
|
THROW(vmSymbols::java_lang_NullPointerException());
|
||||||
THROW_0(vmSymbols::java_lang_NullPointerException());
|
|
||||||
}
|
}
|
||||||
objArrayOop chunk = objArrayOop(backtrace(throwable));
|
|
||||||
int depth = 0;
|
assert(stack_trace_array_h->is_objArray(), "Stack trace array should be an array of StackTraceElenent");
|
||||||
if (chunk != NULL) {
|
|
||||||
// Iterate over chunks and count full ones
|
if (stack_trace_array_h->length() != depth(throwable())) {
|
||||||
while (true) {
|
THROW(vmSymbols::java_lang_IndexOutOfBoundsException());
|
||||||
objArrayOop next = objArrayOop(chunk->obj_at(trace_next_offset));
|
|
||||||
if (next == NULL) break;
|
|
||||||
depth += trace_chunk_size;
|
|
||||||
chunk = next;
|
|
||||||
}
|
}
|
||||||
assert(chunk != NULL && chunk->obj_at(trace_next_offset) == NULL, "sanity check");
|
|
||||||
// Count element in remaining partial chunk. NULL value for mirror
|
objArrayHandle result(THREAD, objArrayOop(backtrace(throwable())));
|
||||||
// marks the end of the stack trace elements that are saved.
|
BacktraceIterator iter(result, THREAD);
|
||||||
objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk);
|
|
||||||
assert(mirrors != NULL, "sanity check");
|
int index = 0;
|
||||||
for (int i = 0; i < mirrors->length(); i++) {
|
while (iter.repeat()) {
|
||||||
if (mirrors->obj_at(i) == NULL) break;
|
BacktraceElement bte = iter.next(THREAD);
|
||||||
depth++;
|
|
||||||
|
Handle stack_trace_element(THREAD, stack_trace_array_h->obj_at(index++));
|
||||||
|
|
||||||
|
if (stack_trace_element.is_null()) {
|
||||||
|
THROW(vmSymbols::java_lang_NullPointerException());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror()));
|
||||||
|
methodHandle method (THREAD, holder->method_with_orig_idnum(bte._method_id, bte._version));
|
||||||
|
|
||||||
|
java_lang_StackTraceElement::fill_in(stack_trace_element, holder,
|
||||||
|
method,
|
||||||
|
bte._version,
|
||||||
|
bte._bci,
|
||||||
|
bte._cpref, CHECK);
|
||||||
}
|
}
|
||||||
return depth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
|
||||||
oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS) {
|
|
||||||
if (throwable == NULL) {
|
|
||||||
THROW_0(vmSymbols::java_lang_NullPointerException());
|
|
||||||
}
|
|
||||||
if (index < 0) {
|
|
||||||
THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL);
|
|
||||||
}
|
|
||||||
// Compute how many chunks to skip and index into actual chunk
|
|
||||||
objArrayOop chunk = objArrayOop(backtrace(throwable));
|
|
||||||
int skip_chunks = index / trace_chunk_size;
|
|
||||||
int chunk_index = index % trace_chunk_size;
|
|
||||||
while (chunk != NULL && skip_chunks > 0) {
|
|
||||||
chunk = objArrayOop(chunk->obj_at(trace_next_offset));
|
|
||||||
skip_chunks--;
|
|
||||||
}
|
|
||||||
if (chunk == NULL) {
|
|
||||||
THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL);
|
|
||||||
}
|
|
||||||
// Get method id, bci, version, mirror and cpref from chunk
|
|
||||||
typeArrayOop methods = BacktraceBuilder::get_methods(chunk);
|
|
||||||
typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk);
|
|
||||||
objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk);
|
|
||||||
typeArrayOop cprefs = BacktraceBuilder::get_cprefs(chunk);
|
|
||||||
|
|
||||||
assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check");
|
|
||||||
|
|
||||||
int method = methods->short_at(chunk_index);
|
|
||||||
int version = Backtrace::version_at(bcis->int_at(chunk_index));
|
|
||||||
int bci = Backtrace::bci_at(bcis->int_at(chunk_index));
|
|
||||||
int cpref = cprefs->short_at(chunk_index);
|
|
||||||
Handle mirror(THREAD, mirrors->obj_at(chunk_index));
|
|
||||||
|
|
||||||
// Chunk can be partial full
|
|
||||||
if (mirror.is_null()) {
|
|
||||||
THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL);
|
|
||||||
}
|
|
||||||
oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, cpref, CHECK_0);
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
oop java_lang_StackTraceElement::create(Handle mirror, int method_id,
|
|
||||||
int version, int bci, int cpref, TRAPS) {
|
|
||||||
// Allocate java.lang.StackTraceElement instance
|
// Allocate java.lang.StackTraceElement instance
|
||||||
Klass* k = SystemDictionary::StackTraceElement_klass();
|
Klass* k = SystemDictionary::StackTraceElement_klass();
|
||||||
assert(k != NULL, "must be loaded in 1.4+");
|
assert(k != NULL, "must be loaded in 1.4+");
|
||||||
|
@ -2078,23 +2094,31 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id,
|
||||||
|
|
||||||
Handle element = ik->allocate_instance_handle(CHECK_0);
|
Handle element = ik->allocate_instance_handle(CHECK_0);
|
||||||
|
|
||||||
|
int cpref = method->name_index();
|
||||||
|
int version = method->constants()->version();
|
||||||
|
fill_in(element, method->method_holder(), method, version, bci, cpref, CHECK_0);
|
||||||
|
return element();
|
||||||
|
}
|
||||||
|
|
||||||
|
void java_lang_StackTraceElement::fill_in(Handle element,
|
||||||
|
InstanceKlass* holder, const methodHandle& method,
|
||||||
|
int version, int bci, int cpref, TRAPS) {
|
||||||
|
assert(element->is_a(SystemDictionary::StackTraceElement_klass()), "sanity check");
|
||||||
|
|
||||||
// Fill in class name
|
// Fill in class name
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
|
|
||||||
const char* str = holder->external_name();
|
const char* str = holder->external_name();
|
||||||
oop classname = StringTable::intern((char*) str, CHECK_0);
|
oop classname = StringTable::intern((char*) str, CHECK);
|
||||||
java_lang_StackTraceElement::set_declaringClass(element(), classname);
|
java_lang_StackTraceElement::set_declaringClass(element(), classname);
|
||||||
|
|
||||||
Method* method = holder->method_with_orig_idnum(method_id, version);
|
|
||||||
|
|
||||||
// The method can be NULL if the requested class version is gone
|
// The method can be NULL if the requested class version is gone
|
||||||
Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref);
|
Symbol* sym = !method.is_null() ? method->name() : holder->constants()->symbol_at(cpref);
|
||||||
|
|
||||||
// Fill in method name
|
// Fill in method name
|
||||||
oop methodname = StringTable::intern(sym, CHECK_0);
|
oop methodname = StringTable::intern(sym, CHECK);
|
||||||
java_lang_StackTraceElement::set_methodName(element(), methodname);
|
java_lang_StackTraceElement::set_methodName(element(), methodname);
|
||||||
|
|
||||||
if (!version_matches(method, version)) {
|
if (!version_matches(method(), version)) {
|
||||||
// The method was redefined, accurate line number information isn't available
|
// The method was redefined, accurate line number information isn't available
|
||||||
java_lang_StackTraceElement::set_fileName(element(), NULL);
|
java_lang_StackTraceElement::set_fileName(element(), NULL);
|
||||||
java_lang_StackTraceElement::set_lineNumber(element(), -1);
|
java_lang_StackTraceElement::set_lineNumber(element(), -1);
|
||||||
|
@ -2103,20 +2127,12 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id,
|
||||||
Symbol* source = Backtrace::get_source_file_name(holder, version);
|
Symbol* source = Backtrace::get_source_file_name(holder, version);
|
||||||
if (ShowHiddenFrames && source == NULL)
|
if (ShowHiddenFrames && source == NULL)
|
||||||
source = vmSymbols::unknown_class_name();
|
source = vmSymbols::unknown_class_name();
|
||||||
oop filename = StringTable::intern(source, CHECK_0);
|
oop filename = StringTable::intern(source, CHECK);
|
||||||
java_lang_StackTraceElement::set_fileName(element(), filename);
|
java_lang_StackTraceElement::set_fileName(element(), filename);
|
||||||
|
|
||||||
int line_number = Backtrace::get_line_number(method, bci);
|
int line_number = Backtrace::get_line_number(method, bci);
|
||||||
java_lang_StackTraceElement::set_lineNumber(element(), line_number);
|
java_lang_StackTraceElement::set_lineNumber(element(), line_number);
|
||||||
}
|
}
|
||||||
return element();
|
|
||||||
}
|
|
||||||
|
|
||||||
oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
|
|
||||||
Handle mirror (THREAD, method->method_holder()->java_mirror());
|
|
||||||
int method_id = method->orig_method_idnum();
|
|
||||||
int cpref = method->name_index();
|
|
||||||
return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) {
|
Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) {
|
||||||
|
@ -3477,8 +3493,8 @@ int java_lang_Class::_signers_offset;
|
||||||
GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
|
GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
|
||||||
int java_lang_Throwable::backtrace_offset;
|
int java_lang_Throwable::backtrace_offset;
|
||||||
int java_lang_Throwable::detailMessage_offset;
|
int java_lang_Throwable::detailMessage_offset;
|
||||||
int java_lang_Throwable::cause_offset;
|
|
||||||
int java_lang_Throwable::stackTrace_offset;
|
int java_lang_Throwable::stackTrace_offset;
|
||||||
|
int java_lang_Throwable::depth_offset;
|
||||||
int java_lang_Throwable::static_unassigned_stacktrace_offset;
|
int java_lang_Throwable::static_unassigned_stacktrace_offset;
|
||||||
int java_lang_reflect_AccessibleObject::override_offset;
|
int java_lang_reflect_AccessibleObject::override_offset;
|
||||||
int java_lang_reflect_Method::clazz_offset;
|
int java_lang_reflect_Method::clazz_offset;
|
||||||
|
@ -3679,7 +3695,6 @@ void JavaClasses::compute_hard_coded_offsets() {
|
||||||
// Throwable Class
|
// Throwable Class
|
||||||
java_lang_Throwable::backtrace_offset = java_lang_Throwable::hc_backtrace_offset * x + header;
|
java_lang_Throwable::backtrace_offset = java_lang_Throwable::hc_backtrace_offset * x + header;
|
||||||
java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header;
|
java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header;
|
||||||
java_lang_Throwable::cause_offset = java_lang_Throwable::hc_cause_offset * x + header;
|
|
||||||
java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header;
|
java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header;
|
||||||
java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset * x;
|
java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset * x;
|
||||||
|
|
||||||
|
@ -3730,6 +3745,7 @@ void JavaClasses::compute_hard_coded_offsets() {
|
||||||
void JavaClasses::compute_offsets() {
|
void JavaClasses::compute_offsets() {
|
||||||
// java_lang_Class::compute_offsets was called earlier in bootstrap
|
// java_lang_Class::compute_offsets was called earlier in bootstrap
|
||||||
java_lang_ClassLoader::compute_offsets();
|
java_lang_ClassLoader::compute_offsets();
|
||||||
|
java_lang_Throwable::compute_offsets();
|
||||||
java_lang_Thread::compute_offsets();
|
java_lang_Thread::compute_offsets();
|
||||||
java_lang_ThreadGroup::compute_offsets();
|
java_lang_ThreadGroup::compute_offsets();
|
||||||
java_lang_invoke_MethodHandle::compute_offsets();
|
java_lang_invoke_MethodHandle::compute_offsets();
|
||||||
|
@ -3883,8 +3899,8 @@ void JavaClasses::check_offsets() {
|
||||||
|
|
||||||
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, backtrace, "Ljava/lang/Object;");
|
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, backtrace, "Ljava/lang/Object;");
|
||||||
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, detailMessage, "Ljava/lang/String;");
|
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, detailMessage, "Ljava/lang/String;");
|
||||||
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, cause, "Ljava/lang/Throwable;");
|
|
||||||
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, stackTrace, "[Ljava/lang/StackTraceElement;");
|
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, stackTrace, "[Ljava/lang/StackTraceElement;");
|
||||||
|
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, depth, "I");
|
||||||
|
|
||||||
// Boxed primitive objects (java_lang_boxing_object)
|
// Boxed primitive objects (java_lang_boxing_object)
|
||||||
|
|
||||||
|
|
|
@ -440,6 +440,7 @@ class java_lang_ThreadGroup : AllStatic {
|
||||||
|
|
||||||
class java_lang_Throwable: AllStatic {
|
class java_lang_Throwable: AllStatic {
|
||||||
friend class BacktraceBuilder;
|
friend class BacktraceBuilder;
|
||||||
|
friend class BacktraceIterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Offsets
|
// Offsets
|
||||||
|
@ -465,16 +466,12 @@ class java_lang_Throwable: AllStatic {
|
||||||
|
|
||||||
static int backtrace_offset;
|
static int backtrace_offset;
|
||||||
static int detailMessage_offset;
|
static int detailMessage_offset;
|
||||||
static int cause_offset;
|
|
||||||
static int stackTrace_offset;
|
static int stackTrace_offset;
|
||||||
|
static int depth_offset;
|
||||||
static int static_unassigned_stacktrace_offset;
|
static int static_unassigned_stacktrace_offset;
|
||||||
|
|
||||||
// Printing
|
|
||||||
static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci, int cpref);
|
|
||||||
// StackTrace (programmatic access, new since 1.4)
|
// StackTrace (programmatic access, new since 1.4)
|
||||||
static void clear_stacktrace(oop throwable);
|
static void clear_stacktrace(oop throwable);
|
||||||
// No stack trace available
|
|
||||||
static const char* no_stack_trace_message();
|
|
||||||
// Stacktrace (post JDK 1.7.0 to allow immutability protocol to be followed)
|
// Stacktrace (post JDK 1.7.0 to allow immutability protocol to be followed)
|
||||||
static void set_stacktrace(oop throwable, oop st_element_array);
|
static void set_stacktrace(oop throwable, oop st_element_array);
|
||||||
static oop unassigned_stacktrace();
|
static oop unassigned_stacktrace();
|
||||||
|
@ -483,19 +480,20 @@ class java_lang_Throwable: AllStatic {
|
||||||
// Backtrace
|
// Backtrace
|
||||||
static oop backtrace(oop throwable);
|
static oop backtrace(oop throwable);
|
||||||
static void set_backtrace(oop throwable, oop value);
|
static void set_backtrace(oop throwable, oop value);
|
||||||
|
static int depth(oop throwable);
|
||||||
|
static void set_depth(oop throwable, int value);
|
||||||
// Needed by JVMTI to filter out this internal field.
|
// Needed by JVMTI to filter out this internal field.
|
||||||
static int get_backtrace_offset() { return backtrace_offset;}
|
static int get_backtrace_offset() { return backtrace_offset;}
|
||||||
static int get_detailMessage_offset() { return detailMessage_offset;}
|
static int get_detailMessage_offset() { return detailMessage_offset;}
|
||||||
// Message
|
// Message
|
||||||
static oop message(oop throwable);
|
|
||||||
static oop message(Handle throwable);
|
static oop message(Handle throwable);
|
||||||
static void set_message(oop throwable, oop value);
|
static void set_message(oop throwable, oop value);
|
||||||
static Symbol* detail_message(oop throwable);
|
static Symbol* detail_message(oop throwable);
|
||||||
static void print_stack_element(outputStream *st, Handle mirror, int method,
|
|
||||||
int version, int bci, int cpref);
|
|
||||||
static void print_stack_element(outputStream *st, const methodHandle& method, int bci);
|
static void print_stack_element(outputStream *st, const methodHandle& method, int bci);
|
||||||
static void print_stack_usage(Handle stream);
|
static void print_stack_usage(Handle stream);
|
||||||
|
|
||||||
|
static void compute_offsets();
|
||||||
|
|
||||||
// Allocate space for backtrace (created but stack trace not filled in)
|
// Allocate space for backtrace (created but stack trace not filled in)
|
||||||
static void allocate_backtrace(Handle throwable, TRAPS);
|
static void allocate_backtrace(Handle throwable, TRAPS);
|
||||||
// Fill in current stack trace for throwable with preallocated backtrace (no GC)
|
// Fill in current stack trace for throwable with preallocated backtrace (no GC)
|
||||||
|
@ -504,8 +502,7 @@ class java_lang_Throwable: AllStatic {
|
||||||
static void fill_in_stack_trace(Handle throwable, const methodHandle& method, TRAPS);
|
static void fill_in_stack_trace(Handle throwable, const methodHandle& method, TRAPS);
|
||||||
static void fill_in_stack_trace(Handle throwable, const methodHandle& method = methodHandle());
|
static void fill_in_stack_trace(Handle throwable, const methodHandle& method = methodHandle());
|
||||||
// Programmatic access to stack trace
|
// Programmatic access to stack trace
|
||||||
static oop get_stack_trace_element(oop throwable, int index, TRAPS);
|
static void get_stack_trace_elements(Handle throwable, objArrayHandle stack_trace, TRAPS);
|
||||||
static int get_stack_trace_depth(oop throwable, TRAPS);
|
|
||||||
// Printing
|
// Printing
|
||||||
static void print(Handle throwable, outputStream* st);
|
static void print(Handle throwable, outputStream* st);
|
||||||
static void print_stack_trace(Handle throwable, outputStream* st);
|
static void print_stack_trace(Handle throwable, outputStream* st);
|
||||||
|
@ -1277,17 +1274,19 @@ class java_lang_StackTraceElement: AllStatic {
|
||||||
static int fileName_offset;
|
static int fileName_offset;
|
||||||
static int lineNumber_offset;
|
static int lineNumber_offset;
|
||||||
|
|
||||||
public:
|
|
||||||
// Setters
|
// Setters
|
||||||
static void set_declaringClass(oop element, oop value);
|
static void set_declaringClass(oop element, oop value);
|
||||||
static void set_methodName(oop element, oop value);
|
static void set_methodName(oop element, oop value);
|
||||||
static void set_fileName(oop element, oop value);
|
static void set_fileName(oop element, oop value);
|
||||||
static void set_lineNumber(oop element, int value);
|
static void set_lineNumber(oop element, int value);
|
||||||
|
|
||||||
|
public:
|
||||||
// Create an instance of StackTraceElement
|
// Create an instance of StackTraceElement
|
||||||
static oop create(Handle mirror, int method, int version, int bci, int cpref, TRAPS);
|
|
||||||
static oop create(const methodHandle& method, int bci, TRAPS);
|
static oop create(const methodHandle& method, int bci, TRAPS);
|
||||||
|
|
||||||
|
static void fill_in(Handle element, InstanceKlass* holder, const methodHandle& method,
|
||||||
|
int version, int bci, int cpref, TRAPS);
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
friend class JavaClasses;
|
friend class JavaClasses;
|
||||||
};
|
};
|
||||||
|
|
|
@ -376,6 +376,7 @@
|
||||||
template(fillInStackTrace_name, "fillInStackTrace") \
|
template(fillInStackTrace_name, "fillInStackTrace") \
|
||||||
template(getCause_name, "getCause") \
|
template(getCause_name, "getCause") \
|
||||||
template(initCause_name, "initCause") \
|
template(initCause_name, "initCause") \
|
||||||
|
template(depth_name, "depth") \
|
||||||
template(setProperty_name, "setProperty") \
|
template(setProperty_name, "setProperty") \
|
||||||
template(getProperty_name, "getProperty") \
|
template(getProperty_name, "getProperty") \
|
||||||
template(context_name, "context") \
|
template(context_name, "context") \
|
||||||
|
|
|
@ -1931,11 +1931,6 @@ CompactibleFreeListSpace::refillLinearAllocBlockIfNeeded(LinearAllocBlock* blk)
|
||||||
if (blk->_ptr == NULL) {
|
if (blk->_ptr == NULL) {
|
||||||
refillLinearAllocBlock(blk);
|
refillLinearAllocBlock(blk);
|
||||||
}
|
}
|
||||||
if (PrintMiscellaneous && Verbose) {
|
|
||||||
if (blk->_word_size == 0) {
|
|
||||||
warning("CompactibleFreeListSpace(prologue):: Linear allocation failure");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -502,7 +502,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||||
{
|
{
|
||||||
MutexLockerEx x(_markBitMap.lock(), Mutex::_no_safepoint_check_flag);
|
MutexLockerEx x(_markBitMap.lock(), Mutex::_no_safepoint_check_flag);
|
||||||
if (!_markBitMap.allocate(_span)) {
|
if (!_markBitMap.allocate(_span)) {
|
||||||
warning("Failed to allocate CMS Bit Map");
|
log_warning(gc)("Failed to allocate CMS Bit Map");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(_markBitMap.covers(_span), "_markBitMap inconsistency?");
|
assert(_markBitMap.covers(_span), "_markBitMap inconsistency?");
|
||||||
|
@ -513,7 +513,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_markStack.allocate(MarkStackSize)) {
|
if (!_markStack.allocate(MarkStackSize)) {
|
||||||
warning("Failed to allocate CMS Marking Stack");
|
log_warning(gc)("Failed to allocate CMS Marking Stack");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,8 +527,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||||
_conc_workers = new YieldingFlexibleWorkGang("CMS Thread",
|
_conc_workers = new YieldingFlexibleWorkGang("CMS Thread",
|
||||||
ConcGCThreads, true);
|
ConcGCThreads, true);
|
||||||
if (_conc_workers == NULL) {
|
if (_conc_workers == NULL) {
|
||||||
warning("GC/CMS: _conc_workers allocation failure: "
|
log_warning(gc)("GC/CMS: _conc_workers allocation failure: forcing -CMSConcurrentMTEnabled");
|
||||||
"forcing -CMSConcurrentMTEnabled");
|
|
||||||
CMSConcurrentMTEnabled = false;
|
CMSConcurrentMTEnabled = false;
|
||||||
} else {
|
} else {
|
||||||
_conc_workers->initialize_workers();
|
_conc_workers->initialize_workers();
|
||||||
|
@ -559,7 +558,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||||
&& num_queues > 0) {
|
&& num_queues > 0) {
|
||||||
_task_queues = new OopTaskQueueSet(num_queues);
|
_task_queues = new OopTaskQueueSet(num_queues);
|
||||||
if (_task_queues == NULL) {
|
if (_task_queues == NULL) {
|
||||||
warning("task_queues allocation failure.");
|
log_warning(gc)("task_queues allocation failure.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC);
|
_hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC);
|
||||||
|
@ -567,7 +566,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||||
for (i = 0; i < num_queues; i++) {
|
for (i = 0; i < num_queues; i++) {
|
||||||
PaddedOopTaskQueue *q = new PaddedOopTaskQueue();
|
PaddedOopTaskQueue *q = new PaddedOopTaskQueue();
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
warning("work_queue allocation failure.");
|
log_warning(gc)("work_queue allocation failure.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_task_queues->register_queue(i, q);
|
_task_queues->register_queue(i, q);
|
||||||
|
@ -5657,13 +5656,13 @@ bool CMSBitMap::allocate(MemRegion mr) {
|
||||||
ReservedSpace brs(ReservedSpace::allocation_align_size_up(
|
ReservedSpace brs(ReservedSpace::allocation_align_size_up(
|
||||||
(_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
|
(_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
|
||||||
if (!brs.is_reserved()) {
|
if (!brs.is_reserved()) {
|
||||||
warning("CMS bit map allocation failure");
|
log_warning(gc)("CMS bit map allocation failure");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// For now we'll just commit all of the bit map up front.
|
// For now we'll just commit all of the bit map up front.
|
||||||
// Later on we'll try to be more parsimonious with swap.
|
// Later on we'll try to be more parsimonious with swap.
|
||||||
if (!_virtual_space.initialize(brs, brs.size())) {
|
if (!_virtual_space.initialize(brs, brs.size())) {
|
||||||
warning("CMS bit map backing store failure");
|
log_warning(gc)("CMS bit map backing store failure");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
assert(_virtual_space.committed_size() == brs.size(),
|
assert(_virtual_space.committed_size() == brs.size(),
|
||||||
|
@ -5749,11 +5748,11 @@ bool CMSMarkStack::allocate(size_t size) {
|
||||||
ReservedSpace rs(ReservedSpace::allocation_align_size_up(
|
ReservedSpace rs(ReservedSpace::allocation_align_size_up(
|
||||||
size * sizeof(oop)));
|
size * sizeof(oop)));
|
||||||
if (!rs.is_reserved()) {
|
if (!rs.is_reserved()) {
|
||||||
warning("CMSMarkStack allocation failure");
|
log_warning(gc)("CMSMarkStack allocation failure");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!_virtual_space.initialize(rs, rs.size())) {
|
if (!_virtual_space.initialize(rs, rs.size())) {
|
||||||
warning("CMSMarkStack backing store failure");
|
log_warning(gc)("CMSMarkStack backing store failure");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
assert(_virtual_space.committed_size() == rs.size(),
|
assert(_virtual_space.committed_size() == rs.size(),
|
||||||
|
@ -7047,12 +7046,12 @@ SweepClosure::SweepClosure(CMSCollector* collector,
|
||||||
}
|
}
|
||||||
|
|
||||||
void SweepClosure::print_on(outputStream* st) const {
|
void SweepClosure::print_on(outputStream* st) const {
|
||||||
tty->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")",
|
st->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")",
|
||||||
p2i(_sp->bottom()), p2i(_sp->end()));
|
p2i(_sp->bottom()), p2i(_sp->end()));
|
||||||
tty->print_cr("_limit = " PTR_FORMAT, p2i(_limit));
|
st->print_cr("_limit = " PTR_FORMAT, p2i(_limit));
|
||||||
tty->print_cr("_freeFinger = " PTR_FORMAT, p2i(_freeFinger));
|
st->print_cr("_freeFinger = " PTR_FORMAT, p2i(_freeFinger));
|
||||||
NOT_PRODUCT(tty->print_cr("_last_fc = " PTR_FORMAT, p2i(_last_fc));)
|
NOT_PRODUCT(st->print_cr("_last_fc = " PTR_FORMAT, p2i(_last_fc));)
|
||||||
tty->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d",
|
st->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d",
|
||||||
_inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced);
|
_inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7066,8 +7065,10 @@ SweepClosure::~SweepClosure() {
|
||||||
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
|
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
|
||||||
"sweep _limit out of bounds");
|
"sweep _limit out of bounds");
|
||||||
if (inFreeRange()) {
|
if (inFreeRange()) {
|
||||||
warning("inFreeRange() should have been reset; dumping state of SweepClosure");
|
LogHandle(gc, sweep) log;
|
||||||
print();
|
log.error("inFreeRange() should have been reset; dumping state of SweepClosure");
|
||||||
|
ResourceMark rm;
|
||||||
|
print_on(log.error_stream());
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -96,7 +96,7 @@ void ConcurrentMarkSweepThread::run() {
|
||||||
// From this time Thread::current() should be working.
|
// From this time Thread::current() should be working.
|
||||||
assert(this == Thread::current(), "just checking");
|
assert(this == Thread::current(), "just checking");
|
||||||
if (BindCMSThreadToCPU && !os::bind_to_processor(CPUForCMSThread)) {
|
if (BindCMSThreadToCPU && !os::bind_to_processor(CPUForCMSThread)) {
|
||||||
warning("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread);
|
log_warning(gc)("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread);
|
||||||
}
|
}
|
||||||
// Wait until Universe::is_fully_initialized()
|
// Wait until Universe::is_fully_initialized()
|
||||||
{
|
{
|
||||||
|
@ -358,7 +358,7 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) {
|
||||||
|
|
||||||
// Too many loops warning
|
// Too many loops warning
|
||||||
if(++loop_count == 0) {
|
if(++loop_count == 0) {
|
||||||
warning("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1);
|
log_warning(gc)("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ class CMSLoopCountWarn: public StackObj {
|
||||||
inline void tick() {
|
inline void tick() {
|
||||||
_ticks++;
|
_ticks++;
|
||||||
if (CMSLoopWarn && _ticks % _threshold == 0) {
|
if (CMSLoopWarn && _ticks % _threshold == 0) {
|
||||||
warning("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg);
|
log_warning(gc)("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,18 +82,19 @@ inline void ParScanClosure::do_oop_work(T* p,
|
||||||
if ((HeapWord*)obj < _boundary) {
|
if ((HeapWord*)obj < _boundary) {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (_g->to()->is_in_reserved(obj)) {
|
if (_g->to()->is_in_reserved(obj)) {
|
||||||
tty->print_cr("Scanning field (" PTR_FORMAT ") twice?", p2i(p));
|
LogHandle(gc) log;
|
||||||
|
log.error("Scanning field (" PTR_FORMAT ") twice?", p2i(p));
|
||||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||||
Space* sp = gch->space_containing(p);
|
Space* sp = gch->space_containing(p);
|
||||||
oop obj = oop(sp->block_start(p));
|
oop obj = oop(sp->block_start(p));
|
||||||
assert((HeapWord*)obj < (HeapWord*)p, "Error");
|
assert((HeapWord*)obj < (HeapWord*)p, "Error");
|
||||||
tty->print_cr("Object: " PTR_FORMAT, p2i((void *)obj));
|
log.error("Object: " PTR_FORMAT, p2i((void *)obj));
|
||||||
tty->print_cr("-------");
|
log.error("-------");
|
||||||
obj->print();
|
obj->print_on(log.error_stream());
|
||||||
tty->print_cr("-----");
|
log.error("-----");
|
||||||
tty->print_cr("Heap:");
|
log.error("Heap:");
|
||||||
tty->print_cr("-----");
|
log.error("-----");
|
||||||
gch->print();
|
gch->print_on(log.error_stream());
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -115,9 +115,8 @@ bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
|
||||||
uint worker_i) {
|
uint worker_i) {
|
||||||
bool res = true;
|
bool res = true;
|
||||||
if (_buf != NULL) {
|
if (_buf != NULL) {
|
||||||
res = apply_closure_to_buffer(cl, _buf, _index, _sz,
|
BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
|
||||||
consume,
|
res = apply_closure_to_buffer(cl, node, _sz, consume, worker_i);
|
||||||
worker_i);
|
|
||||||
if (res && consume) {
|
if (res && consume) {
|
||||||
_index = _sz;
|
_index = _sz;
|
||||||
}
|
}
|
||||||
|
@ -126,24 +125,27 @@ bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
|
bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
|
||||||
void** buf,
|
BufferNode* node,
|
||||||
size_t index, size_t sz,
|
size_t buffer_size,
|
||||||
bool consume,
|
bool consume,
|
||||||
uint worker_i) {
|
uint worker_i) {
|
||||||
if (cl == NULL) return true;
|
if (cl == NULL) return true;
|
||||||
size_t limit = byte_index_to_index(sz);
|
void** buf = BufferNode::make_buffer_from_node(node);
|
||||||
for (size_t i = byte_index_to_index(index); i < limit; ++i) {
|
size_t limit = byte_index_to_index(buffer_size);
|
||||||
|
for (size_t i = byte_index_to_index(node->index()); i < limit; ++i) {
|
||||||
jbyte* card_ptr = static_cast<jbyte*>(buf[i]);
|
jbyte* card_ptr = static_cast<jbyte*>(buf[i]);
|
||||||
if (card_ptr != NULL) {
|
assert(card_ptr != NULL, "invariant");
|
||||||
// Set the entry to null, so we don't do it again (via the test
|
|
||||||
// above) if we reconsider this buffer.
|
|
||||||
if (consume) {
|
|
||||||
buf[i] = NULL;
|
|
||||||
}
|
|
||||||
if (!cl->do_card_ptr(card_ptr, worker_i)) {
|
if (!cl->do_card_ptr(card_ptr, worker_i)) {
|
||||||
|
if (consume) {
|
||||||
|
size_t new_index = index_to_byte_index(i + 1);
|
||||||
|
assert(new_index <= buffer_size, "invariant");
|
||||||
|
node->set_index(new_index);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (consume) {
|
||||||
|
node->set_index(buffer_size);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -188,14 +190,15 @@ void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
|
||||||
t->dirty_card_queue().handle_zero_index();
|
t->dirty_card_queue().handle_zero_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
|
bool DirtyCardQueueSet::mut_process_buffer(BufferNode* node) {
|
||||||
guarantee(_free_ids != NULL, "must be");
|
guarantee(_free_ids != NULL, "must be");
|
||||||
|
|
||||||
// claim a par id
|
// claim a par id
|
||||||
uint worker_i = _free_ids->claim_par_id();
|
uint worker_i = _free_ids->claim_par_id();
|
||||||
|
|
||||||
bool b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure, buf, 0,
|
bool b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure,
|
||||||
_sz, true, worker_i);
|
node, _sz,
|
||||||
|
true, worker_i);
|
||||||
if (b) {
|
if (b) {
|
||||||
Atomic::inc(&_processed_buffers_mut);
|
Atomic::inc(&_processed_buffers_mut);
|
||||||
}
|
}
|
||||||
|
@ -239,49 +242,30 @@ bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure*
|
||||||
if (nd == NULL) {
|
if (nd == NULL) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
void** buf = BufferNode::make_buffer_from_node(nd);
|
if (DirtyCardQueue::apply_closure_to_buffer(cl, nd, _sz, true, worker_i)) {
|
||||||
size_t index = nd->index();
|
|
||||||
if (DirtyCardQueue::apply_closure_to_buffer(cl,
|
|
||||||
buf, index, _sz,
|
|
||||||
true, worker_i)) {
|
|
||||||
// Done with fully processed buffer.
|
// Done with fully processed buffer.
|
||||||
deallocate_buffer(buf);
|
deallocate_buffer(nd);
|
||||||
Atomic::inc(&_processed_buffers_rs_thread);
|
Atomic::inc(&_processed_buffers_rs_thread);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Return partially processed buffer to the queue.
|
// Return partially processed buffer to the queue.
|
||||||
enqueue_complete_buffer(buf, index);
|
enqueue_complete_buffer(nd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirtyCardQueueSet::apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
|
|
||||||
BufferNode* nd = _completed_buffers_head;
|
|
||||||
while (nd != NULL) {
|
|
||||||
bool b =
|
|
||||||
DirtyCardQueue::apply_closure_to_buffer(cl,
|
|
||||||
BufferNode::make_buffer_from_node(nd),
|
|
||||||
0, _sz, false);
|
|
||||||
guarantee(b, "Should not stop early.");
|
|
||||||
nd = nd->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
|
void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
|
||||||
BufferNode* nd = _cur_par_buffer_node;
|
BufferNode* nd = _cur_par_buffer_node;
|
||||||
while (nd != NULL) {
|
while (nd != NULL) {
|
||||||
BufferNode* next = (BufferNode*)nd->next();
|
BufferNode* next = nd->next();
|
||||||
BufferNode* actual = (BufferNode*)Atomic::cmpxchg_ptr((void*)next, (volatile void*)&_cur_par_buffer_node, (void*)nd);
|
void* actual = Atomic::cmpxchg_ptr(next, &_cur_par_buffer_node, nd);
|
||||||
if (actual == nd) {
|
if (actual == nd) {
|
||||||
bool b =
|
bool b = DirtyCardQueue::apply_closure_to_buffer(cl, nd, _sz, false);
|
||||||
DirtyCardQueue::apply_closure_to_buffer(cl,
|
|
||||||
BufferNode::make_buffer_from_node(actual),
|
|
||||||
0, _sz, false);
|
|
||||||
guarantee(b, "Should not stop early.");
|
guarantee(b, "Should not stop early.");
|
||||||
nd = next;
|
nd = next;
|
||||||
} else {
|
} else {
|
||||||
nd = actual;
|
nd = static_cast<BufferNode*>(actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,7 +288,7 @@ void DirtyCardQueueSet::clear() {
|
||||||
while (buffers_to_delete != NULL) {
|
while (buffers_to_delete != NULL) {
|
||||||
BufferNode* nd = buffers_to_delete;
|
BufferNode* nd = buffers_to_delete;
|
||||||
buffers_to_delete = nd->next();
|
buffers_to_delete = nd->next();
|
||||||
deallocate_buffer(BufferNode::make_buffer_from_node(nd));
|
deallocate_buffer(nd);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -320,6 +304,13 @@ void DirtyCardQueueSet::abandon_logs() {
|
||||||
shared_dirty_card_queue()->reset();
|
shared_dirty_card_queue()->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DirtyCardQueueSet::concatenate_log(DirtyCardQueue& dcq) {
|
||||||
|
if (!dcq.is_empty()) {
|
||||||
|
enqueue_complete_buffer(
|
||||||
|
BufferNode::make_node_from_buffer(dcq.get_buf(), dcq.get_index()));
|
||||||
|
dcq.reinitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DirtyCardQueueSet::concatenate_logs() {
|
void DirtyCardQueueSet::concatenate_logs() {
|
||||||
// Iterate over all the threads, if we find a partial log add it to
|
// Iterate over all the threads, if we find a partial log add it to
|
||||||
|
@ -329,23 +320,9 @@ void DirtyCardQueueSet::concatenate_logs() {
|
||||||
_max_completed_queue = max_jint;
|
_max_completed_queue = max_jint;
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
||||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||||
DirtyCardQueue& dcq = t->dirty_card_queue();
|
concatenate_log(t->dirty_card_queue());
|
||||||
if (dcq.size() != 0) {
|
|
||||||
void** buf = dcq.get_buf();
|
|
||||||
// We must NULL out the unused entries, then enqueue.
|
|
||||||
size_t limit = dcq.byte_index_to_index(dcq.get_index());
|
|
||||||
for (size_t i = 0; i < limit; ++i) {
|
|
||||||
buf[i] = NULL;
|
|
||||||
}
|
|
||||||
enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());
|
|
||||||
dcq.reinitialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_shared_dirty_card_queue.size() != 0) {
|
|
||||||
enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(),
|
|
||||||
_shared_dirty_card_queue.get_index());
|
|
||||||
_shared_dirty_card_queue.reinitialize();
|
|
||||||
}
|
}
|
||||||
|
concatenate_log(_shared_dirty_card_queue);
|
||||||
// Restore the completed buffer queue limit.
|
// Restore the completed buffer queue limit.
|
||||||
_max_completed_queue = save_max_completed_queue;
|
_max_completed_queue = save_max_completed_queue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,21 +52,24 @@ public:
|
||||||
// Process queue entries and release resources.
|
// Process queue entries and release resources.
|
||||||
void flush() { flush_impl(); }
|
void flush() { flush_impl(); }
|
||||||
|
|
||||||
// Apply the closure to all elements, and reset the index to make the
|
// Apply the closure to the elements from _index to _sz. If all
|
||||||
// buffer empty. If a closure application returns "false", return
|
// closure applications return true, then returns true. Stops
|
||||||
// "false" immediately, halting the iteration. If "consume" is true,
|
// processing after the first closure application that returns
|
||||||
// deletes processed entries from logs.
|
// false, and returns false from this function. If "consume" is
|
||||||
|
// true, _index is updated to follow the last processed element.
|
||||||
bool apply_closure(CardTableEntryClosure* cl,
|
bool apply_closure(CardTableEntryClosure* cl,
|
||||||
bool consume = true,
|
bool consume = true,
|
||||||
uint worker_i = 0);
|
uint worker_i = 0);
|
||||||
|
|
||||||
// Apply the closure to all elements of "buf", down to "index"
|
// Apply the closure to the elements of "node" from it's index to
|
||||||
// (inclusive.) If returns "false", then a closure application returned
|
// buffer_size. If all closure applications return true, then
|
||||||
// "false", and we return immediately. If "consume" is true, entries are
|
// returns true. Stops processing after the first closure
|
||||||
// set to NULL as they are processed, so they will not be processed again
|
// application that returns false, and returns false from this
|
||||||
// later.
|
// function. If "consume" is true, the node's index is updated to
|
||||||
|
// follow the last processed element.
|
||||||
static bool apply_closure_to_buffer(CardTableEntryClosure* cl,
|
static bool apply_closure_to_buffer(CardTableEntryClosure* cl,
|
||||||
void** buf, size_t index, size_t sz,
|
BufferNode* node,
|
||||||
|
size_t buffer_size,
|
||||||
bool consume = true,
|
bool consume = true,
|
||||||
uint worker_i = 0);
|
uint worker_i = 0);
|
||||||
void **get_buf() { return _buf;}
|
void **get_buf() { return _buf;}
|
||||||
|
@ -94,8 +97,7 @@ class DirtyCardQueueSet: public PtrQueueSet {
|
||||||
|
|
||||||
DirtyCardQueue _shared_dirty_card_queue;
|
DirtyCardQueue _shared_dirty_card_queue;
|
||||||
|
|
||||||
// Override.
|
bool mut_process_buffer(BufferNode* node);
|
||||||
bool mut_process_buffer(void** buf);
|
|
||||||
|
|
||||||
// Protected by the _cbl_mon.
|
// Protected by the _cbl_mon.
|
||||||
FreeIdSet* _free_ids;
|
FreeIdSet* _free_ids;
|
||||||
|
@ -107,6 +109,9 @@ class DirtyCardQueueSet: public PtrQueueSet {
|
||||||
|
|
||||||
// Current buffer node used for parallel iteration.
|
// Current buffer node used for parallel iteration.
|
||||||
BufferNode* volatile _cur_par_buffer_node;
|
BufferNode* volatile _cur_par_buffer_node;
|
||||||
|
|
||||||
|
void concatenate_log(DirtyCardQueue& dcq);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DirtyCardQueueSet(bool notify_when_complete = true);
|
DirtyCardQueueSet(bool notify_when_complete = true);
|
||||||
|
|
||||||
|
@ -126,12 +131,13 @@ public:
|
||||||
static void handle_zero_index_for_thread(JavaThread* t);
|
static void handle_zero_index_for_thread(JavaThread* t);
|
||||||
|
|
||||||
// If there exists some completed buffer, pop it, then apply the
|
// If there exists some completed buffer, pop it, then apply the
|
||||||
// specified closure to all its elements, nulling out those elements
|
// specified closure to its active elements. If all active elements
|
||||||
// processed. If all elements are processed, returns "true". If no
|
// are processed, returns "true". If no completed buffers exist,
|
||||||
// completed buffers exist, returns false. If a completed buffer exists,
|
// returns false. If a completed buffer exists, but is only
|
||||||
// but is only partially completed before a "yield" happens, the
|
// partially completed before a "yield" happens, the partially
|
||||||
// partially completed buffer (with its processed elements set to NULL)
|
// completed buffer (with its index updated to exclude the processed
|
||||||
// is returned to the completed buffer set, and this call returns false.
|
// elements) is returned to the completed buffer set, and this call
|
||||||
|
// returns false.
|
||||||
bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
|
bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
|
||||||
uint worker_i,
|
uint worker_i,
|
||||||
size_t stop_at,
|
size_t stop_at,
|
||||||
|
@ -139,13 +145,10 @@ public:
|
||||||
|
|
||||||
BufferNode* get_completed_buffer(size_t stop_at);
|
BufferNode* get_completed_buffer(size_t stop_at);
|
||||||
|
|
||||||
// Applies the current closure to all completed buffers,
|
|
||||||
// non-consumptively.
|
|
||||||
void apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl);
|
|
||||||
|
|
||||||
void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; }
|
void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; }
|
||||||
// Applies the current closure to all completed buffers, non-consumptively.
|
// Applies the current closure to all completed buffers, non-consumptively.
|
||||||
// Parallel version.
|
// Can be used in parallel, all callers using the iteration state initialized
|
||||||
|
// by reset_for_par_iteration.
|
||||||
void par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl);
|
void par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl);
|
||||||
|
|
||||||
DirtyCardQueue* shared_dirty_card_queue() {
|
DirtyCardQueue* shared_dirty_card_queue() {
|
||||||
|
|
|
@ -567,7 +567,7 @@ G1CollectedHeap::mem_allocate(size_t word_size,
|
||||||
// Give a warning if we seem to be looping forever.
|
// Give a warning if we seem to be looping forever.
|
||||||
if ((QueuedAllocationWarningCount > 0) &&
|
if ((QueuedAllocationWarningCount > 0) &&
|
||||||
(try_count % QueuedAllocationWarningCount == 0)) {
|
(try_count % QueuedAllocationWarningCount == 0)) {
|
||||||
warning("G1CollectedHeap::mem_allocate retries %d times", try_count);
|
log_warning(gc)("G1CollectedHeap::mem_allocate retries %d times", try_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +676,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
|
||||||
// Give a warning if we seem to be looping forever.
|
// Give a warning if we seem to be looping forever.
|
||||||
if ((QueuedAllocationWarningCount > 0) &&
|
if ((QueuedAllocationWarningCount > 0) &&
|
||||||
(try_count % QueuedAllocationWarningCount == 0)) {
|
(try_count % QueuedAllocationWarningCount == 0)) {
|
||||||
warning("G1CollectedHeap::attempt_allocation_slow() "
|
log_warning(gc)("G1CollectedHeap::attempt_allocation_slow() "
|
||||||
"retries %d times", try_count);
|
"retries %d times", try_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1092,7 +1092,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
|
||||||
|
|
||||||
if ((QueuedAllocationWarningCount > 0) &&
|
if ((QueuedAllocationWarningCount > 0) &&
|
||||||
(try_count % QueuedAllocationWarningCount == 0)) {
|
(try_count % QueuedAllocationWarningCount == 0)) {
|
||||||
warning("G1CollectedHeap::attempt_allocation_humongous() "
|
log_warning(gc)("G1CollectedHeap::attempt_allocation_humongous() "
|
||||||
"retries %d times", try_count);
|
"retries %d times", try_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2731,7 +2731,7 @@ void G1CollectedHeap::print_on(outputStream* st) const {
|
||||||
uint young_regions = _young_list->length();
|
uint young_regions = _young_list->length();
|
||||||
st->print("%u young (" SIZE_FORMAT "K), ", young_regions,
|
st->print("%u young (" SIZE_FORMAT "K), ", young_regions,
|
||||||
(size_t) young_regions * HeapRegion::GrainBytes / K);
|
(size_t) young_regions * HeapRegion::GrainBytes / K);
|
||||||
uint survivor_regions = g1_policy()->recorded_survivor_regions();
|
uint survivor_regions = _young_list->survivor_length();
|
||||||
st->print("%u survivors (" SIZE_FORMAT "K)", survivor_regions,
|
st->print("%u survivors (" SIZE_FORMAT "K)", survivor_regions,
|
||||||
(size_t) survivor_regions * HeapRegion::GrainBytes / K);
|
(size_t) survivor_regions * HeapRegion::GrainBytes / K);
|
||||||
st->cr();
|
st->cr();
|
||||||
|
@ -3405,10 +3405,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||||
assert(check_young_list_empty(false /* check_heap */),
|
assert(check_young_list_empty(false /* check_heap */),
|
||||||
"young list should be empty");
|
"young list should be empty");
|
||||||
|
|
||||||
g1_policy()->record_survivor_regions(_young_list->survivor_length(),
|
|
||||||
_young_list->first_survivor_region(),
|
|
||||||
_young_list->last_survivor_region());
|
|
||||||
|
|
||||||
_young_list->reset_auxilary_lists();
|
_young_list->reset_auxilary_lists();
|
||||||
|
|
||||||
if (evacuation_failed()) {
|
if (evacuation_failed()) {
|
||||||
|
|
|
@ -118,9 +118,6 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
||||||
_max_survivor_regions(0),
|
_max_survivor_regions(0),
|
||||||
|
|
||||||
// add here any more surv rate groups
|
// add here any more surv rate groups
|
||||||
_recorded_survivor_regions(0),
|
|
||||||
_recorded_survivor_head(NULL),
|
|
||||||
_recorded_survivor_tail(NULL),
|
|
||||||
_survivors_age_table(true),
|
_survivors_age_table(true),
|
||||||
|
|
||||||
_gc_overhead_perc(0.0),
|
_gc_overhead_perc(0.0),
|
||||||
|
@ -430,7 +427,7 @@ G1CollectorPolicy::YoungTargetLengths G1CollectorPolicy::young_list_target_lengt
|
||||||
// Calculate the absolute and desired min bounds first.
|
// Calculate the absolute and desired min bounds first.
|
||||||
|
|
||||||
// This is how many young regions we already have (currently: the survivors).
|
// This is how many young regions we already have (currently: the survivors).
|
||||||
uint base_min_length = recorded_survivor_regions();
|
const uint base_min_length = _g1->young_list()->survivor_length();
|
||||||
uint desired_min_length = calculate_young_list_desired_min_length(base_min_length);
|
uint desired_min_length = calculate_young_list_desired_min_length(base_min_length);
|
||||||
// This is the absolute minimum young length. Ensure that we
|
// This is the absolute minimum young length. Ensure that we
|
||||||
// will at least have one eden region available for allocation.
|
// will at least have one eden region available for allocation.
|
||||||
|
@ -481,7 +478,7 @@ G1CollectorPolicy::YoungTargetLengths G1CollectorPolicy::young_list_target_lengt
|
||||||
young_list_target_length = desired_min_length;
|
young_list_target_length = desired_min_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(young_list_target_length > recorded_survivor_regions(),
|
assert(young_list_target_length > base_min_length,
|
||||||
"we should be able to allocate at least one eden region");
|
"we should be able to allocate at least one eden region");
|
||||||
assert(young_list_target_length >= absolute_min_length, "post-condition");
|
assert(young_list_target_length >= absolute_min_length, "post-condition");
|
||||||
|
|
||||||
|
@ -595,8 +592,8 @@ G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths,
|
||||||
|
|
||||||
double G1CollectorPolicy::predict_survivor_regions_evac_time() const {
|
double G1CollectorPolicy::predict_survivor_regions_evac_time() const {
|
||||||
double survivor_regions_evac_time = 0.0;
|
double survivor_regions_evac_time = 0.0;
|
||||||
for (HeapRegion * r = _recorded_survivor_head;
|
for (HeapRegion * r = _g1->young_list()->first_survivor_region();
|
||||||
r != NULL && r != _recorded_survivor_tail->get_next_young_region();
|
r != NULL && r != _g1->young_list()->last_survivor_region()->get_next_young_region();
|
||||||
r = r->get_next_young_region()) {
|
r = r->get_next_young_region()) {
|
||||||
survivor_regions_evac_time += predict_region_elapsed_time_ms(r, collector_state()->gcs_are_young());
|
survivor_regions_evac_time += predict_region_elapsed_time_ms(r, collector_state()->gcs_are_young());
|
||||||
}
|
}
|
||||||
|
@ -700,8 +697,6 @@ void G1CollectorPolicy::record_full_collection_end() {
|
||||||
_short_lived_surv_rate_group->start_adding_regions();
|
_short_lived_surv_rate_group->start_adding_regions();
|
||||||
// also call this on any additional surv rate groups
|
// also call this on any additional surv rate groups
|
||||||
|
|
||||||
record_survivor_regions(0, NULL, NULL);
|
|
||||||
|
|
||||||
_free_regions_at_end_of_collection = _g1->num_free_regions();
|
_free_regions_at_end_of_collection = _g1->num_free_regions();
|
||||||
// Reset survivors SurvRateGroup.
|
// Reset survivors SurvRateGroup.
|
||||||
_survivor_surv_rate_group->reset();
|
_survivor_surv_rate_group->reset();
|
||||||
|
|
|
@ -522,16 +522,6 @@ private:
|
||||||
// The limit on the number of regions allocated for survivors.
|
// The limit on the number of regions allocated for survivors.
|
||||||
uint _max_survivor_regions;
|
uint _max_survivor_regions;
|
||||||
|
|
||||||
// For reporting purposes.
|
|
||||||
// The value of _heap_bytes_before_gc is also used to calculate
|
|
||||||
// the cost of copying.
|
|
||||||
|
|
||||||
// The amount of survivor regions after a collection.
|
|
||||||
uint _recorded_survivor_regions;
|
|
||||||
// List of survivor regions.
|
|
||||||
HeapRegion* _recorded_survivor_head;
|
|
||||||
HeapRegion* _recorded_survivor_tail;
|
|
||||||
|
|
||||||
AgeTable _survivors_age_table;
|
AgeTable _survivors_age_table;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -565,18 +555,6 @@ public:
|
||||||
_survivor_surv_rate_group->stop_adding_regions();
|
_survivor_surv_rate_group->stop_adding_regions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void record_survivor_regions(uint regions,
|
|
||||||
HeapRegion* head,
|
|
||||||
HeapRegion* tail) {
|
|
||||||
_recorded_survivor_regions = regions;
|
|
||||||
_recorded_survivor_head = head;
|
|
||||||
_recorded_survivor_tail = tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint recorded_survivor_regions() const {
|
|
||||||
return _recorded_survivor_regions;
|
|
||||||
}
|
|
||||||
|
|
||||||
void record_age_table(AgeTable* age_table) {
|
void record_age_table(AgeTable* age_table) {
|
||||||
_survivors_age_table.merge(age_table);
|
_survivors_age_table.merge(age_table);
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,12 +203,12 @@ bool G1CMMarkStack::allocate(size_t capacity) {
|
||||||
// allocate a stack of the requisite depth
|
// allocate a stack of the requisite depth
|
||||||
ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop)));
|
ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop)));
|
||||||
if (!rs.is_reserved()) {
|
if (!rs.is_reserved()) {
|
||||||
warning("ConcurrentMark MarkStack allocation failure");
|
log_warning(gc)("ConcurrentMark MarkStack allocation failure");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
|
MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
|
||||||
if (!_virtual_space.initialize(rs, rs.size())) {
|
if (!_virtual_space.initialize(rs, rs.size())) {
|
||||||
warning("ConcurrentMark MarkStack backing store failure");
|
log_warning(gc)("ConcurrentMark MarkStack backing store failure");
|
||||||
// Release the virtual memory reserved for the marking stack
|
// Release the virtual memory reserved for the marking stack
|
||||||
rs.release();
|
rs.release();
|
||||||
return false;
|
return false;
|
||||||
|
@ -478,8 +478,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper*
|
||||||
_root_regions.init(_g1h, this);
|
_root_regions.init(_g1h, this);
|
||||||
|
|
||||||
if (ConcGCThreads > ParallelGCThreads) {
|
if (ConcGCThreads > ParallelGCThreads) {
|
||||||
warning("Can't have more ConcGCThreads (%u) "
|
log_warning(gc)("Can't have more ConcGCThreads (%u) than ParallelGCThreads (%u).",
|
||||||
"than ParallelGCThreads (%u).",
|
|
||||||
ConcGCThreads, ParallelGCThreads);
|
ConcGCThreads, ParallelGCThreads);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -534,7 +533,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper*
|
||||||
// Verify that the calculated value for MarkStackSize is in range.
|
// Verify that the calculated value for MarkStackSize is in range.
|
||||||
// It would be nice to use the private utility routine from Arguments.
|
// It would be nice to use the private utility routine from Arguments.
|
||||||
if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) {
|
if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) {
|
||||||
warning("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): "
|
log_warning(gc)("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): "
|
||||||
"must be between 1 and " SIZE_FORMAT,
|
"must be between 1 and " SIZE_FORMAT,
|
||||||
mark_stack_size, MarkStackSizeMax);
|
mark_stack_size, MarkStackSizeMax);
|
||||||
return;
|
return;
|
||||||
|
@ -545,14 +544,14 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper*
|
||||||
if (FLAG_IS_CMDLINE(MarkStackSize)) {
|
if (FLAG_IS_CMDLINE(MarkStackSize)) {
|
||||||
if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
|
if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
|
||||||
if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
|
if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
|
||||||
warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): "
|
log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): "
|
||||||
"must be between 1 and " SIZE_FORMAT,
|
"must be between 1 and " SIZE_FORMAT,
|
||||||
MarkStackSize, MarkStackSizeMax);
|
MarkStackSize, MarkStackSizeMax);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) {
|
} else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) {
|
||||||
if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
|
if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
|
||||||
warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")"
|
log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")"
|
||||||
" or for MarkStackSizeMax (" SIZE_FORMAT ")",
|
" or for MarkStackSizeMax (" SIZE_FORMAT ")",
|
||||||
MarkStackSize, MarkStackSizeMax);
|
MarkStackSize, MarkStackSizeMax);
|
||||||
return;
|
return;
|
||||||
|
@ -562,7 +561,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper*
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_markStack.allocate(MarkStackSize)) {
|
if (!_markStack.allocate(MarkStackSize)) {
|
||||||
warning("Failed to allocate CM marking stack");
|
log_warning(gc)("Failed to allocate CM marking stack");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,15 +110,9 @@ void G1EvacStats::adjust_desired_plab_sz() {
|
||||||
size_t const cur_plab_sz = (size_t)((double)total_waste_allowed / G1LastPLABAverageOccupancy);
|
size_t const cur_plab_sz = (size_t)((double)total_waste_allowed / G1LastPLABAverageOccupancy);
|
||||||
// Take historical weighted average
|
// Take historical weighted average
|
||||||
_filter.sample(cur_plab_sz);
|
_filter.sample(cur_plab_sz);
|
||||||
// Clip from above and below, and align to object boundary
|
_desired_net_plab_sz = MAX2(min_size(), (size_t)_filter.average());
|
||||||
size_t plab_sz;
|
|
||||||
plab_sz = MAX2(min_size(), (size_t)_filter.average());
|
|
||||||
plab_sz = MIN2(max_size(), plab_sz);
|
|
||||||
plab_sz = align_object_size(plab_sz);
|
|
||||||
// Latch the result
|
|
||||||
_desired_net_plab_sz = plab_sz;
|
|
||||||
|
|
||||||
log_sizing(cur_plab_sz, plab_sz);
|
log_sizing(cur_plab_sz, _desired_net_plab_sz);
|
||||||
// Clear accumulators for next round.
|
// Clear accumulators for next round.
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -178,7 +178,7 @@ void G1MonitoringSupport::recalculate_sizes() {
|
||||||
// of a GC).
|
// of a GC).
|
||||||
|
|
||||||
uint young_list_length = g1->young_list()->length();
|
uint young_list_length = g1->young_list()->length();
|
||||||
uint survivor_list_length = g1->g1_policy()->recorded_survivor_regions();
|
uint survivor_list_length = g1->young_list()->survivor_length();
|
||||||
assert(young_list_length >= survivor_list_length, "invariant");
|
assert(young_list_length >= survivor_list_length, "invariant");
|
||||||
uint eden_list_length = young_list_length - survivor_list_length;
|
uint eden_list_length = young_list_length - survivor_list_length;
|
||||||
// Max length includes any potential extensions to the young gen
|
// Max length includes any potential extensions to the young gen
|
||||||
|
|
|
@ -233,10 +233,6 @@
|
||||||
"Raise a fatal VM exit out of memory failure in the event " \
|
"Raise a fatal VM exit out of memory failure in the event " \
|
||||||
" that heap expansion fails due to running out of swap.") \
|
" that heap expansion fails due to running out of swap.") \
|
||||||
\
|
\
|
||||||
develop(uintx, G1ConcMarkForceOverflow, 0, \
|
|
||||||
"The number of times we'll force an overflow during " \
|
|
||||||
"concurrent marking") \
|
|
||||||
\
|
|
||||||
experimental(uintx, G1MaxNewSizePercent, 60, \
|
experimental(uintx, G1MaxNewSizePercent, 60, \
|
||||||
"Percentage (0-100) of the heap size to use as default " \
|
"Percentage (0-100) of the heap size to use as default " \
|
||||||
" maximum young gen size.") \
|
" maximum young gen size.") \
|
||||||
|
|
|
@ -43,16 +43,12 @@ PtrQueue::~PtrQueue() {
|
||||||
|
|
||||||
void PtrQueue::flush_impl() {
|
void PtrQueue::flush_impl() {
|
||||||
if (!_permanent && _buf != NULL) {
|
if (!_permanent && _buf != NULL) {
|
||||||
if (_index == _sz) {
|
BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
|
||||||
|
if (is_empty()) {
|
||||||
// No work to do.
|
// No work to do.
|
||||||
qset()->deallocate_buffer(_buf);
|
qset()->deallocate_buffer(node);
|
||||||
} else {
|
} else {
|
||||||
// We must NULL out the unused entries, then enqueue.
|
qset()->enqueue_complete_buffer(node);
|
||||||
size_t limit = byte_index_to_index(_index);
|
|
||||||
for (size_t i = 0; i < limit; ++i) {
|
|
||||||
_buf[i] = NULL;
|
|
||||||
}
|
|
||||||
qset()->enqueue_complete_buffer(_buf);
|
|
||||||
}
|
}
|
||||||
_buf = NULL;
|
_buf = NULL;
|
||||||
_index = 0;
|
_index = 0;
|
||||||
|
@ -74,7 +70,7 @@ void PtrQueue::enqueue_known_active(void* ptr) {
|
||||||
assert(_index <= _sz, "Invariant.");
|
assert(_index <= _sz, "Invariant.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
|
void PtrQueue::locking_enqueue_completed_buffer(BufferNode* node) {
|
||||||
assert(_lock->owned_by_self(), "Required.");
|
assert(_lock->owned_by_self(), "Required.");
|
||||||
|
|
||||||
// We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
|
// We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
|
||||||
|
@ -82,7 +78,7 @@ void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
|
||||||
// have the same rank and we may get the "possible deadlock" message
|
// have the same rank and we may get the "possible deadlock" message
|
||||||
_lock->unlock();
|
_lock->unlock();
|
||||||
|
|
||||||
qset()->enqueue_complete_buffer(buf);
|
qset()->enqueue_complete_buffer(node);
|
||||||
// We must relock only because the caller will unlock, for the normal
|
// We must relock only because the caller will unlock, for the normal
|
||||||
// case.
|
// case.
|
||||||
_lock->lock_without_safepoint_check();
|
_lock->lock_without_safepoint_check();
|
||||||
|
@ -157,10 +153,9 @@ void** PtrQueueSet::allocate_buffer() {
|
||||||
return BufferNode::make_buffer_from_node(node);
|
return BufferNode::make_buffer_from_node(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtrQueueSet::deallocate_buffer(void** buf) {
|
void PtrQueueSet::deallocate_buffer(BufferNode* node) {
|
||||||
assert(_sz > 0, "Didn't set a buffer size.");
|
assert(_sz > 0, "Didn't set a buffer size.");
|
||||||
MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
|
||||||
BufferNode *node = BufferNode::make_node_from_buffer(buf);
|
|
||||||
node->set_next(_fl_owner->_buf_free_list);
|
node->set_next(_fl_owner->_buf_free_list);
|
||||||
_fl_owner->_buf_free_list = node;
|
_fl_owner->_buf_free_list = node;
|
||||||
_fl_owner->_buf_free_list_sz++;
|
_fl_owner->_buf_free_list_sz++;
|
||||||
|
@ -211,10 +206,10 @@ void PtrQueue::handle_zero_index() {
|
||||||
// preventing the subsequent the multiple enqueue, and
|
// preventing the subsequent the multiple enqueue, and
|
||||||
// install a newly allocated buffer below.
|
// install a newly allocated buffer below.
|
||||||
|
|
||||||
void** buf = _buf; // local pointer to completed buffer
|
BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
|
||||||
_buf = NULL; // clear shared _buf field
|
_buf = NULL; // clear shared _buf field
|
||||||
|
|
||||||
locking_enqueue_completed_buffer(buf); // enqueue completed buffer
|
locking_enqueue_completed_buffer(node); // enqueue completed buffer
|
||||||
|
|
||||||
// While the current thread was enqueueing the buffer another thread
|
// While the current thread was enqueueing the buffer another thread
|
||||||
// may have a allocated a new buffer and inserted it into this pointer
|
// may have a allocated a new buffer and inserted it into this pointer
|
||||||
|
@ -224,9 +219,11 @@ void PtrQueue::handle_zero_index() {
|
||||||
|
|
||||||
if (_buf != NULL) return;
|
if (_buf != NULL) return;
|
||||||
} else {
|
} else {
|
||||||
if (qset()->process_or_enqueue_complete_buffer(_buf)) {
|
BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
|
||||||
|
if (qset()->process_or_enqueue_complete_buffer(node)) {
|
||||||
// Recycle the buffer. No allocation.
|
// Recycle the buffer. No allocation.
|
||||||
_sz = qset()->buffer_size();
|
assert(_buf == BufferNode::make_buffer_from_node(node), "invariant");
|
||||||
|
assert(_sz == qset()->buffer_size(), "invariant");
|
||||||
_index = _sz;
|
_index = _sz;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -238,12 +235,12 @@ void PtrQueue::handle_zero_index() {
|
||||||
_index = _sz;
|
_index = _sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
|
bool PtrQueueSet::process_or_enqueue_complete_buffer(BufferNode* node) {
|
||||||
if (Thread::current()->is_Java_thread()) {
|
if (Thread::current()->is_Java_thread()) {
|
||||||
// We don't lock. It is fine to be epsilon-precise here.
|
// We don't lock. It is fine to be epsilon-precise here.
|
||||||
if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
|
if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
|
||||||
_n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
|
_n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
|
||||||
bool b = mut_process_buffer(buf);
|
bool b = mut_process_buffer(node);
|
||||||
if (b) {
|
if (b) {
|
||||||
// True here means that the buffer hasn't been deallocated and the caller may reuse it.
|
// True here means that the buffer hasn't been deallocated and the caller may reuse it.
|
||||||
return true;
|
return true;
|
||||||
|
@ -251,14 +248,12 @@ bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The buffer will be enqueued. The caller will have to get a new one.
|
// The buffer will be enqueued. The caller will have to get a new one.
|
||||||
enqueue_complete_buffer(buf);
|
enqueue_complete_buffer(node);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
|
void PtrQueueSet::enqueue_complete_buffer(BufferNode* cbn) {
|
||||||
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
|
||||||
BufferNode* cbn = BufferNode::make_node_from_buffer(buf);
|
|
||||||
cbn->set_index(index);
|
|
||||||
cbn->set_next(NULL);
|
cbn->set_next(NULL);
|
||||||
if (_completed_buffers_tail == NULL) {
|
if (_completed_buffers_tail == NULL) {
|
||||||
assert(_completed_buffers_head == NULL, "Well-formedness");
|
assert(_completed_buffers_head == NULL, "Well-formedness");
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
// the addresses of modified old-generation objects. This type supports
|
// the addresses of modified old-generation objects. This type supports
|
||||||
// this operation.
|
// this operation.
|
||||||
|
|
||||||
|
class BufferNode;
|
||||||
class PtrQueueSet;
|
class PtrQueueSet;
|
||||||
class PtrQueue VALUE_OBJ_CLASS_SPEC {
|
class PtrQueue VALUE_OBJ_CLASS_SPEC {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
|
@ -104,7 +105,7 @@ public:
|
||||||
// get into an infinite loop).
|
// get into an infinite loop).
|
||||||
virtual bool should_enqueue_buffer() { return true; }
|
virtual bool should_enqueue_buffer() { return true; }
|
||||||
void handle_zero_index();
|
void handle_zero_index();
|
||||||
void locking_enqueue_completed_buffer(void** buf);
|
void locking_enqueue_completed_buffer(BufferNode* node);
|
||||||
|
|
||||||
void enqueue_known_active(void* ptr);
|
void enqueue_known_active(void* ptr);
|
||||||
|
|
||||||
|
@ -136,6 +137,10 @@ public:
|
||||||
return ind / sizeof(void*);
|
return ind / sizeof(void*);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t index_to_byte_index(size_t ind) {
|
||||||
|
return ind * sizeof(void*);
|
||||||
|
}
|
||||||
|
|
||||||
// To support compiler.
|
// To support compiler.
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -186,10 +191,13 @@ public:
|
||||||
// Free a BufferNode.
|
// Free a BufferNode.
|
||||||
static void deallocate(BufferNode* node);
|
static void deallocate(BufferNode* node);
|
||||||
|
|
||||||
// Return the BufferNode containing the buffer.
|
// Return the BufferNode containing the buffer, after setting its index.
|
||||||
static BufferNode* make_node_from_buffer(void** buffer) {
|
static BufferNode* make_node_from_buffer(void** buffer, size_t index) {
|
||||||
return reinterpret_cast<BufferNode*>(
|
BufferNode* node =
|
||||||
|
reinterpret_cast<BufferNode*>(
|
||||||
reinterpret_cast<char*>(buffer) - buffer_offset());
|
reinterpret_cast<char*>(buffer) - buffer_offset());
|
||||||
|
node->set_index(index);
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the buffer for node.
|
// Return the buffer for node.
|
||||||
|
@ -243,7 +251,7 @@ protected:
|
||||||
// A mutator thread does the the work of processing a buffer.
|
// A mutator thread does the the work of processing a buffer.
|
||||||
// Returns "true" iff the work is complete (and the buffer may be
|
// Returns "true" iff the work is complete (and the buffer may be
|
||||||
// deallocated).
|
// deallocated).
|
||||||
virtual bool mut_process_buffer(void** buf) {
|
virtual bool mut_process_buffer(BufferNode* node) {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -267,13 +275,13 @@ public:
|
||||||
|
|
||||||
// Return an empty buffer to the free list. The "buf" argument is
|
// Return an empty buffer to the free list. The "buf" argument is
|
||||||
// required to be a pointer to the head of an array of length "_sz".
|
// required to be a pointer to the head of an array of length "_sz".
|
||||||
void deallocate_buffer(void** buf);
|
void deallocate_buffer(BufferNode* node);
|
||||||
|
|
||||||
// Declares that "buf" is a complete buffer.
|
// Declares that "buf" is a complete buffer.
|
||||||
void enqueue_complete_buffer(void** buf, size_t index = 0);
|
void enqueue_complete_buffer(BufferNode* node);
|
||||||
|
|
||||||
// To be invoked by the mutator.
|
// To be invoked by the mutator.
|
||||||
bool process_or_enqueue_complete_buffer(void** buf);
|
bool process_or_enqueue_complete_buffer(BufferNode* node);
|
||||||
|
|
||||||
bool completed_buffers_exist_dirty() {
|
bool completed_buffers_exist_dirty() {
|
||||||
return _n_completed_buffers > 0;
|
return _n_completed_buffers > 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -100,6 +100,10 @@ inline bool requires_marking(const void* entry, G1CollectedHeap* heap) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool retain_entry(const void* entry, G1CollectedHeap* heap) {
|
||||||
|
return requires_marking(entry, heap) && !heap->isMarkedNext((oop)entry);
|
||||||
|
}
|
||||||
|
|
||||||
// This method removes entries from a SATB buffer that will not be
|
// This method removes entries from a SATB buffer that will not be
|
||||||
// useful to the concurrent marking threads. Entries are retained if
|
// useful to the concurrent marking threads. Entries are retained if
|
||||||
// they require marking and are not already marked. Retained entries
|
// they require marking and are not already marked. Retained entries
|
||||||
|
@ -114,43 +118,28 @@ void SATBMarkQueue::filter() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used for sanity checking at the end of the loop.
|
|
||||||
DEBUG_ONLY(size_t entries = 0; size_t retained = 0;)
|
|
||||||
|
|
||||||
assert(_index <= _sz, "invariant");
|
assert(_index <= _sz, "invariant");
|
||||||
void** limit = &buf[byte_index_to_index(_index)];
|
|
||||||
void** src = &buf[byte_index_to_index(_sz)];
|
|
||||||
void** dst = src;
|
|
||||||
|
|
||||||
while (limit < src) {
|
// Two-fingered compaction toward the end.
|
||||||
DEBUG_ONLY(entries += 1;)
|
void** src = &buf[byte_index_to_index(_index)];
|
||||||
--src;
|
void** dst = &buf[byte_index_to_index(_sz)];
|
||||||
|
for ( ; src < dst; ++src) {
|
||||||
|
// Search low to high for an entry to keep.
|
||||||
void* entry = *src;
|
void* entry = *src;
|
||||||
// NULL the entry so that unused parts of the buffer contain NULLs
|
if (retain_entry(entry, g1h)) {
|
||||||
// at the end. If we are going to retain it we will copy it to its
|
// Found keeper. Search high to low for an entry to discard.
|
||||||
// final place. If we have retained all entries we have visited so
|
while (src < --dst) {
|
||||||
// far, we'll just end up copying it to the same place.
|
if (!retain_entry(*dst, g1h)) {
|
||||||
*src = NULL;
|
*dst = entry; // Replace discard with keeper.
|
||||||
|
break;
|
||||||
if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) {
|
|
||||||
--dst;
|
|
||||||
assert(*dst == NULL, "filtering destination should be clear");
|
|
||||||
*dst = entry;
|
|
||||||
DEBUG_ONLY(retained += 1;);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t new_index = pointer_delta(dst, buf, 1);
|
// If discard search failed (src == dst), the outer loop will also end.
|
||||||
|
}
|
||||||
#ifdef ASSERT
|
}
|
||||||
size_t entries_calc = (_sz - _index) / sizeof(void*);
|
// dst points to the lowest retained entry, or the end of the buffer
|
||||||
assert(entries == entries_calc, "the number of entries we counted "
|
// if all the entries were filtered out.
|
||||||
"should match the number of entries we calculated");
|
_index = pointer_delta(dst, buf, 1);
|
||||||
size_t retained_calc = (_sz - new_index) / sizeof(void*);
|
|
||||||
assert(retained == retained_calc, "the number of retained entries we counted "
|
|
||||||
"should match the number of retained entries we calculated");
|
|
||||||
#endif // ASSERT
|
|
||||||
|
|
||||||
_index = new_index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method will first apply the above filtering to the buffer. If
|
// This method will first apply the above filtering to the buffer. If
|
||||||
|
@ -286,19 +275,11 @@ bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl)
|
||||||
}
|
}
|
||||||
if (nd != NULL) {
|
if (nd != NULL) {
|
||||||
void **buf = BufferNode::make_buffer_from_node(nd);
|
void **buf = BufferNode::make_buffer_from_node(nd);
|
||||||
// Skip over NULL entries at beginning (e.g. push end) of buffer.
|
size_t index = SATBMarkQueue::byte_index_to_index(nd->index());
|
||||||
// Filtering can result in non-full completed buffers; see
|
size_t size = SATBMarkQueue::byte_index_to_index(_sz);
|
||||||
// should_enqueue_buffer.
|
assert(index <= size, "invariant");
|
||||||
assert(_sz % sizeof(void*) == 0, "invariant");
|
cl->do_buffer(buf + index, size - index);
|
||||||
size_t limit = SATBMarkQueue::byte_index_to_index(_sz);
|
deallocate_buffer(nd);
|
||||||
for (size_t i = 0; i < limit; ++i) {
|
|
||||||
if (buf[i] != NULL) {
|
|
||||||
// Found the end of the block of NULLs; process the remainder.
|
|
||||||
cl->do_buffer(buf + i, limit - i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deallocate_buffer(buf);
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -355,7 +336,7 @@ void SATBMarkQueueSet::abandon_partial_marking() {
|
||||||
while (buffers_to_delete != NULL) {
|
while (buffers_to_delete != NULL) {
|
||||||
BufferNode* nd = buffers_to_delete;
|
BufferNode* nd = buffers_to_delete;
|
||||||
buffers_to_delete = nd->next();
|
buffers_to_delete = nd->next();
|
||||||
deallocate_buffer(BufferNode::make_buffer_from_node(nd));
|
deallocate_buffer(nd);
|
||||||
}
|
}
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
||||||
// So we can safely manipulate these queues.
|
// So we can safely manipulate these queues.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -115,9 +115,8 @@ public:
|
||||||
|
|
||||||
// If there exists some completed buffer, pop and process it, and
|
// If there exists some completed buffer, pop and process it, and
|
||||||
// return true. Otherwise return false. Processing a buffer
|
// return true. Otherwise return false. Processing a buffer
|
||||||
// consists of applying the closure to the buffer range starting
|
// consists of applying the closure to the active range of the
|
||||||
// with the first non-NULL entry to the end of the buffer; the
|
// buffer; the leading entries may be excluded due to filtering.
|
||||||
// leading entries may be NULL due to filtering.
|
|
||||||
bool apply_closure_to_completed_buffer(SATBBufferClosure* cl);
|
bool apply_closure_to_completed_buffer(SATBBufferClosure* cl);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -113,7 +113,7 @@ void GCTaskThread::run() {
|
||||||
}
|
}
|
||||||
if (!os::bind_to_processor(processor_id())) {
|
if (!os::bind_to_processor(processor_id())) {
|
||||||
DEBUG_ONLY(
|
DEBUG_ONLY(
|
||||||
warning("Couldn't bind GCTaskThread %u to processor %u",
|
log_warning(gc)("Couldn't bind GCTaskThread %u to processor %u",
|
||||||
which(), processor_id());
|
which(), processor_id());
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,8 +325,8 @@ HeapWord* ParallelScavengeHeap::mem_allocate(
|
||||||
loop_count++;
|
loop_count++;
|
||||||
if ((result == NULL) && (QueuedAllocationWarningCount > 0) &&
|
if ((result == NULL) && (QueuedAllocationWarningCount > 0) &&
|
||||||
(loop_count % QueuedAllocationWarningCount == 0)) {
|
(loop_count % QueuedAllocationWarningCount == 0)) {
|
||||||
warning("ParallelScavengeHeap::mem_allocate retries %d times \n\t"
|
log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count);
|
||||||
" size=" SIZE_FORMAT, loop_count, size);
|
log_warning(gc)("\tsize=" SIZE_FORMAT, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -638,7 +638,7 @@ jlong PSMarkSweep::millis_since_last_gc() {
|
||||||
jlong ret_val = now - _time_of_last_gc;
|
jlong ret_val = now - _time_of_last_gc;
|
||||||
// XXX See note in genCollectedHeap::millis_since_last_gc().
|
// XXX See note in genCollectedHeap::millis_since_last_gc().
|
||||||
if (ret_val < 0) {
|
if (ret_val < 0) {
|
||||||
NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, ret_val);)
|
NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, ret_val);)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return ret_val;
|
return ret_val;
|
||||||
|
|
|
@ -309,7 +309,7 @@ bool PSOldGen::expand_to_reserved() {
|
||||||
const size_t remaining_bytes = virtual_space()->uncommitted_size();
|
const size_t remaining_bytes = virtual_space()->uncommitted_size();
|
||||||
if (remaining_bytes > 0) {
|
if (remaining_bytes > 0) {
|
||||||
result = expand_by(remaining_bytes);
|
result = expand_by(remaining_bytes);
|
||||||
DEBUG_ONLY(if (!result) warning("grow to reserve failed"));
|
DEBUG_ONLY(if (!result) log_warning(gc)("grow to reserve failed"));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2467,8 +2467,7 @@ void PSParallelCompact::verify_complete(SpaceId space_id) {
|
||||||
for (cur_region = beg_region; cur_region < new_top_region; ++cur_region) {
|
for (cur_region = beg_region; cur_region < new_top_region; ++cur_region) {
|
||||||
const RegionData* const c = sd.region(cur_region);
|
const RegionData* const c = sd.region(cur_region);
|
||||||
if (!c->completed()) {
|
if (!c->completed()) {
|
||||||
warning("region " SIZE_FORMAT " not filled: "
|
log_warning(gc)("region " SIZE_FORMAT " not filled: destination_count=%u",
|
||||||
"destination_count=%u",
|
|
||||||
cur_region, c->destination_count());
|
cur_region, c->destination_count());
|
||||||
issued_a_warning = true;
|
issued_a_warning = true;
|
||||||
}
|
}
|
||||||
|
@ -2477,8 +2476,7 @@ void PSParallelCompact::verify_complete(SpaceId space_id) {
|
||||||
for (cur_region = new_top_region; cur_region < old_top_region; ++cur_region) {
|
for (cur_region = new_top_region; cur_region < old_top_region; ++cur_region) {
|
||||||
const RegionData* const c = sd.region(cur_region);
|
const RegionData* const c = sd.region(cur_region);
|
||||||
if (!c->available()) {
|
if (!c->available()) {
|
||||||
warning("region " SIZE_FORMAT " not empty: "
|
log_warning(gc)("region " SIZE_FORMAT " not empty: destination_count=%u",
|
||||||
"destination_count=%u",
|
|
||||||
cur_region, c->destination_count());
|
cur_region, c->destination_count());
|
||||||
issued_a_warning = true;
|
issued_a_warning = true;
|
||||||
}
|
}
|
||||||
|
@ -3013,7 +3011,7 @@ jlong PSParallelCompact::millis_since_last_gc() {
|
||||||
jlong ret_val = now - _time_of_last_gc;
|
jlong ret_val = now - _time_of_last_gc;
|
||||||
// XXX See note in genCollectedHeap::millis_since_last_gc().
|
// XXX See note in genCollectedHeap::millis_since_last_gc().
|
||||||
if (ret_val < 0) {
|
if (ret_val < 0) {
|
||||||
NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, ret_val);)
|
NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, ret_val);)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return ret_val;
|
return ret_val;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -144,7 +144,7 @@ bool CardGeneration::grow_to_reserved() {
|
||||||
const size_t remaining_bytes = _virtual_space.uncommitted_size();
|
const size_t remaining_bytes = _virtual_space.uncommitted_size();
|
||||||
if (remaining_bytes > 0) {
|
if (remaining_bytes > 0) {
|
||||||
success = grow_by(remaining_bytes);
|
success = grow_by(remaining_bytes);
|
||||||
DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
|
DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");)
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -325,17 +325,17 @@ void CardTableRS::younger_refs_in_space_iterate(Space* sp,
|
||||||
// In the case of CMS+ParNew, issue a warning
|
// In the case of CMS+ParNew, issue a warning
|
||||||
if (!ur.contains(urasm)) {
|
if (!ur.contains(urasm)) {
|
||||||
assert(UseConcMarkSweepGC, "Tautology: see assert above");
|
assert(UseConcMarkSweepGC, "Tautology: see assert above");
|
||||||
warning("CMS+ParNew: Did you forget to call save_marks()? "
|
log_warning(gc)("CMS+ParNew: Did you forget to call save_marks()? "
|
||||||
"[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
|
"[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
|
||||||
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||||
p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
|
p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
|
||||||
MemRegion ur2 = sp->used_region();
|
MemRegion ur2 = sp->used_region();
|
||||||
MemRegion urasm2 = sp->used_region_at_save_marks();
|
MemRegion urasm2 = sp->used_region_at_save_marks();
|
||||||
if (!ur.equals(ur2)) {
|
if (!ur.equals(ur2)) {
|
||||||
warning("CMS+ParNew: Flickering used_region()!!");
|
log_warning(gc)("CMS+ParNew: Flickering used_region()!!");
|
||||||
}
|
}
|
||||||
if (!urasm.equals(urasm2)) {
|
if (!urasm.equals(urasm2)) {
|
||||||
warning("CMS+ParNew: Flickering used_region_at_save_marks()!!");
|
log_warning(gc)("CMS+ParNew: Flickering used_region_at_save_marks()!!");
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1272,7 +1272,7 @@ jlong GenCollectedHeap::millis_since_last_gc() {
|
||||||
// back a time later than 'now'.
|
// back a time later than 'now'.
|
||||||
jlong retVal = now - tolgc_cl.time();
|
jlong retVal = now - tolgc_cl.time();
|
||||||
if (retVal < 0) {
|
if (retVal < 0) {
|
||||||
NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, retVal);)
|
NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, retVal);)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "gc/shared/collectorCounters.hpp"
|
#include "gc/shared/collectorCounters.hpp"
|
||||||
#include "gc/shared/referenceProcessor.hpp"
|
#include "gc/shared/referenceProcessor.hpp"
|
||||||
|
#include "logging/log.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/memRegion.hpp"
|
#include "memory/memRegion.hpp"
|
||||||
#include "memory/universe.hpp"
|
#include "memory/universe.hpp"
|
||||||
|
@ -377,7 +378,7 @@ class Generation: public CHeapObj<mtGC> {
|
||||||
// have to guard against non-monotonicity.
|
// have to guard against non-monotonicity.
|
||||||
NOT_PRODUCT(
|
NOT_PRODUCT(
|
||||||
if (now < _time_of_last_gc) {
|
if (now < _time_of_last_gc) {
|
||||||
warning("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, _time_of_last_gc, now);
|
log_warning(gc)("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, _time_of_last_gc, now);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return _time_of_last_gc;
|
return _time_of_last_gc;
|
||||||
|
|
|
@ -136,7 +136,7 @@ void PLABStats::log_sizing(size_t calculated_words, size_t net_desired_words) {
|
||||||
|
|
||||||
// Calculates plab size for current number of gc worker threads.
|
// Calculates plab size for current number of gc worker threads.
|
||||||
size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) {
|
size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) {
|
||||||
return MAX2(min_size(), (size_t)align_object_size(_desired_net_plab_sz / no_of_gc_workers));
|
return (size_t)align_object_size(MIN2(MAX2(min_size(), _desired_net_plab_sz / no_of_gc_workers), max_size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute desired plab size for one gc worker thread and latch result for later
|
// Compute desired plab size for one gc worker thread and latch result for later
|
||||||
|
@ -175,14 +175,9 @@ void PLABStats::adjust_desired_plab_sz() {
|
||||||
size_t recent_plab_sz = used / target_refills;
|
size_t recent_plab_sz = used / target_refills;
|
||||||
// Take historical weighted average
|
// Take historical weighted average
|
||||||
_filter.sample(recent_plab_sz);
|
_filter.sample(recent_plab_sz);
|
||||||
// Clip from above and below, and align to object boundary
|
_desired_net_plab_sz = MAX2(min_size(), (size_t)_filter.average());
|
||||||
size_t new_plab_sz = MAX2(min_size(), (size_t)_filter.average());
|
|
||||||
new_plab_sz = MIN2(max_size(), new_plab_sz);
|
|
||||||
new_plab_sz = align_object_size(new_plab_sz);
|
|
||||||
// Latch the result
|
|
||||||
_desired_net_plab_sz = new_plab_sz;
|
|
||||||
|
|
||||||
log_sizing(recent_plab_sz, new_plab_sz);
|
log_sizing(recent_plab_sz, _desired_net_plab_sz);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ void ReferenceProcessor::update_soft_ref_master_clock() {
|
||||||
|
|
||||||
NOT_PRODUCT(
|
NOT_PRODUCT(
|
||||||
if (now < _soft_ref_timestamp_clock) {
|
if (now < _soft_ref_timestamp_clock) {
|
||||||
warning("time warp: " JLONG_FORMAT " to " JLONG_FORMAT,
|
log_warning(gc)("time warp: " JLONG_FORMAT " to " JLONG_FORMAT,
|
||||||
_soft_ref_timestamp_clock, now);
|
_soft_ref_timestamp_clock, now);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -645,9 +645,7 @@ public:
|
||||||
OopClosure& keep_alive,
|
OopClosure& keep_alive,
|
||||||
VoidClosure& complete_gc)
|
VoidClosure& complete_gc)
|
||||||
{
|
{
|
||||||
Thread* thr = Thread::current();
|
_ref_processor.process_phase1(_refs_lists[i], _policy,
|
||||||
int refs_list_index = ((WorkerThread*)thr)->id();
|
|
||||||
_ref_processor.process_phase1(_refs_lists[refs_list_index], _policy,
|
|
||||||
&is_alive, &keep_alive, &complete_gc);
|
&is_alive, &keep_alive, &complete_gc);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
@ -683,11 +681,6 @@ public:
|
||||||
OopClosure& keep_alive,
|
OopClosure& keep_alive,
|
||||||
VoidClosure& complete_gc)
|
VoidClosure& complete_gc)
|
||||||
{
|
{
|
||||||
// Don't use "refs_list_index" calculated in this way because
|
|
||||||
// balance_queues() has moved the Ref's into the first n queues.
|
|
||||||
// Thread* thr = Thread::current();
|
|
||||||
// int refs_list_index = ((WorkerThread*)thr)->id();
|
|
||||||
// _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent,
|
|
||||||
_ref_processor.process_phase3(_refs_lists[i], _clear_referent,
|
_ref_processor.process_phase3(_refs_lists[i], _clear_referent,
|
||||||
&is_alive, &keep_alive, &complete_gc);
|
&is_alive, &keep_alive, &complete_gc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -160,7 +160,7 @@ void VM_GC_HeapInspection::doit() {
|
||||||
// be about to attempt holds value for us only
|
// be about to attempt holds value for us only
|
||||||
// if it happens now and not if it happens in the eventual
|
// if it happens now and not if it happens in the eventual
|
||||||
// future.
|
// future.
|
||||||
warning("GC locker is held; pre-dump GC was skipped");
|
log_warning(gc)("GC locker is held; pre-dump GC was skipped");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HeapInspection inspect(_csv_format, _print_help, _print_class_stats,
|
HeapInspection inspect(_csv_format, _print_help, _print_class_stats,
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#ifndef SHARE_VM_LOGGING_LOGTAG_HPP
|
#ifndef SHARE_VM_LOGGING_LOGTAG_HPP
|
||||||
#define SHARE_VM_LOGGING_LOGTAG_HPP
|
#define SHARE_VM_LOGGING_LOGTAG_HPP
|
||||||
|
|
||||||
|
#include "logging/logTag_ext.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
|
@ -76,6 +77,7 @@
|
||||||
LOG_TAG(safepointcleanup) \
|
LOG_TAG(safepointcleanup) \
|
||||||
LOG_TAG(scavenge) \
|
LOG_TAG(scavenge) \
|
||||||
LOG_TAG(scrub) \
|
LOG_TAG(scrub) \
|
||||||
|
LOG_TAG(stacktrace) \
|
||||||
LOG_TAG(start) \
|
LOG_TAG(start) \
|
||||||
LOG_TAG(startuptime) \
|
LOG_TAG(startuptime) \
|
||||||
LOG_TAG(state) \
|
LOG_TAG(state) \
|
||||||
|
@ -90,7 +92,8 @@
|
||||||
LOG_TAG(verboseverification) \
|
LOG_TAG(verboseverification) \
|
||||||
LOG_TAG(verify) \
|
LOG_TAG(verify) \
|
||||||
LOG_TAG(vmoperation) \
|
LOG_TAG(vmoperation) \
|
||||||
LOG_TAG(vtables)
|
LOG_TAG(vtables) \
|
||||||
|
LOG_TAG_LIST_EXT
|
||||||
|
|
||||||
#define PREFIX_LOG_TAG(T) (LogTag::_##T)
|
#define PREFIX_LOG_TAG(T) (LogTag::_##T)
|
||||||
|
|
||||||
|
|
29
hotspot/src/share/vm/logging/logTag_ext.hpp
Normal file
29
hotspot/src/share/vm/logging/logTag_ext.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef SHARE_VM_LOGGING_LOGTAG_EXT_HPP
|
||||||
|
#define SHARE_VM_LOGGING_LOGTAG_EXT_HPP
|
||||||
|
|
||||||
|
#define LOG_TAG_LIST_EXT
|
||||||
|
|
||||||
|
#endif // SHARE_VM_LOGGING_LOGTAG_EXT_HPP
|
|
@ -376,8 +376,7 @@ void Universe::genesis(TRAPS) {
|
||||||
// We can allocate directly in the permanent generation, so we do.
|
// We can allocate directly in the permanent generation, so we do.
|
||||||
int size;
|
int size;
|
||||||
if (UseConcMarkSweepGC) {
|
if (UseConcMarkSweepGC) {
|
||||||
warning("Using +FullGCALot with concurrent mark sweep gc "
|
log_warning(gc)("Using +FullGCALot with concurrent mark sweep gc will not force all objects to relocate");
|
||||||
"will not force all objects to relocate");
|
|
||||||
size = FullGCALotDummies;
|
size = FullGCALotDummies;
|
||||||
} else {
|
} else {
|
||||||
size = FullGCALotDummies * 2;
|
size = FullGCALotDummies * 2;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -514,19 +514,13 @@ JVM_ENTRY(void, JVM_FillInStackTrace(JNIEnv *env, jobject receiver))
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
|
||||||
JVM_ENTRY(jint, JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable))
|
JVM_ENTRY(void, JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray stackTrace))
|
||||||
JVMWrapper("JVM_GetStackTraceDepth");
|
JVMWrapper("JVM_GetStackTraceElements");
|
||||||
oop exception = JNIHandles::resolve(throwable);
|
Handle exception(THREAD, JNIHandles::resolve(throwable));
|
||||||
return java_lang_Throwable::get_stack_trace_depth(exception, THREAD);
|
objArrayOop st = objArrayOop(JNIHandles::resolve(stackTrace));
|
||||||
JVM_END
|
objArrayHandle stack_trace(THREAD, st);
|
||||||
|
// Fill in the allocated stack trace
|
||||||
|
java_lang_Throwable::get_stack_trace_elements(exception, stack_trace, CHECK);
|
||||||
JVM_ENTRY(jobject, JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index))
|
|
||||||
JVMWrapper("JVM_GetStackTraceElement");
|
|
||||||
JvmtiVMObjectAllocEventCollector oam; // This ctor (throughout this module) may trigger a safepoint/GC
|
|
||||||
oop exception = JNIHandles::resolve(throwable);
|
|
||||||
oop element = java_lang_Throwable::get_stack_trace_element(exception, index, CHECK_NULL);
|
|
||||||
return JNIHandles::make_local(env, element);
|
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -201,11 +201,8 @@ JVM_GetVmArguments(JNIEnv *env);
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
JVM_FillInStackTrace(JNIEnv *env, jobject throwable);
|
JVM_FillInStackTrace(JNIEnv *env, jobject throwable);
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT void JNICALL
|
||||||
JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable);
|
JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements);
|
||||||
|
|
||||||
JNIEXPORT jobject JNICALL
|
|
||||||
JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* java.lang.StackWalker
|
* java.lang.StackWalker
|
||||||
|
|
|
@ -1049,9 +1049,6 @@ public:
|
||||||
"directory) of the dump file (defaults to java_pid<pid>.hprof " \
|
"directory) of the dump file (defaults to java_pid<pid>.hprof " \
|
||||||
"in the working directory)") \
|
"in the working directory)") \
|
||||||
\
|
\
|
||||||
develop(size_t, HeapDumpSegmentSize, 1*G, \
|
|
||||||
"Approximate segment size when generating a segmented heap dump") \
|
|
||||||
\
|
|
||||||
develop(bool, BreakAtWarning, false, \
|
develop(bool, BreakAtWarning, false, \
|
||||||
"Execute breakpoint upon encountering VM warning") \
|
"Execute breakpoint upon encountering VM warning") \
|
||||||
\
|
\
|
||||||
|
@ -2065,9 +2062,6 @@ public:
|
||||||
develop(uintx, MetadataAllocationFailALotInterval, 1000, \
|
develop(uintx, MetadataAllocationFailALotInterval, 1000, \
|
||||||
"Metadata allocation failure a lot interval") \
|
"Metadata allocation failure a lot interval") \
|
||||||
\
|
\
|
||||||
develop(bool, TraceMetadataChunkAllocation, false, \
|
|
||||||
"Trace chunk metadata allocations") \
|
|
||||||
\
|
|
||||||
notproduct(bool, ExecuteInternalVMTests, false, \
|
notproduct(bool, ExecuteInternalVMTests, false, \
|
||||||
"Enable execution of internal VM tests") \
|
"Enable execution of internal VM tests") \
|
||||||
\
|
\
|
||||||
|
@ -2774,10 +2768,6 @@ public:
|
||||||
"Produce histogram of IC misses") \
|
"Produce histogram of IC misses") \
|
||||||
\
|
\
|
||||||
/* interpreter */ \
|
/* interpreter */ \
|
||||||
develop(bool, ClearInterpreterLocals, false, \
|
|
||||||
"Always clear local variables of interpreter activations upon " \
|
|
||||||
"entry") \
|
|
||||||
\
|
|
||||||
product_pd(bool, RewriteBytecodes, \
|
product_pd(bool, RewriteBytecodes, \
|
||||||
"Allow rewriting of bytecodes (bytecodes are not immutable)") \
|
"Allow rewriting of bytecodes (bytecodes are not immutable)") \
|
||||||
\
|
\
|
||||||
|
|
64
hotspot/test/runtime/Throwable/StackTraceLogging.java
Normal file
64
hotspot/test/runtime/Throwable/StackTraceLogging.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8150778
|
||||||
|
* @summary check stacktrace logging
|
||||||
|
* @library /testlibrary
|
||||||
|
* @modules java.base/sun.misc
|
||||||
|
* java.management
|
||||||
|
* @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
|
||||||
|
* @compile TestThrowable.java
|
||||||
|
* @run driver StackTraceLogging
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
import jdk.test.lib.OutputAnalyzer;
|
||||||
|
import jdk.test.lib.ProcessTools;
|
||||||
|
|
||||||
|
public class StackTraceLogging {
|
||||||
|
static void updateEnvironment(ProcessBuilder pb, String environmentVariable, String value) {
|
||||||
|
Map<String, String> env = pb.environment();
|
||||||
|
env.put(environmentVariable, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
|
||||||
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
|
// These depths match the ones in TestThrowable.java
|
||||||
|
int[] depths = {10, 34, 100, 1024};
|
||||||
|
for (int d : depths) {
|
||||||
|
output.shouldContain("java.lang.RuntimeException, " + d);
|
||||||
|
}
|
||||||
|
output.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:stacktrace=info",
|
||||||
|
"-XX:MaxJavaStackTraceDepth=1024",
|
||||||
|
"TestThrowable");
|
||||||
|
analyzeOutputOn(pb);
|
||||||
|
}
|
||||||
|
}
|
78
hotspot/test/runtime/Throwable/TestThrowable.java
Normal file
78
hotspot/test/runtime/Throwable/TestThrowable.java
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8150778
|
||||||
|
* @summary Test exception depths, and code to get stack traces
|
||||||
|
* @library /testlibrary
|
||||||
|
* @run main/othervm -XX:MaxJavaStackTraceDepth=1024 TestThrowable
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
public class TestThrowable {
|
||||||
|
|
||||||
|
// Inner class that throws a lot of exceptions
|
||||||
|
static class Thrower {
|
||||||
|
static int MaxJavaStackTraceDepth = 1024; // as above
|
||||||
|
int[] depths = {10, 34, 100, 1024, 2042};
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
int getDepth(Throwable t) throws Exception {
|
||||||
|
Field f = Throwable.class.getDeclaredField("depth");
|
||||||
|
f.setAccessible(true); // it's private
|
||||||
|
return f.getInt(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void callThrow(int depth) {
|
||||||
|
if (++count < depth) {
|
||||||
|
callThrow(depth);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("depth tested " + depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void testThrow() throws Exception {
|
||||||
|
for (int d : depths) {
|
||||||
|
try {
|
||||||
|
count = getDepth(new Throwable());
|
||||||
|
callThrow(d);
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.getStackTrace();
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
int throwableDepth = getDepth(e);
|
||||||
|
Asserts.assertTrue(throwableDepth == d ||
|
||||||
|
(d > MaxJavaStackTraceDepth && throwableDepth == MaxJavaStackTraceDepth),
|
||||||
|
"depth should return the correct value: depth tested=" +
|
||||||
|
d + " throwableDepth=" + throwableDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String... unused) throws Exception {
|
||||||
|
Thrower t = new Thrower();
|
||||||
|
t.testThrow();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue