mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
Merge
This commit is contained in:
commit
61592ca6fa
12 changed files with 235 additions and 109 deletions
|
@ -628,7 +628,7 @@ 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) {
|
bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
|
||||||
assert(java_string->klass() == SystemDictionary::String_klass(),
|
assert(java_string->klass() == SystemDictionary::String_klass(),
|
||||||
"must be java_string");
|
"must be java_string");
|
||||||
typeArrayOop value = java_lang_String::value(java_string);
|
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
|
||||||
int length = java_lang_String::length(java_string);
|
int length = java_lang_String::length(java_string);
|
||||||
if (length != len) {
|
if (length != len) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -655,11 +655,11 @@ bool java_lang_String::equals(oop str1, oop str2) {
|
||||||
"must be java String");
|
"must be java String");
|
||||||
assert(str2->klass() == SystemDictionary::String_klass(),
|
assert(str2->klass() == SystemDictionary::String_klass(),
|
||||||
"must be java String");
|
"must be java String");
|
||||||
typeArrayOop value1 = java_lang_String::value(str1);
|
typeArrayOop value1 = java_lang_String::value_no_keepalive(str1);
|
||||||
int length1 = java_lang_String::length(str1);
|
int length1 = java_lang_String::length(value1);
|
||||||
bool is_latin1 = java_lang_String::is_latin1(str1);
|
bool is_latin1 = java_lang_String::is_latin1(str1);
|
||||||
typeArrayOop value2 = java_lang_String::value(str2);
|
typeArrayOop value2 = java_lang_String::value_no_keepalive(str2);
|
||||||
int length2 = java_lang_String::length(str2);
|
int length2 = java_lang_String::length(value2);
|
||||||
bool is_latin2 = java_lang_String::is_latin1(str2);
|
bool is_latin2 = java_lang_String::is_latin1(str2);
|
||||||
|
|
||||||
if ((length1 != length2) || (is_latin1 != is_latin2)) {
|
if ((length1 != length2) || (is_latin1 != is_latin2)) {
|
||||||
|
@ -668,7 +668,7 @@ bool java_lang_String::equals(oop str1, oop str2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int blength1 = value1->length();
|
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)) {
|
if (value1->byte_at(i) != value2->byte_at(i)) {
|
||||||
return false;
|
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) {
|
void java_lang_String::print(oop java_string, outputStream* st) {
|
||||||
assert(java_string->klass() == SystemDictionary::String_klass(), "must be java_string");
|
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) {
|
if (value == NULL) {
|
||||||
// This can happen if, e.g., printing a String
|
// This can happen if, e.g., printing a String
|
||||||
|
|
|
@ -102,6 +102,7 @@ class java_lang_String : AllStatic {
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
static inline typeArrayOop value(oop java_string);
|
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 unsigned int hash(oop java_string);
|
||||||
static inline bool is_latin1(oop java_string);
|
static inline bool is_latin1(oop java_string);
|
||||||
static inline int length(oop java_string);
|
static inline int length(oop java_string);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP
|
#define SHARE_VM_CLASSFILE_JAVACLASSES_INLINE_HPP
|
||||||
|
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "oops/oopsHierarchy.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");
|
assert(is_instance(java_string), "must be java_string");
|
||||||
return (typeArrayOop) java_string->obj_field(value_offset);
|
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) {
|
unsigned int java_lang_String::hash(oop java_string) {
|
||||||
assert(initialized && (hash_offset > 0), "Must be initialized");
|
assert(initialized && (hash_offset > 0), "Must be initialized");
|
||||||
assert(is_instance(java_string), "must be java_string");
|
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) {
|
int java_lang_String::length(oop java_string) {
|
||||||
assert(initialized, "Must be initialized");
|
assert(initialized, "Must be initialized");
|
||||||
assert(is_instance(java_string), "must be java_string");
|
assert(is_instance(java_string), "must be java_string");
|
||||||
typeArrayOop value_array = ((typeArrayOop)java_string->obj_field(value_offset));
|
typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
|
||||||
if (value_array == NULL) {
|
if (value == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int arr_length = value_array->length();
|
int arr_length = value->length();
|
||||||
if (!is_latin1(java_string)) {
|
if (!is_latin1(java_string)) {
|
||||||
assert((arr_length & 1) == 0, "should be even for UTF16 string");
|
assert((arr_length & 1) == 0, "should be even for UTF16 string");
|
||||||
arr_length >>= 1; // convert number of bytes to number of elements
|
arr_length >>= 1; // convert number of bytes to number of elements
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "memory/filemap.hpp"
|
#include "memory/filemap.hpp"
|
||||||
#include "memory/metaspaceShared.hpp"
|
#include "memory/metaspaceShared.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "runtime/atomic.hpp"
|
#include "runtime/atomic.hpp"
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
|
@ -43,7 +44,6 @@
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
#include "gc/g1/g1CollectedHeap.hpp"
|
#include "gc/g1/g1CollectedHeap.hpp"
|
||||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
|
||||||
#include "gc/g1/g1StringDedup.hpp"
|
#include "gc/g1/g1StringDedup.hpp"
|
||||||
#endif
|
#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) {
|
oop StringTable::lookup_shared(jchar* name, int len, unsigned int hash) {
|
||||||
assert(hash == java_lang_String::hash_code(name, len),
|
assert(hash == java_lang_String::hash_code(name, len),
|
||||||
"hash must be computed using java_lang_String::hash_code");
|
"hash must be computed using java_lang_String::hash_code");
|
||||||
|
@ -136,8 +152,11 @@ oop StringTable::lookup_in_main_table(int index, jchar* name,
|
||||||
for (HashtableEntry<oop, mtSymbol>* l = bucket(index); l != NULL; l = l->next()) {
|
for (HashtableEntry<oop, mtSymbol>* l = bucket(index); l != NULL; l = l->next()) {
|
||||||
count++;
|
count++;
|
||||||
if (l->hash() == hash) {
|
if (l->hash() == hash) {
|
||||||
if (java_lang_String::equals(l->literal(), name, len)) {
|
if (java_lang_String::equals(string_object_no_keepalive(l), name, len)) {
|
||||||
return l->literal();
|
// 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);
|
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) {
|
oop StringTable::lookup(jchar* name, int len) {
|
||||||
// shared table always uses java_lang_String::hash_code
|
// shared table always uses java_lang_String::hash_code
|
||||||
unsigned int hash = java_lang_String::hash_code(name, len);
|
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);
|
int index = the_table()->hash_to_index(hash);
|
||||||
string = the_table()->lookup_in_main_table(index, name, len, hash);
|
string = the_table()->lookup_in_main_table(index, name, len, hash);
|
||||||
|
|
||||||
ensure_string_alive(string);
|
|
||||||
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,9 +243,6 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
|
||||||
|
|
||||||
// Found
|
// Found
|
||||||
if (found_string != NULL) {
|
if (found_string != NULL) {
|
||||||
if (found_string != string_or_null()) {
|
|
||||||
ensure_string_alive(found_string);
|
|
||||||
}
|
|
||||||
return found_string;
|
return found_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,10 +278,6 @@ oop StringTable::intern(Handle string_or_null, jchar* name,
|
||||||
hashValue, CHECK_NULL);
|
hashValue, CHECK_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (added_or_found != string()) {
|
|
||||||
ensure_string_alive(added_or_found);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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) {
|
while (entry != NULL) {
|
||||||
assert(!entry->is_shared(), "CDS not used for the StringTable");
|
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) {
|
if (f != NULL) {
|
||||||
f->do_oop((oop*)entry->literal_addr());
|
f->do_oop(entry->literal_addr());
|
||||||
}
|
}
|
||||||
p = entry->next_addr();
|
p = entry->next_addr();
|
||||||
} else {
|
} else {
|
||||||
|
@ -429,7 +427,7 @@ void StringTable::verify() {
|
||||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||||
HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
|
HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
|
||||||
for ( ; p != NULL; p = p->next()) {
|
for ( ; p != NULL; p = p->next()) {
|
||||||
oop s = p->literal();
|
oop s = string_object_no_keepalive(p);
|
||||||
guarantee(s != NULL, "interned string is NULL");
|
guarantee(s != NULL, "interned string is NULL");
|
||||||
unsigned int h = hash_string(s);
|
unsigned int h = hash_string(s);
|
||||||
guarantee(p->hash() == h, "broken hash in string table entry");
|
guarantee(p->hash() == h, "broken hash in string table entry");
|
||||||
|
@ -448,8 +446,8 @@ void StringTable::dump(outputStream* st, bool verbose) {
|
||||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||||
HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
|
HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
|
||||||
for ( ; p != NULL; p = p->next()) {
|
for ( ; p != NULL; p = p->next()) {
|
||||||
oop s = p->literal();
|
oop s = string_object_no_keepalive(p);
|
||||||
typeArrayOop value = java_lang_String::value(s);
|
typeArrayOop value = java_lang_String::value_no_keepalive(s);
|
||||||
int length = java_lang_String::length(s);
|
int length = java_lang_String::length(s);
|
||||||
bool is_latin1 = java_lang_String::is_latin1(s);
|
bool is_latin1 = java_lang_String::is_latin1(s);
|
||||||
|
|
||||||
|
@ -484,8 +482,8 @@ StringTable::VerifyRetTypes StringTable::compare_entries(
|
||||||
HashtableEntry<oop, mtSymbol>* e_ptr2) {
|
HashtableEntry<oop, mtSymbol>* e_ptr2) {
|
||||||
// These entries are sanity checked by verify_and_compare_entries()
|
// These entries are sanity checked by verify_and_compare_entries()
|
||||||
// before this function is called.
|
// before this function is called.
|
||||||
oop str1 = e_ptr1->literal();
|
oop str1 = string_object_no_keepalive(e_ptr1);
|
||||||
oop str2 = e_ptr2->literal();
|
oop str2 = string_object_no_keepalive(e_ptr2);
|
||||||
|
|
||||||
if (str1 == str2) {
|
if (str1 == str2) {
|
||||||
tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") "
|
tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") "
|
||||||
|
@ -510,7 +508,7 @@ StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt,
|
||||||
|
|
||||||
VerifyRetTypes ret = _verify_pass; // be optimistic
|
VerifyRetTypes ret = _verify_pass; // be optimistic
|
||||||
|
|
||||||
oop str = e_ptr->literal();
|
oop str = string_object_no_keepalive(e_ptr);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
if (mesg_mode == _verify_with_mesgs) {
|
if (mesg_mode == _verify_with_mesgs) {
|
||||||
tty->print_cr("ERROR: NULL oop value in entry @ bucket[%d][%d]", bkt,
|
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");
|
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
|
||||||
|
|
||||||
oop new_s = NULL;
|
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);
|
typeArrayOop new_v = (typeArrayOop)MetaspaceShared::archive_heap_object(v, THREAD);
|
||||||
if (new_v == NULL) {
|
if (new_v == NULL) {
|
||||||
return 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) {
|
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||||
HashtableEntry<oop, mtSymbol>* bucket = the_table()->bucket(i);
|
HashtableEntry<oop, mtSymbol>* bucket = the_table()->bucket(i);
|
||||||
for ( ; bucket != NULL; bucket = bucket->next()) {
|
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);
|
unsigned int hash = java_lang_String::hash_code(s);
|
||||||
if (hash == 0) {
|
if (hash == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -721,7 +719,7 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the archived string in bucket
|
// set the archived string in bucket
|
||||||
bucket->set_literal(new_s);
|
set_string_object(bucket, new_s);
|
||||||
|
|
||||||
// add to the compact table
|
// add to the compact table
|
||||||
writer->add(hash, new_s);
|
writer->add(hash, new_s);
|
||||||
|
@ -763,4 +761,3 @@ void StringTable::shared_oops_do(OopClosure* f) {
|
||||||
_shared_table.oops_do(f);
|
_shared_table.oops_do(f);
|
||||||
}
|
}
|
||||||
#endif //INCLUDE_CDS_JAVA_HEAP
|
#endif //INCLUDE_CDS_JAVA_HEAP
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,13 @@ private:
|
||||||
static unsigned int hash_string(oop string);
|
static unsigned int hash_string(oop string);
|
||||||
static unsigned int alt_hash_string(const jchar* s, int len);
|
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,
|
StringTable() : RehashableHashtable<oop, mtSymbol>((int)StringTableSize,
|
||||||
sizeof (HashtableEntry<oop, mtSymbol>)) {}
|
sizeof (HashtableEntry<oop, mtSymbol>)) {}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "gc/shared/specialized_oop_closures.hpp"
|
#include "gc/shared/specialized_oop_closures.hpp"
|
||||||
#include "memory/iterator.hpp"
|
#include "memory/iterator.hpp"
|
||||||
#include "memory/memRegion.hpp"
|
#include "memory/memRegion.hpp"
|
||||||
|
#include "oops/access.hpp"
|
||||||
#include "oops/metadata.hpp"
|
#include "oops/metadata.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
|
|
||||||
|
@ -178,6 +179,8 @@ class oopDesc {
|
||||||
static inline void encode_store_heap_oop(oop* p, oop v);
|
static inline void encode_store_heap_oop(oop* p, oop v);
|
||||||
|
|
||||||
// Access to fields in a instanceOop through these methods.
|
// 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;
|
oop obj_field(int offset) const;
|
||||||
void obj_field_put(int offset, oop value);
|
void obj_field_put(int offset, oop value);
|
||||||
void obj_field_put_raw(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);
|
*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 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 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); }
|
inline jbyte oopDesc::byte_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); }
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "jvmtifiles/jvmtiEnv.hpp"
|
#include "jvmtifiles/jvmtiEnv.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/instanceMirrorKlass.hpp"
|
#include "oops/instanceMirrorKlass.hpp"
|
||||||
#include "oops/objArrayKlass.hpp"
|
#include "oops/objArrayKlass.hpp"
|
||||||
#include "oops/objArrayOop.inline.hpp"
|
#include "oops/objArrayOop.inline.hpp"
|
||||||
|
@ -52,10 +53,6 @@
|
||||||
#include "runtime/vm_operations.hpp"
|
#include "runtime/vm_operations.hpp"
|
||||||
#include "services/serviceUtil.hpp"
|
#include "services/serviceUtil.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#if INCLUDE_ALL_GCS
|
|
||||||
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
|
|
||||||
#include "gc/parallel/parallelScavengeHeap.hpp"
|
|
||||||
#endif // INCLUDE_ALL_GCS
|
|
||||||
|
|
||||||
// JvmtiTagHashmapEntry
|
// JvmtiTagHashmapEntry
|
||||||
//
|
//
|
||||||
|
@ -83,8 +80,13 @@ class JvmtiTagHashmapEntry : public CHeapObj<mtInternal> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// accessor methods
|
// accessor methods
|
||||||
inline oop object() const { return _object; }
|
|
||||||
inline oop* object_addr() { return &_object; }
|
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 jlong tag() const { return _tag; }
|
||||||
|
|
||||||
inline void set_tag(jlong tag) {
|
inline void set_tag(jlong tag) {
|
||||||
|
@ -92,6 +94,10 @@ class JvmtiTagHashmapEntry : public CHeapObj<mtInternal> {
|
||||||
_tag = tag;
|
_tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool equals(oop object) {
|
||||||
|
return object == object_peek();
|
||||||
|
}
|
||||||
|
|
||||||
inline JvmtiTagHashmapEntry* next() const { return _next; }
|
inline JvmtiTagHashmapEntry* next() const { return _next; }
|
||||||
inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
|
inline void set_next(JvmtiTagHashmapEntry* next) { _next = next; }
|
||||||
};
|
};
|
||||||
|
@ -211,7 +217,7 @@ class JvmtiTagHashmap : public CHeapObj<mtInternal> {
|
||||||
JvmtiTagHashmapEntry* entry = _table[i];
|
JvmtiTagHashmapEntry* entry = _table[i];
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
JvmtiTagHashmapEntry* next = entry->next();
|
JvmtiTagHashmapEntry* next = entry->next();
|
||||||
oop key = entry->object();
|
oop key = entry->object_peek();
|
||||||
assert(key != NULL, "jni weak reference cleared!!");
|
assert(key != NULL, "jni weak reference cleared!!");
|
||||||
unsigned int h = hash(key, new_size);
|
unsigned int h = hash(key, new_size);
|
||||||
JvmtiTagHashmapEntry* anchor = new_table[h];
|
JvmtiTagHashmapEntry* anchor = new_table[h];
|
||||||
|
@ -304,7 +310,7 @@ class JvmtiTagHashmap : public CHeapObj<mtInternal> {
|
||||||
unsigned int h = hash(key);
|
unsigned int h = hash(key);
|
||||||
JvmtiTagHashmapEntry* entry = _table[h];
|
JvmtiTagHashmapEntry* entry = _table[h];
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
if (entry->object() == key) {
|
if (entry->equals(key)) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
entry = entry->next();
|
entry = entry->next();
|
||||||
|
@ -345,7 +351,7 @@ class JvmtiTagHashmap : public CHeapObj<mtInternal> {
|
||||||
JvmtiTagHashmapEntry* entry = _table[h];
|
JvmtiTagHashmapEntry* entry = _table[h];
|
||||||
JvmtiTagHashmapEntry* prev = NULL;
|
JvmtiTagHashmapEntry* prev = NULL;
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
if (key == entry->object()) {
|
if (entry->equals(key)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev = entry;
|
prev = entry;
|
||||||
|
@ -1535,16 +1541,12 @@ class TagObjectCollector : public JvmtiTagHashmapEntryClosure {
|
||||||
void do_entry(JvmtiTagHashmapEntry* entry) {
|
void do_entry(JvmtiTagHashmapEntry* entry) {
|
||||||
for (int i=0; i<_tag_count; i++) {
|
for (int i=0; i<_tag_count; i++) {
|
||||||
if (_tags[i] == entry->tag()) {
|
if (_tags[i] == entry->tag()) {
|
||||||
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)
|
// 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
|
// 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.
|
// SATB marking similar to other j.l.ref.Reference referents. This is
|
||||||
G1SATBCardTableModRefBS::enqueue(o);
|
// achieved by using a phantom load in the object() accessor.
|
||||||
}
|
oop o = entry->object();
|
||||||
#endif
|
assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
|
||||||
jobject ref = JNIHandles::make_local(JavaThread::current(), o);
|
jobject ref = JNIHandles::make_local(JavaThread::current(), o);
|
||||||
_object_results->append(ref);
|
_object_results->append(ref);
|
||||||
_tag_results->append((uint64_t)entry->tag());
|
_tag_results->append((uint64_t)entry->tag());
|
||||||
|
@ -3363,10 +3365,8 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
JvmtiTagHashmapEntry* next = entry->next();
|
JvmtiTagHashmapEntry* next = entry->next();
|
||||||
|
|
||||||
oop* obj = entry->object_addr();
|
|
||||||
|
|
||||||
// has object been GC'ed
|
// 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
|
// grab the tag
|
||||||
jlong tag = entry->tag();
|
jlong tag = entry->tag();
|
||||||
guarantee(tag != 0, "checking");
|
guarantee(tag != 0, "checking");
|
||||||
|
@ -3384,7 +3384,7 @@ void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||||
++freed;
|
++freed;
|
||||||
} else {
|
} else {
|
||||||
f->do_oop(entry->object_addr());
|
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
|
// if the object has moved then re-hash it and move its
|
||||||
// entry to its new location.
|
// 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
|
// Re-add all the entries which were kept aside
|
||||||
while (delayed_add != NULL) {
|
while (delayed_add != NULL) {
|
||||||
JvmtiTagHashmapEntry* next = delayed_add->next();
|
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]);
|
delayed_add->set_next(table[pos]);
|
||||||
table[pos] = delayed_add;
|
table[pos] = delayed_add;
|
||||||
delayed_add = next;
|
delayed_add = next;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/shared/gcLocker.hpp"
|
#include "gc/shared/gcLocker.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "oops/method.hpp"
|
#include "oops/method.hpp"
|
||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
|
@ -33,24 +34,39 @@
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
#include "utilities/hashtable.inline.hpp"
|
#include "utilities/hashtable.inline.hpp"
|
||||||
#include "utilities/macros.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()
|
ResolvedMethodTable::ResolvedMethodTable()
|
||||||
: Hashtable<oop, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
: Hashtable<oop, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
||||||
|
|
||||||
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
||||||
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||||
if (p->hash() == hash) {
|
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
|
// The method is in the table as a target already
|
||||||
if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
|
if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
|
log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
|
||||||
method->name_and_sig_as_C_string(), index);
|
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);
|
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) {
|
oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
||||||
assert_locked_or_safepoint(ResolvedMethodTable_lock);
|
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
|
// One was added while aquiring the lock
|
||||||
oop entry = lookup(index, hash, method);
|
oop entry = lookup(index, hash, method);
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
ensure_oop_alive(entry);
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,14 +103,13 @@ oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
|
log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
|
||||||
method->name_and_sig_as_C_string(), index);
|
method->name_and_sig_as_C_string(), index);
|
||||||
return p->literal();
|
return rmethod_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
||||||
|
|
||||||
oop ResolvedMethodTable::find_method(Method* method) {
|
oop ResolvedMethodTable::find_method(Method* method) {
|
||||||
oop entry = _the_table->lookup(method);
|
oop entry = _the_table->lookup(method);
|
||||||
ensure_oop_alive(entry);
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,12 +149,12 @@ void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) {
|
||||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
_oops_counted++;
|
_oops_counted++;
|
||||||
if (is_alive->do_object_b(entry->literal())) {
|
if (is_alive->do_object_b(entry->object_no_keepalive())) {
|
||||||
p = entry->next_addr();
|
p = entry->next_addr();
|
||||||
} else {
|
} else {
|
||||||
_oops_removed++;
|
_oops_removed++;
|
||||||
if (log_is_enabled(Debug, membername, table)) {
|
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;
|
ResourceMark rm;
|
||||||
log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d",
|
log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d",
|
||||||
m->name_and_sig_as_C_string(), i);
|
m->name_and_sig_as_C_string(), i);
|
||||||
|
@ -185,7 +187,7 @@ void ResolvedMethodTable::print() {
|
||||||
ResolvedMethodEntry* entry = bucket(i);
|
ResolvedMethodEntry* entry = bucket(i);
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
tty->print("%d : ", i);
|
tty->print("%d : ", i);
|
||||||
oop rmethod_name = entry->literal();
|
oop rmethod_name = entry->object_no_keepalive();
|
||||||
rmethod_name->print();
|
rmethod_name->print();
|
||||||
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
|
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
|
||||||
m->print();
|
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) {
|
for (int i = 0; i < _the_table->table_size(); ++i) {
|
||||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
|
oop mem_name = entry->object_no_keepalive();
|
||||||
oop mem_name = entry->literal();
|
|
||||||
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
||||||
|
|
||||||
if (old_method->is_old()) {
|
if (old_method->is_old()) {
|
||||||
|
|
|
@ -44,6 +44,9 @@ class ResolvedMethodEntry : public HashtableEntry<oop, mtClass> {
|
||||||
return (ResolvedMethodEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
return (ResolvedMethodEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oop object();
|
||||||
|
oop object_no_keepalive();
|
||||||
|
|
||||||
void print_on(outputStream* st) const;
|
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.
|
* 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
|
||||||
|
@ -243,11 +243,12 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu
|
||||||
RegisterMap map((JavaThread*)t, false); // No update
|
RegisterMap map((JavaThread*)t, false); // No update
|
||||||
fr = fr.sender(&map);
|
fr = fr.sender(&map);
|
||||||
} else {
|
} 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);
|
fr = os::get_sender_for_C_frame(&fr);
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
if (os::is_first_C_frame(&fr)) break;
|
||||||
fr = os::get_sender_for_C_frame(&fr);
|
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…
Add table
Add a link
Reference in a new issue