mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
Merge
This commit is contained in:
commit
f9b1731815
22 changed files with 525 additions and 390 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2013, 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
|
||||||
|
@ -698,29 +698,58 @@ err:
|
||||||
|
|
||||||
// read segments of a shared object
|
// read segments of a shared object
|
||||||
static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) {
|
static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ELF_PHDR* phbuf;
|
ELF_PHDR* phbuf;
|
||||||
ELF_PHDR* lib_php = NULL;
|
ELF_PHDR* lib_php = NULL;
|
||||||
|
|
||||||
if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL)
|
int page_size=sysconf(_SC_PAGE_SIZE);
|
||||||
return false;
|
|
||||||
|
|
||||||
// we want to process only PT_LOAD segments that are not writable.
|
if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) {
|
||||||
// i.e., text segments. The read/write/exec (data) segments would
|
return false;
|
||||||
// have been already added from core file segments.
|
}
|
||||||
for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
|
|
||||||
if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
|
// we want to process only PT_LOAD segments that are not writable.
|
||||||
if (add_map_info(ph, lib_fd, lib_php->p_offset, lib_php->p_vaddr + lib_base, lib_php->p_filesz) == NULL)
|
// i.e., text segments. The read/write/exec (data) segments would
|
||||||
goto err;
|
// have been already added from core file segments.
|
||||||
|
for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
|
||||||
|
if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
|
||||||
|
|
||||||
|
uintptr_t target_vaddr = lib_php->p_vaddr + lib_base;
|
||||||
|
map_info *existing_map = core_lookup(ph, target_vaddr);
|
||||||
|
|
||||||
|
if (existing_map == NULL){
|
||||||
|
if (add_map_info(ph, lib_fd, lib_php->p_offset,
|
||||||
|
target_vaddr, lib_php->p_filesz) == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((existing_map->memsz != page_size) &&
|
||||||
|
(existing_map->fd != lib_fd) &&
|
||||||
|
(existing_map->memsz != lib_php->p_filesz)){
|
||||||
|
|
||||||
|
print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)",
|
||||||
|
target_vaddr, lib_php->p_filesz, lib_php->p_flags);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replace PT_LOAD segment with library segment */
|
||||||
|
print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n",
|
||||||
|
existing_map->memsz, lib_php->p_filesz);
|
||||||
|
|
||||||
|
existing_map->fd = lib_fd;
|
||||||
|
existing_map->offset = lib_php->p_offset;
|
||||||
|
existing_map->memsz = lib_php->p_filesz;
|
||||||
}
|
}
|
||||||
lib_php++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
free(phbuf);
|
lib_php++;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
free(phbuf);
|
||||||
|
return true;
|
||||||
err:
|
err:
|
||||||
free(phbuf);
|
free(phbuf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// process segments from interpreter (ld.so or ld-linux.so)
|
// process segments from interpreter (ld.so or ld-linux.so)
|
||||||
|
|
|
@ -438,6 +438,29 @@ bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool java_lang_String::equals(oop str1, oop str2) {
|
||||||
|
assert(str1->klass() == SystemDictionary::String_klass(),
|
||||||
|
"must be java String");
|
||||||
|
assert(str2->klass() == SystemDictionary::String_klass(),
|
||||||
|
"must be java String");
|
||||||
|
typeArrayOop value1 = java_lang_String::value(str1);
|
||||||
|
int offset1 = java_lang_String::offset(str1);
|
||||||
|
int length1 = java_lang_String::length(str1);
|
||||||
|
typeArrayOop value2 = java_lang_String::value(str2);
|
||||||
|
int offset2 = java_lang_String::offset(str2);
|
||||||
|
int length2 = java_lang_String::length(str2);
|
||||||
|
|
||||||
|
if (length1 != length2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length1; i++) {
|
||||||
|
if (value1->char_at(i + offset1) != value2->char_at(i + offset2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void java_lang_String::print(Handle java_string, outputStream* st) {
|
void java_lang_String::print(Handle java_string, outputStream* st) {
|
||||||
oop obj = java_string();
|
oop obj = java_string();
|
||||||
assert(obj->klass() == SystemDictionary::String_klass(), "must be java_string");
|
assert(obj->klass() == SystemDictionary::String_klass(), "must be java_string");
|
||||||
|
|
|
@ -182,6 +182,7 @@ class java_lang_String : AllStatic {
|
||||||
static unsigned int hash_string(oop java_string);
|
static unsigned int hash_string(oop java_string);
|
||||||
|
|
||||||
static bool equals(oop java_string, jchar* chars, int len);
|
static bool equals(oop java_string, jchar* chars, int len);
|
||||||
|
static bool equals(oop str1, oop str2);
|
||||||
|
|
||||||
// Conversion between '.' and '/' formats
|
// Conversion between '.' and '/' formats
|
||||||
static Handle externalize_classname(Handle java_string, TRAPS) { return char_converter(java_string, '/', '.', THREAD); }
|
static Handle externalize_classname(Handle java_string, TRAPS) { return char_converter(java_string, '/', '.', THREAD); }
|
||||||
|
|
|
@ -807,6 +807,8 @@ void StringTable::possibly_parallel_oops_do(OopClosure* f) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This verification is part of Universe::verify() and needs to be quick.
|
||||||
|
// See StringTable::verify_and_compare() below for exhaustive verification.
|
||||||
void StringTable::verify() {
|
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);
|
||||||
|
@ -825,6 +827,162 @@ void StringTable::dump(outputStream* st) {
|
||||||
the_table()->dump_table(st, "StringTable");
|
the_table()->dump_table(st, "StringTable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringTable::VerifyRetTypes StringTable::compare_entries(
|
||||||
|
int bkt1, int e_cnt1,
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr1,
|
||||||
|
int bkt2, int e_cnt2,
|
||||||
|
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();
|
||||||
|
|
||||||
|
if (str1 == str2) {
|
||||||
|
tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") "
|
||||||
|
"in entry @ bucket[%d][%d] and entry @ bucket[%d][%d]",
|
||||||
|
str1, bkt1, e_cnt1, bkt2, e_cnt2);
|
||||||
|
return _verify_fail_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (java_lang_String::equals(str1, str2)) {
|
||||||
|
tty->print_cr("ERROR: identical String values in entry @ "
|
||||||
|
"bucket[%d][%d] and entry @ bucket[%d][%d]",
|
||||||
|
bkt1, e_cnt1, bkt2, e_cnt2);
|
||||||
|
return _verify_fail_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _verify_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTable::VerifyRetTypes StringTable::verify_entry(int bkt, int e_cnt,
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr,
|
||||||
|
StringTable::VerifyMesgModes mesg_mode) {
|
||||||
|
|
||||||
|
VerifyRetTypes ret = _verify_pass; // be optimistic
|
||||||
|
|
||||||
|
oop str = e_ptr->literal();
|
||||||
|
if (str == NULL) {
|
||||||
|
if (mesg_mode == _verify_with_mesgs) {
|
||||||
|
tty->print_cr("ERROR: NULL oop value in entry @ bucket[%d][%d]", bkt,
|
||||||
|
e_cnt);
|
||||||
|
}
|
||||||
|
// NULL oop means no more verifications are possible
|
||||||
|
return _verify_fail_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str->klass() != SystemDictionary::String_klass()) {
|
||||||
|
if (mesg_mode == _verify_with_mesgs) {
|
||||||
|
tty->print_cr("ERROR: oop is not a String in entry @ bucket[%d][%d]",
|
||||||
|
bkt, e_cnt);
|
||||||
|
}
|
||||||
|
// not a String means no more verifications are possible
|
||||||
|
return _verify_fail_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int h = java_lang_String::hash_string(str);
|
||||||
|
if (e_ptr->hash() != h) {
|
||||||
|
if (mesg_mode == _verify_with_mesgs) {
|
||||||
|
tty->print_cr("ERROR: broken hash value in entry @ bucket[%d][%d], "
|
||||||
|
"bkt_hash=%d, str_hash=%d", bkt, e_cnt, e_ptr->hash(), h);
|
||||||
|
}
|
||||||
|
ret = _verify_fail_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (the_table()->hash_to_index(h) != bkt) {
|
||||||
|
if (mesg_mode == _verify_with_mesgs) {
|
||||||
|
tty->print_cr("ERROR: wrong index value for entry @ bucket[%d][%d], "
|
||||||
|
"str_hash=%d, hash_to_index=%d", bkt, e_cnt, h,
|
||||||
|
the_table()->hash_to_index(h));
|
||||||
|
}
|
||||||
|
ret = _verify_fail_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See StringTable::verify() above for the quick verification that is
|
||||||
|
// part of Universe::verify(). This verification is exhaustive and
|
||||||
|
// reports on every issue that is found. StringTable::verify() only
|
||||||
|
// reports on the first issue that is found.
|
||||||
|
//
|
||||||
|
// StringTable::verify_entry() checks:
|
||||||
|
// - oop value != NULL (same as verify())
|
||||||
|
// - oop value is a String
|
||||||
|
// - hash(String) == hash in entry (same as verify())
|
||||||
|
// - index for hash == index of entry (same as verify())
|
||||||
|
//
|
||||||
|
// StringTable::compare_entries() checks:
|
||||||
|
// - oops are unique across all entries
|
||||||
|
// - String values are unique across all entries
|
||||||
|
//
|
||||||
|
int StringTable::verify_and_compare_entries() {
|
||||||
|
assert(StringTable_lock->is_locked(), "sanity check");
|
||||||
|
|
||||||
|
int fail_cnt = 0;
|
||||||
|
|
||||||
|
// first, verify all the entries individually:
|
||||||
|
for (int bkt = 0; bkt < the_table()->table_size(); bkt++) {
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr = the_table()->bucket(bkt);
|
||||||
|
for (int e_cnt = 0; e_ptr != NULL; e_ptr = e_ptr->next(), e_cnt++) {
|
||||||
|
VerifyRetTypes ret = verify_entry(bkt, e_cnt, e_ptr, _verify_with_mesgs);
|
||||||
|
if (ret != _verify_pass) {
|
||||||
|
fail_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimization: if the above check did not find any failures, then
|
||||||
|
// the comparison loop below does not need to call verify_entry()
|
||||||
|
// before calling compare_entries(). If there were failures, then we
|
||||||
|
// have to call verify_entry() to see if the entry can be passed to
|
||||||
|
// compare_entries() safely. When we call verify_entry() in the loop
|
||||||
|
// below, we do so quietly to void duplicate messages and we don't
|
||||||
|
// increment fail_cnt because the failures have already been counted.
|
||||||
|
bool need_entry_verify = (fail_cnt != 0);
|
||||||
|
|
||||||
|
// second, verify all entries relative to each other:
|
||||||
|
for (int bkt1 = 0; bkt1 < the_table()->table_size(); bkt1++) {
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr1 = the_table()->bucket(bkt1);
|
||||||
|
for (int e_cnt1 = 0; e_ptr1 != NULL; e_ptr1 = e_ptr1->next(), e_cnt1++) {
|
||||||
|
if (need_entry_verify) {
|
||||||
|
VerifyRetTypes ret = verify_entry(bkt1, e_cnt1, e_ptr1,
|
||||||
|
_verify_quietly);
|
||||||
|
if (ret == _verify_fail_done) {
|
||||||
|
// cannot use the current entry to compare against other entries
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int bkt2 = bkt1; bkt2 < the_table()->table_size(); bkt2++) {
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr2 = the_table()->bucket(bkt2);
|
||||||
|
int e_cnt2;
|
||||||
|
for (e_cnt2 = 0; e_ptr2 != NULL; e_ptr2 = e_ptr2->next(), e_cnt2++) {
|
||||||
|
if (bkt1 == bkt2 && e_cnt2 <= e_cnt1) {
|
||||||
|
// skip the entries up to and including the one that
|
||||||
|
// we're comparing against
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_entry_verify) {
|
||||||
|
VerifyRetTypes ret = verify_entry(bkt2, e_cnt2, e_ptr2,
|
||||||
|
_verify_quietly);
|
||||||
|
if (ret == _verify_fail_done) {
|
||||||
|
// cannot compare against this entry
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare two entries, report and count any failures:
|
||||||
|
if (compare_entries(bkt1, e_cnt1, e_ptr1, bkt2, e_cnt2, e_ptr2)
|
||||||
|
!= _verify_pass) {
|
||||||
|
fail_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fail_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new table and using alternate hash code, populate the new table
|
// Create a new table and using alternate hash code, populate the new table
|
||||||
// with the existing strings. Set flag to use the alternate hash code afterwards.
|
// with the existing strings. Set flag to use the alternate hash code afterwards.
|
||||||
|
|
|
@ -311,6 +311,26 @@ public:
|
||||||
static void verify();
|
static void verify();
|
||||||
static void dump(outputStream* st);
|
static void dump(outputStream* st);
|
||||||
|
|
||||||
|
enum VerifyMesgModes {
|
||||||
|
_verify_quietly = 0,
|
||||||
|
_verify_with_mesgs = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VerifyRetTypes {
|
||||||
|
_verify_pass = 0,
|
||||||
|
_verify_fail_continue = 1,
|
||||||
|
_verify_fail_done = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
static VerifyRetTypes compare_entries(int bkt1, int e_cnt1,
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr1,
|
||||||
|
int bkt2, int e_cnt2,
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr2);
|
||||||
|
static VerifyRetTypes verify_entry(int bkt, int e_cnt,
|
||||||
|
HashtableEntry<oop, mtSymbol>* e_ptr,
|
||||||
|
VerifyMesgModes mesg_mode);
|
||||||
|
static int verify_and_compare_entries();
|
||||||
|
|
||||||
// Sharing
|
// Sharing
|
||||||
static void copy_buckets(char** top, char*end) {
|
static void copy_buckets(char** top, char*end) {
|
||||||
the_table()->Hashtable<oop, mtSymbol>::copy_buckets(top, end);
|
the_table()->Hashtable<oop, mtSymbol>::copy_buckets(top, end);
|
||||||
|
|
|
@ -103,9 +103,10 @@ static void calculate_fingerprints() {
|
||||||
if (k->oop_is_instance()) {
|
if (k->oop_is_instance()) {
|
||||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||||
for (int i = 0; i < ik->methods()->length(); i++) {
|
for (int i = 0; i < ik->methods()->length(); i++) {
|
||||||
ResourceMark rm;
|
|
||||||
Method* m = ik->methods()->at(i);
|
Method* m = ik->methods()->at(i);
|
||||||
(new Fingerprinter(m))->fingerprint();
|
Fingerprinter fp(m);
|
||||||
|
// The side effect of this call sets method's fingerprint field.
|
||||||
|
fp.fingerprint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,16 +108,16 @@ objArrayOop ConstantPool::resolved_references() const {
|
||||||
void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data,
|
void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data,
|
||||||
intStack reference_map,
|
intStack reference_map,
|
||||||
int constant_pool_map_length,
|
int constant_pool_map_length,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
// Initialized the resolved object cache.
|
// Initialized the resolved object cache.
|
||||||
int map_length = reference_map.length();
|
int map_length = reference_map.length();
|
||||||
if (map_length > 0) {
|
if (map_length > 0) {
|
||||||
// Only need mapping back to constant pool entries. The map isn't used for
|
// Only need mapping back to constant pool entries. The map isn't used for
|
||||||
// invokedynamic resolved_reference entries. The constant pool cache index
|
// invokedynamic resolved_reference entries. For invokedynamic entries,
|
||||||
// has the mapping back to both the constant pool and to the resolved
|
// the constant pool cache index has the mapping back to both the constant
|
||||||
// reference index.
|
// pool and to the resolved reference index.
|
||||||
if (constant_pool_map_length > 0) {
|
if (constant_pool_map_length > 0) {
|
||||||
Array<u2>* om = MetadataFactory::new_array<u2>(loader_data, map_length, CHECK);
|
Array<u2>* om = MetadataFactory::new_array<u2>(loader_data, constant_pool_map_length, CHECK);
|
||||||
|
|
||||||
for (int i = 0; i < constant_pool_map_length; i++) {
|
for (int i = 0; i < constant_pool_map_length; i++) {
|
||||||
int x = reference_map.at(i);
|
int x = reference_map.at(i);
|
||||||
|
@ -182,16 +182,9 @@ oop ConstantPool::lock() {
|
||||||
|
|
||||||
int ConstantPool::cp_to_object_index(int cp_index) {
|
int ConstantPool::cp_to_object_index(int cp_index) {
|
||||||
// this is harder don't do this so much.
|
// this is harder don't do this so much.
|
||||||
for (int i = 0; i< reference_map()->length(); i++) {
|
int i = reference_map()->find(cp_index);
|
||||||
if (reference_map()->at(i) == cp_index) return i;
|
// We might not find the index for jsr292 call.
|
||||||
// Zero entry is divider between constant pool indices for strings,
|
return (i < 0) ? _no_index_sentinel : i;
|
||||||
// method handles and method types. After that the index is a constant
|
|
||||||
// pool cache index for invokedynamic. Stop when zero (which can never
|
|
||||||
// be a constant pool index)
|
|
||||||
if (reference_map()->at(i) == 0) break;
|
|
||||||
}
|
|
||||||
// We might not find the index.
|
|
||||||
return _no_index_sentinel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
|
Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
|
||||||
|
@ -840,8 +833,7 @@ oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj
|
||||||
// If the string has already been interned, this entry will be non-null
|
// If the string has already been interned, this entry will be non-null
|
||||||
oop str = this_oop->resolved_references()->obj_at(obj_index);
|
oop str = this_oop->resolved_references()->obj_at(obj_index);
|
||||||
if (str != NULL) return str;
|
if (str != NULL) return str;
|
||||||
|
Symbol* sym = this_oop->unresolved_string_at(which);
|
||||||
Symbol* sym = this_oop->unresolved_string_at(which);
|
|
||||||
str = StringTable::intern(sym, CHECK_(NULL));
|
str = StringTable::intern(sym, CHECK_(NULL));
|
||||||
this_oop->string_at_put(which, obj_index, str);
|
this_oop->string_at_put(which, obj_index, str);
|
||||||
assert(java_lang_String::is_instance(str), "must be string");
|
assert(java_lang_String::is_instance(str), "must be string");
|
||||||
|
@ -1619,9 +1611,11 @@ jint ConstantPool::cpool_entry_size(jint idx) {
|
||||||
case JVM_CONSTANT_UnresolvedClassInError:
|
case JVM_CONSTANT_UnresolvedClassInError:
|
||||||
case JVM_CONSTANT_StringIndex:
|
case JVM_CONSTANT_StringIndex:
|
||||||
case JVM_CONSTANT_MethodType:
|
case JVM_CONSTANT_MethodType:
|
||||||
|
case JVM_CONSTANT_MethodTypeInError:
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
case JVM_CONSTANT_MethodHandle:
|
case JVM_CONSTANT_MethodHandle:
|
||||||
|
case JVM_CONSTANT_MethodHandleInError:
|
||||||
return 4; //tag, ref_kind, ref_index
|
return 4; //tag, ref_kind, ref_index
|
||||||
|
|
||||||
case JVM_CONSTANT_Integer:
|
case JVM_CONSTANT_Integer:
|
||||||
|
@ -1802,8 +1796,8 @@ int ConstantPool::copy_cpool_bytes(int cpool_size,
|
||||||
case JVM_CONSTANT_MethodHandle:
|
case JVM_CONSTANT_MethodHandle:
|
||||||
case JVM_CONSTANT_MethodHandleInError: {
|
case JVM_CONSTANT_MethodHandleInError: {
|
||||||
*bytes = JVM_CONSTANT_MethodHandle;
|
*bytes = JVM_CONSTANT_MethodHandle;
|
||||||
int kind = method_handle_ref_kind_at(idx);
|
int kind = method_handle_ref_kind_at_error_ok(idx);
|
||||||
idx1 = method_handle_index_at(idx);
|
idx1 = method_handle_index_at_error_ok(idx);
|
||||||
*(bytes+1) = (unsigned char) kind;
|
*(bytes+1) = (unsigned char) kind;
|
||||||
Bytes::put_Java_u2((address) (bytes+2), idx1);
|
Bytes::put_Java_u2((address) (bytes+2), idx1);
|
||||||
DBG(printf("JVM_CONSTANT_MethodHandle: %d %hd", kind, idx1));
|
DBG(printf("JVM_CONSTANT_MethodHandle: %d %hd", kind, idx1));
|
||||||
|
@ -1812,7 +1806,7 @@ int ConstantPool::copy_cpool_bytes(int cpool_size,
|
||||||
case JVM_CONSTANT_MethodType:
|
case JVM_CONSTANT_MethodType:
|
||||||
case JVM_CONSTANT_MethodTypeInError: {
|
case JVM_CONSTANT_MethodTypeInError: {
|
||||||
*bytes = JVM_CONSTANT_MethodType;
|
*bytes = JVM_CONSTANT_MethodType;
|
||||||
idx1 = method_type_index_at(idx);
|
idx1 = method_type_index_at_error_ok(idx);
|
||||||
Bytes::put_Java_u2((address) (bytes+1), idx1);
|
Bytes::put_Java_u2((address) (bytes+1), idx1);
|
||||||
DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
|
DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
|
||||||
break;
|
break;
|
||||||
|
@ -2000,12 +1994,12 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) {
|
||||||
break;
|
break;
|
||||||
case JVM_CONSTANT_MethodHandle :
|
case JVM_CONSTANT_MethodHandle :
|
||||||
case JVM_CONSTANT_MethodHandleInError :
|
case JVM_CONSTANT_MethodHandleInError :
|
||||||
st->print("ref_kind=%d", method_handle_ref_kind_at(index));
|
st->print("ref_kind=%d", method_handle_ref_kind_at_error_ok(index));
|
||||||
st->print(" ref_index=%d", method_handle_index_at(index));
|
st->print(" ref_index=%d", method_handle_index_at_error_ok(index));
|
||||||
break;
|
break;
|
||||||
case JVM_CONSTANT_MethodType :
|
case JVM_CONSTANT_MethodType :
|
||||||
case JVM_CONSTANT_MethodTypeInError :
|
case JVM_CONSTANT_MethodTypeInError :
|
||||||
st->print("signature_index=%d", method_type_index_at(index));
|
st->print("signature_index=%d", method_type_index_at_error_ok(index));
|
||||||
break;
|
break;
|
||||||
case JVM_CONSTANT_InvokeDynamic :
|
case JVM_CONSTANT_InvokeDynamic :
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,7 +231,6 @@ class ConstantPool : public Metadata {
|
||||||
static int cache_offset_in_bytes() { return offset_of(ConstantPool, _cache); }
|
static int cache_offset_in_bytes() { return offset_of(ConstantPool, _cache); }
|
||||||
static int pool_holder_offset_in_bytes() { return offset_of(ConstantPool, _pool_holder); }
|
static int pool_holder_offset_in_bytes() { return offset_of(ConstantPool, _pool_holder); }
|
||||||
static int resolved_references_offset_in_bytes() { return offset_of(ConstantPool, _resolved_references); }
|
static int resolved_references_offset_in_bytes() { return offset_of(ConstantPool, _resolved_references); }
|
||||||
static int reference_map_offset_in_bytes() { return offset_of(ConstantPool, _reference_map); }
|
|
||||||
|
|
||||||
// Storing constants
|
// Storing constants
|
||||||
|
|
||||||
|
@ -475,18 +474,42 @@ class ConstantPool : public Metadata {
|
||||||
return *int_at_addr(which);
|
return *int_at_addr(which);
|
||||||
}
|
}
|
||||||
|
|
||||||
int method_handle_ref_kind_at(int which) {
|
private:
|
||||||
assert(tag_at(which).is_method_handle(), "Corrupted constant pool");
|
int method_handle_ref_kind_at(int which, bool error_ok) {
|
||||||
|
assert(tag_at(which).is_method_handle() ||
|
||||||
|
(error_ok && tag_at(which).is_method_handle_in_error()), "Corrupted constant pool");
|
||||||
return extract_low_short_from_int(*int_at_addr(which)); // mask out unwanted ref_index bits
|
return extract_low_short_from_int(*int_at_addr(which)); // mask out unwanted ref_index bits
|
||||||
}
|
}
|
||||||
int method_handle_index_at(int which) {
|
int method_handle_index_at(int which, bool error_ok) {
|
||||||
assert(tag_at(which).is_method_handle(), "Corrupted constant pool");
|
assert(tag_at(which).is_method_handle() ||
|
||||||
|
(error_ok && tag_at(which).is_method_handle_in_error()), "Corrupted constant pool");
|
||||||
return extract_high_short_from_int(*int_at_addr(which)); // shift out unwanted ref_kind bits
|
return extract_high_short_from_int(*int_at_addr(which)); // shift out unwanted ref_kind bits
|
||||||
}
|
}
|
||||||
int method_type_index_at(int which) {
|
int method_type_index_at(int which, bool error_ok) {
|
||||||
assert(tag_at(which).is_method_type(), "Corrupted constant pool");
|
assert(tag_at(which).is_method_type() ||
|
||||||
|
(error_ok && tag_at(which).is_method_type_in_error()), "Corrupted constant pool");
|
||||||
return *int_at_addr(which);
|
return *int_at_addr(which);
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
int method_handle_ref_kind_at(int which) {
|
||||||
|
return method_handle_ref_kind_at(which, false);
|
||||||
|
}
|
||||||
|
int method_handle_ref_kind_at_error_ok(int which) {
|
||||||
|
return method_handle_ref_kind_at(which, true);
|
||||||
|
}
|
||||||
|
int method_handle_index_at(int which) {
|
||||||
|
return method_handle_index_at(which, false);
|
||||||
|
}
|
||||||
|
int method_handle_index_at_error_ok(int which) {
|
||||||
|
return method_handle_index_at(which, true);
|
||||||
|
}
|
||||||
|
int method_type_index_at(int which) {
|
||||||
|
return method_type_index_at(which, false);
|
||||||
|
}
|
||||||
|
int method_type_index_at_error_ok(int which) {
|
||||||
|
return method_type_index_at(which, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Derived queries:
|
// Derived queries:
|
||||||
Symbol* method_handle_name_ref_at(int which) {
|
Symbol* method_handle_name_ref_at(int which) {
|
||||||
int member = method_handle_index_at(which);
|
int member = method_handle_index_at(which);
|
||||||
|
|
|
@ -2769,24 +2769,17 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||||
st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr();
|
st->print(BULLET"field annotations: "); fields_annotations()->print_value_on(st); st->cr();
|
||||||
st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr();
|
st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr();
|
||||||
{
|
{
|
||||||
ResourceMark rm;
|
bool have_pv = false;
|
||||||
// PreviousVersionInfo objects returned via PreviousVersionWalker
|
PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this);
|
||||||
// contain a GrowableArray of handles. We have to clean up the
|
for (PreviousVersionNode * pv_node = pvw.next_previous_version();
|
||||||
// GrowableArray _after_ the PreviousVersionWalker destructor
|
pv_node != NULL; pv_node = pvw.next_previous_version()) {
|
||||||
// has destroyed the handles.
|
if (!have_pv)
|
||||||
{
|
st->print(BULLET"previous version: ");
|
||||||
bool have_pv = false;
|
have_pv = true;
|
||||||
PreviousVersionWalker pvw((InstanceKlass*)this);
|
pv_node->prev_constant_pool()->print_value_on(st);
|
||||||
for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
|
}
|
||||||
pv_info != NULL; pv_info = pvw.next_previous_version()) {
|
if (have_pv) st->cr();
|
||||||
if (!have_pv)
|
} // pvw is cleaned up
|
||||||
st->print(BULLET"previous version: ");
|
|
||||||
have_pv = true;
|
|
||||||
pv_info->prev_constant_pool_handle()()->print_value_on(st);
|
|
||||||
}
|
|
||||||
if (have_pv) st->cr();
|
|
||||||
} // pvw is cleaned up
|
|
||||||
} // rm is cleaned up
|
|
||||||
|
|
||||||
if (generic_signature() != NULL) {
|
if (generic_signature() != NULL) {
|
||||||
st->print(BULLET"generic signature: ");
|
st->print(BULLET"generic signature: ");
|
||||||
|
@ -3317,34 +3310,34 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
||||||
Array<Method*>* old_methods = ikh->methods();
|
Array<Method*>* old_methods = ikh->methods();
|
||||||
|
|
||||||
if (cp_ref->on_stack()) {
|
if (cp_ref->on_stack()) {
|
||||||
PreviousVersionNode * pv_node = NULL;
|
PreviousVersionNode * pv_node = NULL;
|
||||||
if (emcp_method_count == 0) {
|
if (emcp_method_count == 0) {
|
||||||
// non-shared ConstantPool gets a reference
|
// non-shared ConstantPool gets a reference
|
||||||
pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), NULL);
|
pv_node = new PreviousVersionNode(cp_ref, NULL);
|
||||||
RC_TRACE(0x00000400,
|
RC_TRACE(0x00000400,
|
||||||
("add: all methods are obsolete; flushing any EMCP refs"));
|
("add: all methods are obsolete; flushing any EMCP refs"));
|
||||||
} else {
|
} else {
|
||||||
int local_count = 0;
|
int local_count = 0;
|
||||||
GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass)
|
GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass)
|
||||||
GrowableArray<Method*>(emcp_method_count, true);
|
GrowableArray<Method*>(emcp_method_count, true);
|
||||||
for (int i = 0; i < old_methods->length(); i++) {
|
for (int i = 0; i < old_methods->length(); i++) {
|
||||||
if (emcp_methods->at(i)) {
|
if (emcp_methods->at(i)) {
|
||||||
// this old method is EMCP. Save it only if it's on the stack
|
// this old method is EMCP. Save it only if it's on the stack
|
||||||
Method* old_method = old_methods->at(i);
|
Method* old_method = old_methods->at(i);
|
||||||
if (old_method->on_stack()) {
|
if (old_method->on_stack()) {
|
||||||
method_refs->append(old_method);
|
method_refs->append(old_method);
|
||||||
|
}
|
||||||
|
if (++local_count >= emcp_method_count) {
|
||||||
|
// no more EMCP methods so bail out now
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (++local_count >= emcp_method_count) {
|
|
||||||
// no more EMCP methods so bail out now
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// non-shared ConstantPool gets a reference
|
// non-shared ConstantPool gets a reference
|
||||||
pv_node = new PreviousVersionNode(cp_ref, !cp_ref->is_shared(), method_refs);
|
pv_node = new PreviousVersionNode(cp_ref, method_refs);
|
||||||
}
|
}
|
||||||
// append new previous version.
|
// append new previous version.
|
||||||
_previous_versions->append(pv_node);
|
_previous_versions->append(pv_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since the caller is the VMThread and we are at a safepoint, this
|
// Since the caller is the VMThread and we are at a safepoint, this
|
||||||
|
@ -3445,6 +3438,8 @@ Method* InstanceKlass::method_with_idnum(int idnum) {
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// None found, return null for the caller to handle.
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
@ -3461,10 +3456,9 @@ unsigned char * InstanceKlass::get_cached_class_file_bytes() {
|
||||||
// Construct a PreviousVersionNode entry for the array hung off
|
// Construct a PreviousVersionNode entry for the array hung off
|
||||||
// the InstanceKlass.
|
// the InstanceKlass.
|
||||||
PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool,
|
PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool,
|
||||||
bool prev_cp_is_weak, GrowableArray<Method*>* prev_EMCP_methods) {
|
GrowableArray<Method*>* prev_EMCP_methods) {
|
||||||
|
|
||||||
_prev_constant_pool = prev_constant_pool;
|
_prev_constant_pool = prev_constant_pool;
|
||||||
_prev_cp_is_weak = prev_cp_is_weak;
|
|
||||||
_prev_EMCP_methods = prev_EMCP_methods;
|
_prev_EMCP_methods = prev_EMCP_methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3480,99 +3474,38 @@ PreviousVersionNode::~PreviousVersionNode() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Construct a PreviousVersionInfo entry
|
|
||||||
PreviousVersionInfo::PreviousVersionInfo(PreviousVersionNode *pv_node) {
|
|
||||||
_prev_constant_pool_handle = constantPoolHandle(); // NULL handle
|
|
||||||
_prev_EMCP_method_handles = NULL;
|
|
||||||
|
|
||||||
ConstantPool* cp = pv_node->prev_constant_pool();
|
|
||||||
assert(cp != NULL, "constant pool ref was unexpectedly cleared");
|
|
||||||
if (cp == NULL) {
|
|
||||||
return; // robustness
|
|
||||||
}
|
|
||||||
|
|
||||||
// make the ConstantPool* safe to return
|
|
||||||
_prev_constant_pool_handle = constantPoolHandle(cp);
|
|
||||||
|
|
||||||
GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
|
|
||||||
if (method_refs == NULL) {
|
|
||||||
// the InstanceKlass did not have any EMCP methods
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_prev_EMCP_method_handles = new GrowableArray<methodHandle>(10);
|
|
||||||
|
|
||||||
int n_methods = method_refs->length();
|
|
||||||
for (int i = 0; i < n_methods; i++) {
|
|
||||||
Method* method = method_refs->at(i);
|
|
||||||
assert (method != NULL, "method has been cleared");
|
|
||||||
if (method == NULL) {
|
|
||||||
continue; // robustness
|
|
||||||
}
|
|
||||||
// make the Method* safe to return
|
|
||||||
_prev_EMCP_method_handles->append(methodHandle(method));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Destroy a PreviousVersionInfo
|
|
||||||
PreviousVersionInfo::~PreviousVersionInfo() {
|
|
||||||
// Since _prev_EMCP_method_handles is not C-heap allocated, we
|
|
||||||
// don't have to delete it.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Construct a helper for walking the previous versions array
|
// Construct a helper for walking the previous versions array
|
||||||
PreviousVersionWalker::PreviousVersionWalker(InstanceKlass *ik) {
|
PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) {
|
||||||
|
_thread = thread;
|
||||||
_previous_versions = ik->previous_versions();
|
_previous_versions = ik->previous_versions();
|
||||||
_current_index = 0;
|
_current_index = 0;
|
||||||
// _hm needs no initialization
|
|
||||||
_current_p = NULL;
|
_current_p = NULL;
|
||||||
}
|
_current_constant_pool_handle = constantPoolHandle(thread, ik->constants());
|
||||||
|
|
||||||
|
|
||||||
// Destroy a PreviousVersionWalker
|
|
||||||
PreviousVersionWalker::~PreviousVersionWalker() {
|
|
||||||
// Delete the current info just in case the caller didn't walk to
|
|
||||||
// the end of the previous versions list. No harm if _current_p is
|
|
||||||
// already NULL.
|
|
||||||
delete _current_p;
|
|
||||||
|
|
||||||
// When _hm is destroyed, all the Handles returned in
|
|
||||||
// PreviousVersionInfo objects will be destroyed.
|
|
||||||
// Also, after this destructor is finished it will be
|
|
||||||
// safe to delete the GrowableArray allocated in the
|
|
||||||
// PreviousVersionInfo objects.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Return the interesting information for the next previous version
|
// Return the interesting information for the next previous version
|
||||||
// of the klass. Returns NULL if there are no more previous versions.
|
// of the klass. Returns NULL if there are no more previous versions.
|
||||||
PreviousVersionInfo* PreviousVersionWalker::next_previous_version() {
|
PreviousVersionNode* PreviousVersionWalker::next_previous_version() {
|
||||||
if (_previous_versions == NULL) {
|
if (_previous_versions == NULL) {
|
||||||
// no previous versions so nothing to return
|
// no previous versions so nothing to return
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete _current_p; // cleanup the previous info for the caller
|
_current_p = NULL; // reset to NULL
|
||||||
_current_p = NULL; // reset to NULL so we don't delete same object twice
|
_current_constant_pool_handle = NULL;
|
||||||
|
|
||||||
int length = _previous_versions->length();
|
int length = _previous_versions->length();
|
||||||
|
|
||||||
while (_current_index < length) {
|
while (_current_index < length) {
|
||||||
PreviousVersionNode * pv_node = _previous_versions->at(_current_index++);
|
PreviousVersionNode * pv_node = _previous_versions->at(_current_index++);
|
||||||
PreviousVersionInfo * pv_info = new (ResourceObj::C_HEAP, mtClass)
|
|
||||||
PreviousVersionInfo(pv_node);
|
|
||||||
|
|
||||||
constantPoolHandle cp_h = pv_info->prev_constant_pool_handle();
|
// Save a handle to the constant pool for this previous version,
|
||||||
assert (!cp_h.is_null(), "null cp found in previous version");
|
// which keeps all the methods from being deallocated.
|
||||||
|
_current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool());
|
||||||
// The caller will need to delete pv_info when they are done with it.
|
_current_p = pv_node;
|
||||||
_current_p = pv_info;
|
return pv_node;
|
||||||
return pv_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// all of the underlying nodes' info has been deleted
|
|
||||||
return NULL;
|
return NULL;
|
||||||
} // end next_previous_version()
|
} // end next_previous_version()
|
||||||
|
|
|
@ -1126,21 +1126,11 @@ class BreakpointInfo;
|
||||||
|
|
||||||
|
|
||||||
// A collection point for interesting information about the previous
|
// A collection point for interesting information about the previous
|
||||||
// version(s) of an InstanceKlass. This class uses weak references to
|
// version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes
|
||||||
// the information so that the information may be collected as needed
|
// is attached to the InstanceKlass as needed. See PreviousVersionWalker below.
|
||||||
// by the system. If the information is shared, then a regular
|
|
||||||
// reference must be used because a weak reference would be seen as
|
|
||||||
// collectible. A GrowableArray of PreviousVersionNodes is attached
|
|
||||||
// to the InstanceKlass as needed. See PreviousVersionWalker below.
|
|
||||||
class PreviousVersionNode : public CHeapObj<mtClass> {
|
class PreviousVersionNode : public CHeapObj<mtClass> {
|
||||||
private:
|
private:
|
||||||
// A shared ConstantPool is never collected so we'll always have
|
ConstantPool* _prev_constant_pool;
|
||||||
// a reference to it so we can update items in the cache. We'll
|
|
||||||
// have a weak reference to a non-shared ConstantPool until all
|
|
||||||
// of the methods (EMCP or obsolete) have been collected; the
|
|
||||||
// non-shared ConstantPool becomes collectible at that point.
|
|
||||||
ConstantPool* _prev_constant_pool; // regular or weak reference
|
|
||||||
bool _prev_cp_is_weak; // true if not a shared ConstantPool
|
|
||||||
|
|
||||||
// If the previous version of the InstanceKlass doesn't have any
|
// If the previous version of the InstanceKlass doesn't have any
|
||||||
// EMCP methods, then _prev_EMCP_methods will be NULL. If all the
|
// EMCP methods, then _prev_EMCP_methods will be NULL. If all the
|
||||||
|
@ -1149,8 +1139,8 @@ class PreviousVersionNode : public CHeapObj<mtClass> {
|
||||||
GrowableArray<Method*>* _prev_EMCP_methods;
|
GrowableArray<Method*>* _prev_EMCP_methods;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PreviousVersionNode(ConstantPool* prev_constant_pool, bool prev_cp_is_weak,
|
PreviousVersionNode(ConstantPool* prev_constant_pool,
|
||||||
GrowableArray<Method*>* prev_EMCP_methods);
|
GrowableArray<Method*>* prev_EMCP_methods);
|
||||||
~PreviousVersionNode();
|
~PreviousVersionNode();
|
||||||
ConstantPool* prev_constant_pool() const {
|
ConstantPool* prev_constant_pool() const {
|
||||||
return _prev_constant_pool;
|
return _prev_constant_pool;
|
||||||
|
@ -1161,59 +1151,26 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// A Handle-ized version of PreviousVersionNode.
|
// Helper object for walking previous versions.
|
||||||
class PreviousVersionInfo : public ResourceObj {
|
|
||||||
private:
|
|
||||||
constantPoolHandle _prev_constant_pool_handle;
|
|
||||||
// If the previous version of the InstanceKlass doesn't have any
|
|
||||||
// EMCP methods, then _prev_EMCP_methods will be NULL. Since the
|
|
||||||
// methods cannot be collected while we hold a handle,
|
|
||||||
// _prev_EMCP_methods should never have a length of zero.
|
|
||||||
GrowableArray<methodHandle>* _prev_EMCP_method_handles;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PreviousVersionInfo(PreviousVersionNode *pv_node);
|
|
||||||
~PreviousVersionInfo();
|
|
||||||
constantPoolHandle prev_constant_pool_handle() const {
|
|
||||||
return _prev_constant_pool_handle;
|
|
||||||
}
|
|
||||||
GrowableArray<methodHandle>* prev_EMCP_method_handles() const {
|
|
||||||
return _prev_EMCP_method_handles;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Helper object for walking previous versions. This helper cleans up
|
|
||||||
// the Handles that it allocates when the helper object is destroyed.
|
|
||||||
// The PreviousVersionInfo object returned by next_previous_version()
|
|
||||||
// is only valid until a subsequent call to next_previous_version() or
|
|
||||||
// the helper object is destroyed.
|
|
||||||
class PreviousVersionWalker : public StackObj {
|
class PreviousVersionWalker : public StackObj {
|
||||||
private:
|
private:
|
||||||
|
Thread* _thread;
|
||||||
GrowableArray<PreviousVersionNode *>* _previous_versions;
|
GrowableArray<PreviousVersionNode *>* _previous_versions;
|
||||||
int _current_index;
|
int _current_index;
|
||||||
// Fields for cleaning up when we are done walking the previous versions:
|
|
||||||
// A HandleMark for the PreviousVersionInfo handles:
|
|
||||||
HandleMark _hm;
|
|
||||||
|
|
||||||
// It would be nice to have a ResourceMark field in this helper also,
|
// A pointer to the current node object so we can handle the deletes.
|
||||||
// but the ResourceMark code says to be careful to delete handles held
|
PreviousVersionNode* _current_p;
|
||||||
// in GrowableArrays _before_ deleting the GrowableArray. Since we
|
|
||||||
// can't guarantee the order in which the fields are destroyed, we
|
|
||||||
// have to let the creator of the PreviousVersionWalker object do
|
|
||||||
// the right thing. Also, adding a ResourceMark here causes an
|
|
||||||
// include loop.
|
|
||||||
|
|
||||||
// A pointer to the current info object so we can handle the deletes.
|
// The constant pool handle keeps all the methods in this class from being
|
||||||
PreviousVersionInfo * _current_p;
|
// deallocated from the metaspace during class unloading.
|
||||||
|
constantPoolHandle _current_constant_pool_handle;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PreviousVersionWalker(InstanceKlass *ik);
|
PreviousVersionWalker(Thread* thread, InstanceKlass *ik);
|
||||||
~PreviousVersionWalker();
|
|
||||||
|
|
||||||
// Return the interesting information for the next previous version
|
// Return the interesting information for the next previous version
|
||||||
// of the klass. Returns NULL if there are no more previous versions.
|
// of the klass. Returns NULL if there are no more previous versions.
|
||||||
PreviousVersionInfo* next_previous_version();
|
PreviousVersionNode* next_previous_version();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1835,16 +1835,27 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
|
||||||
}
|
}
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly))
|
static bool select_method(methodHandle method, bool want_constructor) {
|
||||||
{
|
if (want_constructor) {
|
||||||
JVMWrapper("JVM_GetClassDeclaredMethods");
|
return (method->is_initializer() && !method->is_static());
|
||||||
|
} else {
|
||||||
|
return (!method->is_initializer() && !method->is_overpass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static jobjectArray get_class_declared_methods_helper(
|
||||||
|
JNIEnv *env,
|
||||||
|
jclass ofClass, jboolean publicOnly,
|
||||||
|
bool want_constructor,
|
||||||
|
Klass* klass, TRAPS) {
|
||||||
|
|
||||||
JvmtiVMObjectAllocEventCollector oam;
|
JvmtiVMObjectAllocEventCollector oam;
|
||||||
|
|
||||||
// Exclude primitive types and array types
|
// Exclude primitive types and array types
|
||||||
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
|
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
|
||||||
|| java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
|
|| java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
|
||||||
// Return empty array
|
// Return empty array
|
||||||
oop res = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), 0, CHECK_NULL);
|
oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL);
|
||||||
return (jobjectArray) JNIHandles::make_local(env, res);
|
return (jobjectArray) JNIHandles::make_local(env, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1855,87 +1866,67 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass,
|
||||||
|
|
||||||
Array<Method*>* methods = k->methods();
|
Array<Method*>* methods = k->methods();
|
||||||
int methods_length = methods->length();
|
int methods_length = methods->length();
|
||||||
|
|
||||||
|
// Save original method_idnum in case of redefinition, which can change
|
||||||
|
// the idnum of obsolete methods. The new method will have the same idnum
|
||||||
|
// but if we refresh the methods array, the counts will be wrong.
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
GrowableArray<int>* idnums = new GrowableArray<int>(methods_length);
|
||||||
int num_methods = 0;
|
int num_methods = 0;
|
||||||
|
|
||||||
int i;
|
for (int i = 0; i < methods_length; i++) {
|
||||||
for (i = 0; i < methods_length; i++) {
|
|
||||||
methodHandle method(THREAD, methods->at(i));
|
methodHandle method(THREAD, methods->at(i));
|
||||||
if (!method->is_initializer() && !method->is_overpass()) {
|
if (select_method(method, want_constructor)) {
|
||||||
if (!publicOnly || method->is_public()) {
|
if (!publicOnly || method->is_public()) {
|
||||||
|
idnums->push(method->method_idnum());
|
||||||
++num_methods;
|
++num_methods;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate result
|
// Allocate result
|
||||||
objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Method_klass(), num_methods, CHECK_NULL);
|
objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL);
|
||||||
objArrayHandle result (THREAD, r);
|
objArrayHandle result (THREAD, r);
|
||||||
|
|
||||||
int out_idx = 0;
|
// Now just put the methods that we selected above, but go by their idnum
|
||||||
for (i = 0; i < methods_length; i++) {
|
// in case of redefinition. The methods can be redefined at any safepoint,
|
||||||
methodHandle method(THREAD, methods->at(i));
|
// so above when allocating the oop array and below when creating reflect
|
||||||
if (!method->is_initializer() && !method->is_overpass()) {
|
// objects.
|
||||||
if (!publicOnly || method->is_public()) {
|
for (int i = 0; i < num_methods; i++) {
|
||||||
oop m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL);
|
methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
|
||||||
result->obj_at_put(out_idx, m);
|
if (method.is_null()) {
|
||||||
++out_idx;
|
// Method may have been deleted and seems this API can handle null
|
||||||
|
// Otherwise should probably put a method that throws NSME
|
||||||
|
result->obj_at_put(i, NULL);
|
||||||
|
} else {
|
||||||
|
oop m;
|
||||||
|
if (want_constructor) {
|
||||||
|
m = Reflection::new_constructor(method, CHECK_NULL);
|
||||||
|
} else {
|
||||||
|
m = Reflection::new_method(method, UseNewReflection, false, CHECK_NULL);
|
||||||
}
|
}
|
||||||
|
result->obj_at_put(i, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(out_idx == num_methods, "just checking");
|
|
||||||
return (jobjectArray) JNIHandles::make_local(env, result());
|
return (jobjectArray) JNIHandles::make_local(env, result());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass, jboolean publicOnly))
|
||||||
|
{
|
||||||
|
JVMWrapper("JVM_GetClassDeclaredMethods");
|
||||||
|
return get_class_declared_methods_helper(env, ofClass, publicOnly,
|
||||||
|
/*want_constructor*/ false,
|
||||||
|
SystemDictionary::reflect_Method_klass(), THREAD);
|
||||||
|
}
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
|
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
|
||||||
{
|
{
|
||||||
JVMWrapper("JVM_GetClassDeclaredConstructors");
|
JVMWrapper("JVM_GetClassDeclaredConstructors");
|
||||||
JvmtiVMObjectAllocEventCollector oam;
|
return get_class_declared_methods_helper(env, ofClass, publicOnly,
|
||||||
|
/*want_constructor*/ true,
|
||||||
// Exclude primitive types and array types
|
SystemDictionary::reflect_Constructor_klass(), THREAD);
|
||||||
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass))
|
|
||||||
|| java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
|
|
||||||
// Return empty array
|
|
||||||
oop res = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), 0 , CHECK_NULL);
|
|
||||||
return (jobjectArray) JNIHandles::make_local(env, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceKlassHandle k(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass)));
|
|
||||||
|
|
||||||
// Ensure class is linked
|
|
||||||
k->link_class(CHECK_NULL);
|
|
||||||
|
|
||||||
Array<Method*>* methods = k->methods();
|
|
||||||
int methods_length = methods->length();
|
|
||||||
int num_constructors = 0;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < methods_length; i++) {
|
|
||||||
methodHandle method(THREAD, methods->at(i));
|
|
||||||
if (method->is_initializer() && !method->is_static()) {
|
|
||||||
if (!publicOnly || method->is_public()) {
|
|
||||||
++num_constructors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate result
|
|
||||||
objArrayOop r = oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), num_constructors, CHECK_NULL);
|
|
||||||
objArrayHandle result(THREAD, r);
|
|
||||||
|
|
||||||
int out_idx = 0;
|
|
||||||
for (i = 0; i < methods_length; i++) {
|
|
||||||
methodHandle method(THREAD, methods->at(i));
|
|
||||||
if (method->is_initializer() && !method->is_static()) {
|
|
||||||
if (!publicOnly || method->is_public()) {
|
|
||||||
oop m = Reflection::new_constructor(method, CHECK_NULL);
|
|
||||||
result->obj_at_put(out_idx, m);
|
|
||||||
++out_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(out_idx == num_constructors, "just checking");
|
|
||||||
return (jobjectArray) JNIHandles::make_local(env, result());
|
|
||||||
}
|
}
|
||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
|
|
@ -406,7 +406,11 @@ public:
|
||||||
VMOp_Type type() const { return VMOp_GetCurrentContendedMonitor; }
|
VMOp_Type type() const { return VMOp_GetCurrentContendedMonitor; }
|
||||||
jvmtiError result() { return _result; }
|
jvmtiError result() { return _result; }
|
||||||
void doit() {
|
void doit() {
|
||||||
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
|
_result = JVMTI_ERROR_THREAD_NOT_ALIVE;
|
||||||
|
if (Threads::includes(_java_thread) && !_java_thread->is_exiting() &&
|
||||||
|
_java_thread->threadObj() != NULL) {
|
||||||
|
_result = ((JvmtiEnvBase *)_env)->get_current_contended_monitor(_calling_thread,_java_thread,_owned_monitor_ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -273,59 +273,49 @@ void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
|
||||||
|
|
||||||
// add/remove breakpoint to/from versions of the method that
|
// add/remove breakpoint to/from versions of the method that
|
||||||
// are EMCP. Directly or transitively obsolete methods are
|
// are EMCP. Directly or transitively obsolete methods are
|
||||||
// not saved in the PreviousVersionInfo.
|
// not saved in the PreviousVersionNodes.
|
||||||
Thread *thread = Thread::current();
|
Thread *thread = Thread::current();
|
||||||
instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder());
|
instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder());
|
||||||
Symbol* m_name = _method->name();
|
Symbol* m_name = _method->name();
|
||||||
Symbol* m_signature = _method->signature();
|
Symbol* m_signature = _method->signature();
|
||||||
|
|
||||||
{
|
// search previous versions if they exist
|
||||||
ResourceMark rm(thread);
|
PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh());
|
||||||
// PreviousVersionInfo objects returned via PreviousVersionWalker
|
for (PreviousVersionNode * pv_node = pvw.next_previous_version();
|
||||||
// contain a GrowableArray of handles. We have to clean up the
|
pv_node != NULL; pv_node = pvw.next_previous_version()) {
|
||||||
// GrowableArray _after_ the PreviousVersionWalker destructor
|
GrowableArray<Method*>* methods = pv_node->prev_EMCP_methods();
|
||||||
// has destroyed the handles.
|
|
||||||
{
|
|
||||||
// search previous versions if they exist
|
|
||||||
PreviousVersionWalker pvw((InstanceKlass *)ikh());
|
|
||||||
for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
|
|
||||||
pv_info != NULL; pv_info = pvw.next_previous_version()) {
|
|
||||||
GrowableArray<methodHandle>* methods =
|
|
||||||
pv_info->prev_EMCP_method_handles();
|
|
||||||
|
|
||||||
if (methods == NULL) {
|
if (methods == NULL) {
|
||||||
// We have run into a PreviousVersion generation where
|
// We have run into a PreviousVersion generation where
|
||||||
// all methods were made obsolete during that generation's
|
// all methods were made obsolete during that generation's
|
||||||
// RedefineClasses() operation. At the time of that
|
// RedefineClasses() operation. At the time of that
|
||||||
// operation, all EMCP methods were flushed so we don't
|
// operation, all EMCP methods were flushed so we don't
|
||||||
// have to go back any further.
|
// have to go back any further.
|
||||||
//
|
//
|
||||||
// A NULL methods array is different than an empty methods
|
// A NULL methods array is different than an empty methods
|
||||||
// array. We cannot infer any optimizations about older
|
// array. We cannot infer any optimizations about older
|
||||||
// generations from an empty methods array for the current
|
// generations from an empty methods array for the current
|
||||||
// generation.
|
// generation.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = methods->length() - 1; i >= 0; i--) {
|
for (int i = methods->length() - 1; i >= 0; i--) {
|
||||||
methodHandle method = methods->at(i);
|
Method* method = methods->at(i);
|
||||||
// obsolete methods that are running are not deleted from
|
// obsolete methods that are running are not deleted from
|
||||||
// previous version array, but they are skipped here.
|
// previous version array, but they are skipped here.
|
||||||
if (!method->is_obsolete() &&
|
if (!method->is_obsolete() &&
|
||||||
method->name() == m_name &&
|
method->name() == m_name &&
|
||||||
method->signature() == m_signature) {
|
method->signature() == m_signature) {
|
||||||
RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
|
RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
|
||||||
meth_act == &Method::set_breakpoint ? "sett" : "clear",
|
meth_act == &Method::set_breakpoint ? "sett" : "clear",
|
||||||
method->name()->as_C_string(),
|
method->name()->as_C_string(),
|
||||||
method->signature()->as_C_string()));
|
method->signature()->as_C_string()));
|
||||||
|
|
||||||
((Method*)method()->*meth_act)(_bci);
|
(method->*meth_act)(_bci);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // pvw is cleaned up
|
}
|
||||||
} // rm is cleaned up
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JvmtiBreakpoint::set() {
|
void JvmtiBreakpoint::set() {
|
||||||
|
|
|
@ -2807,28 +2807,20 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||||
&trace_name_printed);
|
&trace_name_printed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
|
||||||
ResourceMark rm(_thread);
|
// the previous versions' constant pool caches may need adjustment
|
||||||
// PreviousVersionInfo objects returned via PreviousVersionWalker
|
PreviousVersionWalker pvw(_thread, ik);
|
||||||
// contain a GrowableArray of handles. We have to clean up the
|
for (PreviousVersionNode * pv_node = pvw.next_previous_version();
|
||||||
// GrowableArray _after_ the PreviousVersionWalker destructor
|
pv_node != NULL; pv_node = pvw.next_previous_version()) {
|
||||||
// has destroyed the handles.
|
other_cp = pv_node->prev_constant_pool();
|
||||||
{
|
cp_cache = other_cp->cache();
|
||||||
// the previous versions' constant pool caches may need adjustment
|
if (cp_cache != NULL) {
|
||||||
PreviousVersionWalker pvw(ik);
|
cp_cache->adjust_method_entries(_matching_old_methods,
|
||||||
for (PreviousVersionInfo * pv_info = pvw.next_previous_version();
|
_matching_new_methods,
|
||||||
pv_info != NULL; pv_info = pvw.next_previous_version()) {
|
_matching_methods_length,
|
||||||
other_cp = pv_info->prev_constant_pool_handle();
|
&trace_name_printed);
|
||||||
cp_cache = other_cp->cache();
|
}
|
||||||
if (cp_cache != NULL) {
|
}
|
||||||
cp_cache->adjust_method_entries(_matching_old_methods,
|
|
||||||
_matching_new_methods,
|
|
||||||
_matching_methods_length,
|
|
||||||
&trace_name_printed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // pvw is cleaned up
|
|
||||||
} // rm is cleaned up
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2942,10 +2934,9 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
|
||||||
// obsolete methods need a unique idnum
|
// obsolete methods need a unique idnum
|
||||||
u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
|
u2 num = InstanceKlass::cast(_the_class_oop)->next_method_idnum();
|
||||||
if (num != ConstMethod::UNSET_IDNUM) {
|
if (num != ConstMethod::UNSET_IDNUM) {
|
||||||
// u2 old_num = old_method->method_idnum();
|
|
||||||
old_method->set_method_idnum(num);
|
old_method->set_method_idnum(num);
|
||||||
// TO DO: attach obsolete annotations to obsolete method's new idnum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// With tracing we try not to "yack" too much. The position of
|
// With tracing we try not to "yack" too much. The position of
|
||||||
// this trace assumes there are fewer obsolete methods than
|
// this trace assumes there are fewer obsolete methods than
|
||||||
// EMCP methods.
|
// EMCP methods.
|
||||||
|
|
|
@ -1100,6 +1100,7 @@ void Arguments::set_mode_flags(Mode mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(COMPILER2) || defined(_LP64) || !INCLUDE_CDS
|
||||||
// Conflict: required to use shared spaces (-Xshare:on), but
|
// Conflict: required to use shared spaces (-Xshare:on), but
|
||||||
// incompatible command line options were chosen.
|
// incompatible command line options were chosen.
|
||||||
|
|
||||||
|
@ -1112,6 +1113,7 @@ static void no_shared_spaces() {
|
||||||
FLAG_SET_DEFAULT(UseSharedSpaces, false);
|
FLAG_SET_DEFAULT(UseSharedSpaces, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Arguments::set_tiered_flags() {
|
void Arguments::set_tiered_flags() {
|
||||||
// With tiered, set default policy to AdvancedThresholdPolicy, which is 3.
|
// With tiered, set default policy to AdvancedThresholdPolicy, which is 3.
|
||||||
|
@ -1523,16 +1525,18 @@ void Arguments::set_ergonomics_flags() {
|
||||||
FLAG_SET_ERGO(bool, UseParallelGC, true);
|
FLAG_SET_ERGO(bool, UseParallelGC, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Shared spaces work fine with other GCs but causes bytecode rewriting
|
|
||||||
// to be disabled, which hurts interpreter performance and decreases
|
|
||||||
// server performance. On server class machines, keep the default
|
|
||||||
// off unless it is asked for. Future work: either add bytecode rewriting
|
|
||||||
// at link time, or rewrite bytecodes in non-shared methods.
|
|
||||||
if (!DumpSharedSpaces && !RequireSharedSpaces &&
|
|
||||||
(FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) {
|
|
||||||
no_shared_spaces();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#ifdef COMPILER2
|
||||||
|
// Shared spaces work fine with other GCs but causes bytecode rewriting
|
||||||
|
// to be disabled, which hurts interpreter performance and decreases
|
||||||
|
// server performance. When -server is specified, keep the default off
|
||||||
|
// unless it is asked for. Future work: either add bytecode rewriting
|
||||||
|
// at link time, or rewrite bytecodes in non-shared methods.
|
||||||
|
if (!DumpSharedSpaces && !RequireSharedSpaces &&
|
||||||
|
(FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) {
|
||||||
|
no_shared_spaces();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
set_conservative_max_heap_alignment();
|
set_conservative_max_heap_alignment();
|
||||||
|
|
||||||
|
@ -2446,21 +2450,6 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AggressiveOpts) {
|
|
||||||
// Insert alt-rt.jar between user-specified bootclasspath
|
|
||||||
// prefix and the default bootclasspath. os::set_boot_path()
|
|
||||||
// uses meta_index_dir as the default bootclasspath directory.
|
|
||||||
const char* altclasses_jar = "alt-rt.jar";
|
|
||||||
size_t altclasses_path_len = strlen(get_meta_index_dir()) + 1 +
|
|
||||||
strlen(altclasses_jar);
|
|
||||||
char* altclasses_path = NEW_C_HEAP_ARRAY(char, altclasses_path_len, mtInternal);
|
|
||||||
strcpy(altclasses_path, get_meta_index_dir());
|
|
||||||
strcat(altclasses_path, altclasses_jar);
|
|
||||||
scp.add_suffix_to_prefix(altclasses_path);
|
|
||||||
scp_assembly_required = true;
|
|
||||||
FREE_C_HEAP_ARRAY(char, altclasses_path, mtInternal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse _JAVA_OPTIONS environment variable (if present) (mimics classic VM)
|
// Parse _JAVA_OPTIONS environment variable (if present) (mimics classic VM)
|
||||||
result = parse_java_options_environment_variable(&scp, &scp_assembly_required);
|
result = parse_java_options_environment_variable(&scp, &scp_assembly_required);
|
||||||
if (result != JNI_OK) {
|
if (result != JNI_OK) {
|
||||||
|
|
|
@ -2567,6 +2567,9 @@ class CommandLineFlags {
|
||||||
product(bool, PrintStringTableStatistics, false, \
|
product(bool, PrintStringTableStatistics, false, \
|
||||||
"print statistics about the StringTable and SymbolTable") \
|
"print statistics about the StringTable and SymbolTable") \
|
||||||
\
|
\
|
||||||
|
diagnostic(bool, VerifyStringTableAtExit, false, \
|
||||||
|
"verify StringTable contents at exit") \
|
||||||
|
\
|
||||||
notproduct(bool, PrintSymbolTableSizeHistogram, false, \
|
notproduct(bool, PrintSymbolTableSizeHistogram, false, \
|
||||||
"print histogram of the symbol table") \
|
"print histogram of the symbol table") \
|
||||||
\
|
\
|
||||||
|
|
|
@ -136,7 +136,7 @@ DEF_HANDLE(typeArray , is_typeArray )
|
||||||
// Specific Handles for different oop types
|
// Specific Handles for different oop types
|
||||||
#define DEF_METADATA_HANDLE(name, type) \
|
#define DEF_METADATA_HANDLE(name, type) \
|
||||||
class name##Handle; \
|
class name##Handle; \
|
||||||
class name##Handle { \
|
class name##Handle : public StackObj { \
|
||||||
type* _value; \
|
type* _value; \
|
||||||
Thread* _thread; \
|
Thread* _thread; \
|
||||||
protected: \
|
protected: \
|
||||||
|
@ -175,7 +175,7 @@ DEF_METADATA_HANDLE(constantPool, ConstantPool)
|
||||||
// Writing this class explicitly, since DEF_METADATA_HANDLE(klass) doesn't
|
// Writing this class explicitly, since DEF_METADATA_HANDLE(klass) doesn't
|
||||||
// provide the necessary Klass* <-> Klass* conversions. This Klass
|
// provide the necessary Klass* <-> Klass* conversions. This Klass
|
||||||
// could be removed when we don't have the Klass* typedef anymore.
|
// could be removed when we don't have the Klass* typedef anymore.
|
||||||
class KlassHandle {
|
class KlassHandle : public StackObj {
|
||||||
Klass* _value;
|
Klass* _value;
|
||||||
protected:
|
protected:
|
||||||
Klass* obj() const { return _value; }
|
Klass* obj() const { return _value; }
|
||||||
|
|
|
@ -79,6 +79,7 @@ inline name##Handle::name##Handle(const name##Handle &h) { \
|
||||||
} else { \
|
} else { \
|
||||||
_thread = Thread::current(); \
|
_thread = Thread::current(); \
|
||||||
} \
|
} \
|
||||||
|
assert (_thread->is_in_stack((address)this), "not on stack?"); \
|
||||||
_thread->metadata_handles()->push((Metadata*)_value); \
|
_thread->metadata_handles()->push((Metadata*)_value); \
|
||||||
} else { \
|
} else { \
|
||||||
_thread = NULL; \
|
_thread = NULL; \
|
||||||
|
@ -95,6 +96,7 @@ inline name##Handle& name##Handle::operator=(const name##Handle &s) { \
|
||||||
} else { \
|
} else { \
|
||||||
_thread = Thread::current(); \
|
_thread = Thread::current(); \
|
||||||
} \
|
} \
|
||||||
|
assert (_thread->is_in_stack((address)this), "not on stack?"); \
|
||||||
_thread->metadata_handles()->push((Metadata*)_value); \
|
_thread->metadata_handles()->push((Metadata*)_value); \
|
||||||
} else { \
|
} else { \
|
||||||
_thread = NULL; \
|
_thread = NULL; \
|
||||||
|
|
|
@ -544,6 +544,19 @@ void before_exit(JavaThread * thread) {
|
||||||
// it will run into trouble when system destroys static variables.
|
// it will run into trouble when system destroys static variables.
|
||||||
MemTracker::shutdown(MemTracker::NMT_normal);
|
MemTracker::shutdown(MemTracker::NMT_normal);
|
||||||
|
|
||||||
|
if (VerifyStringTableAtExit) {
|
||||||
|
int fail_cnt = 0;
|
||||||
|
{
|
||||||
|
MutexLocker ml(StringTable_lock);
|
||||||
|
fail_cnt = StringTable::verify_and_compare_entries();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail_cnt != 0) {
|
||||||
|
tty->print_cr("ERROR: fail_cnt=%d", fail_cnt);
|
||||||
|
guarantee(fail_cnt == 0, "unexpected StringTable verification failures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef BEFORE_EXIT_NOT_RUN
|
#undef BEFORE_EXIT_NOT_RUN
|
||||||
#undef BEFORE_EXIT_RUNNING
|
#undef BEFORE_EXIT_RUNNING
|
||||||
#undef BEFORE_EXIT_DONE
|
#undef BEFORE_EXIT_DONE
|
||||||
|
|
|
@ -470,7 +470,17 @@ void AttachListener::init() {
|
||||||
vmSymbols::threadgroup_string_void_signature(),
|
vmSymbols::threadgroup_string_void_signature(),
|
||||||
thread_group,
|
thread_group,
|
||||||
string,
|
string,
|
||||||
CHECK);
|
THREAD);
|
||||||
|
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
tty->print_cr("Exception in VM (AttachListener::init) : ");
|
||||||
|
java_lang_Throwable::print(PENDING_EXCEPTION, tty);
|
||||||
|
tty->cr();
|
||||||
|
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
|
KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
|
||||||
JavaCalls::call_special(&result,
|
JavaCalls::call_special(&result,
|
||||||
|
@ -479,7 +489,17 @@ void AttachListener::init() {
|
||||||
vmSymbols::add_method_name(),
|
vmSymbols::add_method_name(),
|
||||||
vmSymbols::thread_void_signature(),
|
vmSymbols::thread_void_signature(),
|
||||||
thread_oop, // ARG 1
|
thread_oop, // ARG 1
|
||||||
CHECK);
|
THREAD);
|
||||||
|
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
tty->print_cr("Exception in VM (AttachListener::init) : ");
|
||||||
|
java_lang_Throwable::print(PENDING_EXCEPTION, tty);
|
||||||
|
tty->cr();
|
||||||
|
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{ MutexLocker mu(Threads_lock);
|
{ MutexLocker mu(Threads_lock);
|
||||||
JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
|
JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
|
||||||
|
|
|
@ -61,7 +61,7 @@ void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenDCmdArgument::to_string(char* c, char* buf, size_t len) {
|
void GenDCmdArgument::to_string(char* c, char* buf, size_t len) {
|
||||||
jio_snprintf(buf, len, "%s", c);
|
jio_snprintf(buf, len, "%s", (c != NULL) ? c : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) {
|
void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) {
|
||||||
|
|
|
@ -33,16 +33,9 @@ import com.oracle.java.testlibrary.*;
|
||||||
|
|
||||||
public class XShareAuto {
|
public class XShareAuto {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
if (!Platform.is64bit()) {
|
|
||||||
System.out.println("ObjectAlignmentInBytes for CDS is only " +
|
|
||||||
"supported on 64bit platforms; this plaform is " +
|
|
||||||
System.getProperty("sun.arch.data.model"));
|
|
||||||
System.out.println("Skipping the test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||||
"-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa",
|
"-server", "-XX:+UnlockDiagnosticVMOptions",
|
||||||
"-Xshare:dump");
|
"-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump");
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
output.shouldContain("Loading classes to share");
|
output.shouldContain("Loading classes to share");
|
||||||
output.shouldHaveExitValue(0);
|
output.shouldHaveExitValue(0);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue