Merge
This commit is contained in:
commit
61592ca6fa
@ -628,12 +628,12 @@ char* java_lang_String::as_utf8_string(oop java_string, int start, int len, char
|
||||
bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
|
||||
assert(java_string->klass() == SystemDictionary::String_klass(),
|
||||
"must be java_string");
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int length = java_lang_String::length(java_string);
|
||||
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
|
||||
int length = java_lang_String::length(java_string);
|
||||
if (length != len) {
|
||||
return false;
|
||||
}
|
||||
bool is_latin1 = java_lang_String::is_latin1(java_string);
|
||||
bool is_latin1 = java_lang_String::is_latin1(java_string);
|
||||
if (!is_latin1) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (value->char_at(i) != chars[i]) {
|
||||
@ -655,12 +655,12 @@ bool java_lang_String::equals(oop str1, oop str2) {
|
||||
"must be java String");
|
||||
assert(str2->klass() == SystemDictionary::String_klass(),
|
||||
"must be java String");
|
||||
typeArrayOop value1 = java_lang_String::value(str1);
|
||||
int length1 = java_lang_String::length(str1);
|
||||
bool is_latin1 = java_lang_String::is_latin1(str1);
|
||||
typeArrayOop value2 = java_lang_String::value(str2);
|
||||
int length2 = java_lang_String::length(str2);
|
||||
bool is_latin2 = java_lang_String::is_latin1(str2);
|
||||
typeArrayOop value1 = java_lang_String::value_no_keepalive(str1);
|
||||
int length1 = java_lang_String::length(value1);
|
||||
bool is_latin1 = java_lang_String::is_latin1(str1);
|
||||
typeArrayOop value2 = java_lang_String::value_no_keepalive(str2);
|
||||
int length2 = java_lang_String::length(value2);
|
||||
bool is_latin2 = java_lang_String::is_latin1(str2);
|
||||
|
||||
if ((length1 != length2) || (is_latin1 != is_latin2)) {
|
||||
// Strings of different size or with different
|
||||
@ -668,7 +668,7 @@ bool java_lang_String::equals(oop str1, oop str2) {
|
||||
return false;
|
||||
}
|
||||
int blength1 = value1->length();
|
||||
for (int i = 0; i < value1->length(); i++) {
|
||||
for (int i = 0; i < blength1; i++) {
|
||||
if (value1->byte_at(i) != value2->byte_at(i)) {
|
||||
return false;
|
||||
}
|
||||
@ -678,7 +678,7 @@ bool java_lang_String::equals(oop str1, oop str2) {
|
||||
|
||||
void java_lang_String::print(oop java_string, outputStream* st) {
|
||||
assert(java_string->klass() == SystemDictionary::String_klass(), "must be java_string");
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
|
||||
|
||||
if (value == NULL) {
|
||||
// This can happen if, e.g., printing a String
|
||||
|
@ -102,6 +102,7 @@ class java_lang_String : AllStatic {
|
||||
|
||||
// Accessors
|
||||
static inline typeArrayOop value(oop java_string);
|
||||
static inline typeArrayOop value_no_keepalive(oop java_string);
|
||||
static inline unsigned int hash(oop java_string);
|
||||
static inline bool is_latin1(oop java_string);
|
||||
static inline int length(oop java_string);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP
|
||||
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
|
||||
@ -53,6 +54,11 @@ typeArrayOop java_lang_String::value(oop java_string) {
|
||||
assert(is_instance(java_string), "must be java_string");
|
||||
return (typeArrayOop) java_string->obj_field(value_offset);
|
||||
}
|
||||
typeArrayOop java_lang_String::value_no_keepalive(oop java_string) {
|
||||
assert(initialized && (value_offset > 0), "Must be initialized");
|
||||
assert(is_instance(java_string), "must be java_string");
|
||||
return (typeArrayOop) java_string->obj_field_access<AS_NO_KEEPALIVE>(value_offset);
|
||||
}
|
||||
unsigned int java_lang_String::hash(oop java_string) {
|
||||
assert(initialized && (hash_offset > 0), "Must be initialized");
|
||||
assert(is_instance(java_string), "must be java_string");
|
||||
@ -68,11 +74,11 @@ bool java_lang_String::is_latin1(oop java_string) {
|
||||
int java_lang_String::length(oop java_string) {
|
||||
assert(initialized, "Must be initialized");
|
||||
assert(is_instance(java_string), "must be java_string");
|
||||
typeArrayOop value_array = ((typeArrayOop)java_string->obj_field(value_offset));
|
||||
if (value_array == NULL) {
|
||||
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
|
||||
if (value == NULL) {
|
||||
return 0;
|
||||
}
|
||||
int arr_length = value_array->length();
|
||||
int arr_length = value->length();
|
||||
if (!is_latin1(java_string)) {
|
||||
assert((arr_length & 1) == 0, "should be even for UTF16 string");
|
||||
arr_length >>= 1; // convert number of bytes to number of elements
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "memory/filemap.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
@ -43,7 +44,6 @@
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#include "gc/g1/g1StringDedup.hpp"
|
||||
#endif
|
||||
|
||||
@ -124,6 +124,22 @@ unsigned int StringTable::hash_string(oop string) {
|
||||
}
|
||||
}
|
||||
|
||||
oop StringTable::string_object(HashtableEntry<oop, mtSymbol>* entry) {
|
||||
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(entry->literal_addr());
|
||||
}
|
||||
|
||||
oop StringTable::string_object_no_keepalive(HashtableEntry<oop, mtSymbol>* entry) {
|
||||
// The AS_NO_KEEPALIVE peeks at the oop without keeping it alive.
|
||||
// This is *very dangerous* in general but is okay in this specific
|
||||
// case. The subsequent oop_load keeps the oop alive if it it matched
|
||||
// the jchar* string.
|
||||
return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(entry->literal_addr());
|
||||
}
|
||||
|
||||
void StringTable::set_string_object(HashtableEntry<oop, mtSymbol>* entry, oop string) {
|
||||
RootAccess<ON_PHANTOM_OOP_REF>::oop_store(entry->literal_addr(), string);
|
||||
}
|
||||
|
||||
oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
|
||||
assert(hash == java_lang_String::hash_code(name, len),
|
||||
"hash must be computed using java_lang_String::hash_code");
|
||||
@ -131,13 +147,16 @@ oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
|
||||
}
|
||||
|
||||
oop StringTable::lookup_in_main_table(int index, jchar* name,
|
||||
int len, unsigned int hash) {
|
||||
int len, unsigned int hash) {
|
||||
int count = 0;
|
||||
for (HashtableEntry<oop, mtSymbol>* l = bucket(index); l != NULL; l = l->next()) {
|
||||
count++;
|
||||
if (l->hash() == hash) {
|
||||
if (java_lang_String::equals(l->literal(), name, len)) {
|
||||
return l->literal();
|
||||
if (java_lang_String::equals(string_object_no_keepalive(l), name, len)) {
|
||||
// We must perform a new load with string_object() that keeps the string
|
||||
// alive as we must expose the oop as strongly reachable when exiting
|
||||
// this context, in case the oop gets published.
|
||||
return string_object(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -192,18 +211,6 @@ oop StringTable::lookup(Symbol* symbol) {
|
||||
return lookup(chars, length);
|
||||
}
|
||||
|
||||
// Tell the GC that this string was looked up in the StringTable.
|
||||
static void ensure_string_alive(oop string) {
|
||||
// A lookup in the StringTable could return an object that was previously
|
||||
// considered dead. The SATB part of G1 needs to get notified about this
|
||||
// potential resurrection, otherwise the marking might not find the object.
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (UseG1GC && string != NULL) {
|
||||
G1SATBCardTableModRefBS::enqueue(string);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
oop StringTable::lookup(jchar* name, int len) {
|
||||
// shared table always uses java_lang_String::hash_code
|
||||
unsigned int hash = java_lang_String::hash_code(name, len);
|
||||
@ -217,8 +224,6 @@ oop StringTable::lookup(jchar* name, int len) {
|
||||
int index = the_table()->hash_to_index(hash);
|
||||
string = the_table()->lookup_in_main_table(index, name, len, hash);
|
||||
|
||||
ensure_string_alive(string);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
@ -238,9 +243,6 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
|
||||
|
||||
// Found
|
||||
if (found_string != NULL) {
|
||||
if (found_string != string_or_null()) {
|
||||
ensure_string_alive(found_string);
|
||||
}
|
||||
return found_string;
|
||||
}
|
||||
|
||||
@ -276,10 +278,6 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
|
||||
hashValue, CHECK_NULL);
|
||||
}
|
||||
|
||||
if (added_or_found != string()) {
|
||||
ensure_string_alive(added_or_found);
|
||||
}
|
||||
|
||||
return added_or_found;
|
||||
}
|
||||
|
||||
@ -388,9 +386,9 @@ void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClos
|
||||
while (entry != NULL) {
|
||||
assert(!entry->is_shared(), "CDS not used for the StringTable");
|
||||
|
||||
if (is_alive->do_object_b(entry->literal())) {
|
||||
if (is_alive->do_object_b(string_object_no_keepalive(entry))) {
|
||||
if (f != NULL) {
|
||||
f->do_oop((oop*)entry->literal_addr());
|
||||
f->do_oop(entry->literal_addr());
|
||||
}
|
||||
p = entry->next_addr();
|
||||
} else {
|
||||
@ -429,7 +427,7 @@ void StringTable::verify() {
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
|
||||
for ( ; p != NULL; p = p->next()) {
|
||||
oop s = p->literal();
|
||||
oop s = string_object_no_keepalive(p);
|
||||
guarantee(s != NULL, "interned string is NULL");
|
||||
unsigned int h = hash_string(s);
|
||||
guarantee(p->hash() == h, "broken hash in string table entry");
|
||||
@ -448,10 +446,10 @@ void StringTable::dump(outputStream* st, bool verbose) {
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
|
||||
for ( ; p != NULL; p = p->next()) {
|
||||
oop s = p->literal();
|
||||
typeArrayOop value = java_lang_String::value(s);
|
||||
int length = java_lang_String::length(s);
|
||||
bool is_latin1 = java_lang_String::is_latin1(s);
|
||||
oop s = string_object_no_keepalive(p);
|
||||
typeArrayOop value = java_lang_String::value_no_keepalive(s);
|
||||
int length = java_lang_String::length(s);
|
||||
bool is_latin1 = java_lang_String::is_latin1(s);
|
||||
|
||||
if (length <= 0) {
|
||||
st->print("%d: ", length);
|
||||
@ -484,8 +482,8 @@ StringTable::VerifyRetTypes StringTable::compare_entries(
|
||||
HashtableEntry<oop, mtSymbol>* e_ptr2) {
|
||||
// These entries are sanity checked by verify_and_compare_entries()
|
||||
// before this function is called.
|
||||
oop str1 = e_ptr1->literal();
|
||||
oop str2 = e_ptr2->literal();
|
||||
oop str1 = string_object_no_keepalive(e_ptr1);
|
||||
oop str2 = string_object_no_keepalive(e_ptr2);
|
||||
|
||||
if (str1 == str2) {
|
||||
tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") "
|
||||
@ -505,12 +503,12 @@ StringTable::VerifyRetTypes StringTable::compare_entries(
|
||||
}
|
||||
|
||||
StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt,
|
||||
HashtableEntry<oop, mtSymbol>* e_ptr,
|
||||
StringTable::VerifyMesgModes mesg_mode) {
|
||||
HashtableEntry<oop, mtSymbol>* e_ptr,
|
||||
StringTable::VerifyMesgModes mesg_mode) {
|
||||
|
||||
VerifyRetTypes ret = _verify_pass; // be optimistic
|
||||
|
||||
oop str = e_ptr->literal();
|
||||
oop str = string_object_no_keepalive(e_ptr);
|
||||
if (str == NULL) {
|
||||
if (mesg_mode == _verify_with_mesgs) {
|
||||
tty->print_cr("ERROR: NULL oop value in entry @ bucket[%d][%d]", bkt,
|
||||
@ -684,7 +682,7 @@ oop StringTable::create_archived_string(oop s, Thread* THREAD) {
|
||||
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||
|
||||
oop new_s = NULL;
|
||||
typeArrayOop v = java_lang_String::value(s);
|
||||
typeArrayOop v = java_lang_String::value_no_keepalive(s);
|
||||
typeArrayOop new_v = (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
|
||||
if (new_v == NULL) {
|
||||
return NULL;
|
||||
@ -708,7 +706,7 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
HashtableEntry<oop, mtSymbol>* bucket = the_table()->bucket(i);
|
||||
for ( ; bucket != NULL; bucket = bucket->next()) {
|
||||
oop s = bucket->literal();
|
||||
oop s = string_object_no_keepalive(bucket);
|
||||
unsigned int hash = java_lang_String::hash_code(s);
|
||||
if (hash == 0) {
|
||||
continue;
|
||||
@ -721,7 +719,7 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
|
||||
}
|
||||
|
||||
// set the archived string in bucket
|
||||
bucket->set_literal(new_s);
|
||||
set_string_object(bucket, new_s);
|
||||
|
||||
// add to the compact table
|
||||
writer->add(hash, new_s);
|
||||
@ -763,4 +761,3 @@ void StringTable::shared_oops_do(OopClosure* f) {
|
||||
_shared_table.oops_do(f);
|
||||
}
|
||||
#endif //INCLUDE_CDS_JAVA_HEAP
|
||||
|
||||
|
@ -76,6 +76,13 @@ private:
|
||||
static unsigned int hash_string(oop string);
|
||||
static unsigned int alt_hash_string(const jchar* s, int len);
|
||||
|
||||
// Accessors for the string roots in the hashtable entries.
|
||||
// Use string_object_no_keepalive() only when the value is not returned
|
||||
// outside of a scope where a thread transition is possible.
|
||||
static oop string_object(HashtableEntry<oop, mtSymbol>* entry);
|
||||
static oop string_object_no_keepalive(HashtableEntry<oop, mtSymbol>* entry);
|
||||
static void set_string_object(HashtableEntry<oop, mtSymbol>* entry, oop string);
|
||||
|
||||
StringTable() : RehashableHashtable<oop, mtSymbol>((int)StringTableSize,
|
||||
sizeof (HashtableEntry<oop, mtSymbol>)) {}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "gc/shared/specialized_oop_closures.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/memRegion.hpp"
|
||||
#include "oops/access.hpp"
|
||||
#include "oops/metadata.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
@ -178,6 +179,8 @@ class oopDesc {
|
||||
static inline void encode_store_heap_oop(oop* p, oop v);
|
||||
|
||||
// Access to fields in a instanceOop through these methods.
|
||||
template <DecoratorSet decorator>
|
||||
oop obj_field_access(int offset) const;
|
||||
oop obj_field(int offset) const;
|
||||
void obj_field_put(int offset, oop value);
|
||||
void obj_field_put_raw(int offset, oop value);
|
||||
|
@ -326,7 +326,10 @@ void oopDesc::encode_store_heap_oop(narrowOop* p, oop v) {
|
||||
*p = encode_heap_oop(v);
|
||||
}
|
||||
|
||||
template <DecoratorSet decorators>
|
||||
inline oop oopDesc::obj_field_access(int offset) const { return HeapAccess<decorators>::oop_load_at(as_oop(), offset); }
|
||||
inline oop oopDesc::obj_field(int offset) const { return HeapAccess<>::oop_load_at(as_oop(), offset); }
|
||||
|
||||
inline void oopDesc::obj_field_put(int offset, oop value) { HeapAccess<>::oop_store_at(as_oop(), offset, value); }
|
||||
|
||||
inline jbyte oopDesc::byte_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); }
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "code/codeCache.hpp"
|
||||
#include "jvmtifiles/jvmtiEnv.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/instanceMirrorKlass.hpp"
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
@ -52,10 +53,6 @@
|
||||
#include "runtime/vm_operations.hpp"
|
||||
#include "services/serviceUtil.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#include "gc/parallel/parallelScavengeHeap.hpp"
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
// JvmtiTagHashmapEntry
|
||||
//
|
||||
@ -78,22 +75,31 @@ class JvmtiTagHashmapEntry : public CHeapObj<mtInternal> {
|
||||
}
|
||||
|
||||
// constructor
|
||||
JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
|
||||
JvmtiTagHashmapEntry(oop object, jlong tag) { init(object, tag); }
|
||||
|
||||
public:
|
||||
|
||||
// accessor methods
|
||||
inline oop object() const { return _object; }
|
||||
inline oop* object_addr() { return &_object; }
|
||||
inline jlong tag() const { return _tag; }
|
||||
inline oop* object_addr() { return &_object; }
|
||||
inline oop object() { return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(object_addr()); }
|
||||
// Peek at the object without keeping it alive. The returned object must be
|
||||
// kept alive using a normal access if it leaks out of a thread transition from VM.
|
||||
inline oop object_peek() {
|
||||
return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(object_addr());
|
||||
}
|
||||
inline jlong tag() const { return _tag; }
|
||||
|
||||
inline void set_tag(jlong tag) {
|
||||
assert(tag != 0, "can't be zero");
|
||||
_tag = tag;
|
||||
}
|
||||
|
||||
inline JvmtiTagHashmapEntry* next() const { return _next; }
|
||||
inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
|
||||
inline bool equals(oop object) {
|
||||
return object == object_peek();
|
||||
}
|
||||
|
||||
inline JvmtiTagHashmapEntry* next() const { return _next; }
|
||||
inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
|
||||
};
|
||||
|
||||
|
||||
@ -211,7 +217,7 @@ class JvmtiTagHashmap : public CHeapObj<mtInternal> {
|
||||
JvmtiTagHashmapEntry* entry = _table[i];
|
||||
while (entry != NULL) {
|
||||
JvmtiTagHashmapEntry* next = entry->next();
|
||||
oop key = entry->object();
|
||||
oop key = entry->object_peek();
|
||||
assert(key != NULL, "jni weak reference cleared!!");
|
||||
unsigned int h = hash(key, new_size);
|
||||
JvmtiTagHashmapEntry* anchor = new_table[h];
|
||||
@ -304,7 +310,7 @@ class JvmtiTagHashmap : public CHeapObj<mtInternal> {
|
||||
unsigned int h = hash(key);
|
||||
JvmtiTagHashmapEntry* entry = _table[h];
|
||||
while (entry != NULL) {
|
||||
if (entry->object() == key) {
|
||||
if (entry->equals(key)) {
|
||||
return entry;
|
||||
}
|
||||
entry = entry->next();
|
||||
@ -345,7 +351,7 @@ class JvmtiTagHashmap : public CHeapObj<mtInternal> {
|
||||
JvmtiTagHashmapEntry* entry = _table[h];
|
||||
JvmtiTagHashmapEntry* prev = NULL;
|
||||
while (entry != NULL) {
|
||||
if (key == entry->object()) {
|
||||
if (entry->equals(key)) {
|
||||
break;
|
||||
}
|
||||
prev = entry;
|
||||
@ -1535,16 +1541,12 @@ class TagObjectCollector : public JvmtiTagHashmapEntryClosure {
|
||||
void do_entry(JvmtiTagHashmapEntry* entry) {
|
||||
for (int i=0; i<_tag_count; i++) {
|
||||
if (_tags[i] == entry->tag()) {
|
||||
// The reference in this tag map could be the only (implicitly weak)
|
||||
// reference to that object. If we hand it out, we need to keep it live wrt
|
||||
// SATB marking similar to other j.l.ref.Reference referents. This is
|
||||
// achieved by using a phantom load in the object() accessor.
|
||||
oop o = entry->object();
|
||||
assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (UseG1GC) {
|
||||
// The reference in this tag map could be the only (implicitly weak)
|
||||
// reference to that object. If we hand it out, we need to keep it live wrt
|
||||
// SATB marking similar to other j.l.ref.Reference referents.
|
||||
G1SATBCardTableModRefBS::enqueue(o);
|
||||
}
|
||||
#endif
|
||||
jobject ref = JNIHandles::make_local(JavaThread::current(), o);
|
||||
_object_results->append(ref);
|
||||
_tag_results->append((uint64_t)entry->tag());
|
||||
@ -3363,10 +3365,8 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
while (entry != NULL) {
|
||||
JvmtiTagHashmapEntry* next = entry->next();
|
||||
|
||||
oop* obj = entry->object_addr();
|
||||
|
||||
// has object been GC'ed
|
||||
if (!is_alive->do_object_b(entry->object())) {
|
||||
if (!is_alive->do_object_b(entry->object_peek())) {
|
||||
// grab the tag
|
||||
jlong tag = entry->tag();
|
||||
guarantee(tag != 0, "checking");
|
||||
@ -3384,7 +3384,7 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
++freed;
|
||||
} else {
|
||||
f->do_oop(entry->object_addr());
|
||||
oop new_oop = entry->object();
|
||||
oop new_oop = entry->object_peek();
|
||||
|
||||
// if the object has moved then re-hash it and move its
|
||||
// entry to its new location.
|
||||
@ -3418,7 +3418,7 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
// Re-add all the entries which were kept aside
|
||||
while (delayed_add != NULL) {
|
||||
JvmtiTagHashmapEntry* next = delayed_add->next();
|
||||
unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size);
|
||||
unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object_peek(), size);
|
||||
delayed_add->set_next(table[pos]);
|
||||
table[pos] = delayed_add;
|
||||
delayed_add = next;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
@ -33,24 +34,39 @@
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
oop ResolvedMethodEntry::object() {
|
||||
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(literal_addr());
|
||||
}
|
||||
|
||||
oop ResolvedMethodEntry::object_no_keepalive() {
|
||||
// The AS_NO_KEEPALIVE peeks at the oop without keeping it alive.
|
||||
// This is dangerous in general but is okay if the loaded oop does
|
||||
// not leak out past a thread transition where a safepoint can happen.
|
||||
// A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor)
|
||||
// keeps the oop alive before doing so.
|
||||
return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(literal_addr());
|
||||
}
|
||||
|
||||
ResolvedMethodTable::ResolvedMethodTable()
|
||||
: Hashtable<oop, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
||||
|
||||
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
||||
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||
if (p->hash() == hash) {
|
||||
oop target = p->literal();
|
||||
|
||||
// Peek the object to check if it is the right target.
|
||||
oop target = p->object_no_keepalive();
|
||||
|
||||
// The method is in the table as a target already
|
||||
if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
|
||||
ResourceMark rm;
|
||||
log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
|
||||
method->name_and_sig_as_C_string(), index);
|
||||
return target;
|
||||
// The object() accessor makes sure the target object is kept alive before
|
||||
// leaking out.
|
||||
return p->object();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,18 +86,6 @@ oop ResolvedMethodTable::lookup(Method* method) {
|
||||
return lookup(index, hash, method);
|
||||
}
|
||||
|
||||
// Tell the GC that this oop was looked up in the table
|
||||
static void ensure_oop_alive(oop mname) {
|
||||
// A lookup in the ResolvedMethodTable could return an object that was previously
|
||||
// considered dead. The SATB part of G1 needs to get notified about this
|
||||
// potential resurrection, otherwise the marking might not find the object.
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (UseG1GC && mname != NULL) {
|
||||
G1SATBCardTableModRefBS::enqueue(mname);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
||||
assert_locked_or_safepoint(ResolvedMethodTable_lock);
|
||||
|
||||
@ -91,7 +95,6 @@ oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
||||
// One was added while aquiring the lock
|
||||
oop entry = lookup(index, hash, method);
|
||||
if (entry != NULL) {
|
||||
ensure_oop_alive(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -100,14 +103,13 @@ oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
||||
ResourceMark rm;
|
||||
log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
|
||||
method->name_and_sig_as_C_string(), index);
|
||||
return p->literal();
|
||||
return rmethod_name;
|
||||
}
|
||||
|
||||
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
||||
|
||||
oop ResolvedMethodTable::find_method(Method* method) {
|
||||
oop entry = _the_table->lookup(method);
|
||||
ensure_oop_alive(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -147,12 +149,12 @@ void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) {
|
||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
||||
while (entry != NULL) {
|
||||
_oops_counted++;
|
||||
if (is_alive->do_object_b(entry->literal())) {
|
||||
if (is_alive->do_object_b(entry->object_no_keepalive())) {
|
||||
p = entry->next_addr();
|
||||
} else {
|
||||
_oops_removed++;
|
||||
if (log_is_enabled(Debug, membername, table)) {
|
||||
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->literal());
|
||||
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->object_no_keepalive());
|
||||
ResourceMark rm;
|
||||
log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d",
|
||||
m->name_and_sig_as_C_string(), i);
|
||||
@ -185,7 +187,7 @@ void ResolvedMethodTable::print() {
|
||||
ResolvedMethodEntry* entry = bucket(i);
|
||||
while (entry != NULL) {
|
||||
tty->print("%d : ", i);
|
||||
oop rmethod_name = entry->literal();
|
||||
oop rmethod_name = entry->object_no_keepalive();
|
||||
rmethod_name->print();
|
||||
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
|
||||
m->print();
|
||||
@ -203,8 +205,7 @@ void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
|
||||
for (int i = 0; i < _the_table->table_size(); ++i) {
|
||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
||||
while (entry != NULL) {
|
||||
|
||||
oop mem_name = entry->literal();
|
||||
oop mem_name = entry->object_no_keepalive();
|
||||
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
||||
|
||||
if (old_method->is_old()) {
|
||||
|
@ -44,6 +44,9 @@ class ResolvedMethodEntry : public HashtableEntry<oop, mtClass> {
|
||||
return (ResolvedMethodEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
||||
}
|
||||
|
||||
oop object();
|
||||
oop object_no_keepalive();
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2018, 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
|
||||
@ -243,11 +243,12 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu
|
||||
RegisterMap map((JavaThread*)t, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8194652
|
||||
* @summary Printing native stack shows an "error occurred during error reporting".
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @library /test/lib
|
||||
*/
|
||||
|
||||
// This test was adapted from SafeFetchInErrorHandlingTest.java.
|
||||
public class BadNativeStackInErrorHandlingTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!Platform.isDebugBuild() || Platform.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-Xmx100M",
|
||||
"-XX:ErrorHandlerTest=14",
|
||||
"-XX:-CreateCoredumpOnCrash",
|
||||
"-version");
|
||||
|
||||
OutputAnalyzer output_detail = new OutputAnalyzer(pb.start());
|
||||
|
||||
// we should have crashed with a SIGSEGV
|
||||
output_detail.shouldMatch("# A fatal error has been detected by the Java Runtime Environment:.*");
|
||||
output_detail.shouldMatch("# +(?:SIGSEGV|EXCEPTION_ACCESS_VIOLATION).*");
|
||||
|
||||
// extract hs-err file
|
||||
String hs_err_file = output_detail.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1);
|
||||
if (hs_err_file == null) {
|
||||
throw new RuntimeException("Did not find hs-err file in output.\n");
|
||||
}
|
||||
|
||||
File f = new File(hs_err_file);
|
||||
if (!f.exists()) {
|
||||
throw new RuntimeException("hs-err file missing at " +
|
||||
f.getAbsolutePath() + ".\n");
|
||||
}
|
||||
|
||||
System.out.println("Found hs_err file. Scanning...");
|
||||
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
|
||||
String line = null;
|
||||
|
||||
// The failing line looks like this:
|
||||
// [error occurred during error reporting (printing native stack), id 0xb]
|
||||
Pattern pattern =
|
||||
Pattern.compile("\\[error occurred during error reporting \\(printing native stack\\), id .*\\]");
|
||||
|
||||
String lastLine = null;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (pattern.matcher(line).matches()) {
|
||||
System.out.println("Found: " + line + ".");
|
||||
throw new RuntimeException("hs-err file should not contain: '" +
|
||||
pattern + "'");
|
||||
}
|
||||
lastLine = line;
|
||||
}
|
||||
br.close();
|
||||
|
||||
if (!lastLine.equals("END.")) {
|
||||
throw new RuntimeException("hs-err file incomplete (missing END marker.)");
|
||||
} else {
|
||||
System.out.println("End marker found.");
|
||||
}
|
||||
|
||||
System.out.println("OK.");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user