mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 18:44:38 +02:00
Merge
This commit is contained in:
commit
6ca042cb32
29 changed files with 868 additions and 367 deletions
|
@ -51,7 +51,8 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
|
||||||
# Add conditional directories here when needed.
|
# Add conditional directories here when needed.
|
||||||
ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
|
ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), solaris-sparc)
|
||||||
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
|
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
|
||||||
$(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc
|
$(HOTSPOT_TOPDIR)/test/runtime/libadimalloc.solaris.sparc \
|
||||||
|
$(HOTSPOT_TOPDIR)/test/runtime/ThreadSignalMask
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(TOOLCHAIN_TYPE), solstudio)
|
ifeq ($(TOOLCHAIN_TYPE), solstudio)
|
||||||
|
|
|
@ -137,7 +137,7 @@ juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p,
|
||||||
if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
|
if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
|
||||||
base_address = uintx(MetaspaceShared::shared_rs()->base());
|
base_address = uintx(MetaspaceShared::shared_rs()->base());
|
||||||
max_delta = uintx(MetaspaceShared::shared_rs()->size());
|
max_delta = uintx(MetaspaceShared::shared_rs()->size());
|
||||||
assert(max_delta <= 0x7fffffff, "range check");
|
assert(max_delta <= MAX_SHARED_DELTA, "range check");
|
||||||
} else {
|
} else {
|
||||||
assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table");
|
assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table");
|
||||||
assert(UseCompressedOops, "UseCompressedOops is required");
|
assert(UseCompressedOops, "UseCompressedOops is required");
|
||||||
|
|
|
@ -499,10 +499,13 @@ HeapWord* G1BlockOffsetArrayContigSpace::initialize_threshold() {
|
||||||
return _next_offset_threshold;
|
return _next_offset_threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top) {
|
void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||||
// The first BOT entry should have offset 0.
|
// The first BOT entry should have offset 0.
|
||||||
reset_bot();
|
reset_bot();
|
||||||
alloc_block(_bottom, obj_top);
|
alloc_block(_bottom, obj_top);
|
||||||
|
if (fill_size > 0) {
|
||||||
|
alloc_block(obj_top, fill_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
|
@ -372,7 +372,7 @@ class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray {
|
||||||
HeapWord* block_start_unsafe(const void* addr);
|
HeapWord* block_start_unsafe(const void* addr);
|
||||||
HeapWord* block_start_unsafe_const(const void* addr) const;
|
HeapWord* block_start_unsafe_const(const void* addr) const;
|
||||||
|
|
||||||
void set_for_starts_humongous(HeapWord* obj_top);
|
void set_for_starts_humongous(HeapWord* obj_top, size_t fill_size);
|
||||||
|
|
||||||
virtual void print_on(outputStream* out) PRODUCT_RETURN;
|
virtual void print_on(outputStream* out) PRODUCT_RETURN;
|
||||||
};
|
};
|
||||||
|
|
|
@ -339,11 +339,18 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||||
// thread to calculate the object size incorrectly.
|
// thread to calculate the object size incorrectly.
|
||||||
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
|
Copy::fill_to_words(new_obj, oopDesc::header_size(), 0);
|
||||||
|
|
||||||
|
size_t fill_size = word_size_sum - word_size;
|
||||||
|
if (fill_size >= min_fill_size()) {
|
||||||
|
fill_with_objects(obj_top, fill_size);
|
||||||
|
} else {
|
||||||
|
fill_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// We will set up the first region as "starts humongous". This
|
// We will set up the first region as "starts humongous". This
|
||||||
// will also update the BOT covering all the regions to reflect
|
// will also update the BOT covering all the regions to reflect
|
||||||
// that there is a single object that starts at the bottom of the
|
// that there is a single object that starts at the bottom of the
|
||||||
// first region.
|
// first region.
|
||||||
first_hr->set_starts_humongous(obj_top);
|
first_hr->set_starts_humongous(obj_top, fill_size);
|
||||||
first_hr->set_allocation_context(context);
|
first_hr->set_allocation_context(context);
|
||||||
// Then, if there are any, we will set up the "continues
|
// Then, if there are any, we will set up the "continues
|
||||||
// humongous" regions.
|
// humongous" regions.
|
||||||
|
@ -365,9 +372,9 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||||
|
|
||||||
// Now that the BOT and the object header have been initialized,
|
// Now that the BOT and the object header have been initialized,
|
||||||
// we can update top of the "starts humongous" region.
|
// we can update top of the "starts humongous" region.
|
||||||
first_hr->set_top(MIN2(first_hr->end(), obj_top));
|
first_hr->set_top(first_hr->end());
|
||||||
if (_hr_printer.is_active()) {
|
if (_hr_printer.is_active()) {
|
||||||
_hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->top());
|
_hr_printer.alloc(G1HRPrinter::StartsHumongous, first_hr, first_hr->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, we will update the top fields of the "continues humongous"
|
// Now, we will update the top fields of the "continues humongous"
|
||||||
|
@ -375,25 +382,18 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||||
hr = NULL;
|
hr = NULL;
|
||||||
for (uint i = first + 1; i < last; ++i) {
|
for (uint i = first + 1; i < last; ++i) {
|
||||||
hr = region_at(i);
|
hr = region_at(i);
|
||||||
if ((i + 1) == last) {
|
|
||||||
// last continues humongous region
|
|
||||||
assert(hr->bottom() < obj_top && obj_top <= hr->end(),
|
|
||||||
"new_top should fall on this region");
|
|
||||||
hr->set_top(obj_top);
|
|
||||||
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, obj_top);
|
|
||||||
} else {
|
|
||||||
// not last one
|
|
||||||
assert(obj_top > hr->end(), "obj_top should be above this region");
|
|
||||||
hr->set_top(hr->end());
|
hr->set_top(hr->end());
|
||||||
|
if (_hr_printer.is_active()) {
|
||||||
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end());
|
_hr_printer.alloc(G1HRPrinter::ContinuesHumongous, hr, hr->end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we have continues humongous regions (hr != NULL), its top should
|
|
||||||
// match obj_top.
|
assert(hr == NULL || (hr->bottom() < obj_top && obj_top <= hr->end()),
|
||||||
assert(hr == NULL || (hr->top() == obj_top), "sanity");
|
"obj_top should be in last region");
|
||||||
|
|
||||||
check_bitmaps("Humongous Region Allocation", first_hr);
|
check_bitmaps("Humongous Region Allocation", first_hr);
|
||||||
|
|
||||||
increase_used(word_size * HeapWordSize);
|
increase_used(word_size_sum * HeapWordSize);
|
||||||
|
|
||||||
for (uint i = first; i < last; ++i) {
|
for (uint i = first; i < last; ++i) {
|
||||||
_humongous_set.add(region_at(i));
|
_humongous_set.add(region_at(i));
|
||||||
|
@ -1202,9 +1202,8 @@ void G1CollectedHeap::print_hrm_post_compaction() {
|
||||||
heap_region_iterate(&cl);
|
heap_region_iterate(&cl);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool G1CollectedHeap::do_collection(bool explicit_gc,
|
bool G1CollectedHeap::do_full_collection(bool explicit_gc,
|
||||||
bool clear_all_soft_refs,
|
bool clear_all_soft_refs) {
|
||||||
size_t word_size) {
|
|
||||||
assert_at_safepoint(true /* should_be_vm_thread */);
|
assert_at_safepoint(true /* should_be_vm_thread */);
|
||||||
|
|
||||||
if (GC_locker::check_active_before_gc()) {
|
if (GC_locker::check_active_before_gc()) {
|
||||||
|
@ -1362,8 +1361,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
||||||
clear_rsets_post_compaction();
|
clear_rsets_post_compaction();
|
||||||
check_gc_time_stamps();
|
check_gc_time_stamps();
|
||||||
|
|
||||||
// Resize the heap if necessary.
|
resize_if_necessary_after_full_collection();
|
||||||
resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size);
|
|
||||||
|
|
||||||
if (_hr_printer.is_active()) {
|
if (_hr_printer.is_active()) {
|
||||||
// We should do this after we potentially resize the heap so
|
// We should do this after we potentially resize the heap so
|
||||||
|
@ -1471,22 +1469,15 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) {
|
void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) {
|
||||||
// do_collection() will return whether it succeeded in performing
|
// Currently, there is no facility in the do_full_collection(bool) API to notify
|
||||||
// the GC. Currently, there is no facility on the
|
// the caller that the collection did not succeed (e.g., because it was locked
|
||||||
// do_full_collection() API to notify the caller than the collection
|
// out by the GC locker). So, right now, we'll ignore the return value.
|
||||||
// did not succeed (e.g., because it was locked out by the GC
|
bool dummy = do_full_collection(true, /* explicit_gc */
|
||||||
// locker). So, right now, we'll ignore the return value.
|
clear_all_soft_refs);
|
||||||
bool dummy = do_collection(true, /* explicit_gc */
|
|
||||||
clear_all_soft_refs,
|
|
||||||
0 /* word_size */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This code is mostly copied from TenuredGeneration.
|
void G1CollectedHeap::resize_if_necessary_after_full_collection() {
|
||||||
void
|
// Include bytes that will be pre-allocated to support collections, as "used".
|
||||||
G1CollectedHeap::
|
|
||||||
resize_if_necessary_after_full_collection(size_t word_size) {
|
|
||||||
// Include the current allocation, if any, and bytes that will be
|
|
||||||
// pre-allocated to support collections, as "used".
|
|
||||||
const size_t used_after_gc = used();
|
const size_t used_after_gc = used();
|
||||||
const size_t capacity_after_gc = capacity();
|
const size_t capacity_after_gc = capacity();
|
||||||
const size_t free_after_gc = capacity_after_gc - used_after_gc;
|
const size_t free_after_gc = capacity_after_gc - used_after_gc;
|
||||||
|
@ -1598,9 +1589,8 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size,
|
||||||
|
|
||||||
if (do_gc) {
|
if (do_gc) {
|
||||||
// Expansion didn't work, we'll try to do a Full GC.
|
// Expansion didn't work, we'll try to do a Full GC.
|
||||||
*gc_succeeded = do_collection(false, /* explicit_gc */
|
*gc_succeeded = do_full_collection(false, /* explicit_gc */
|
||||||
clear_all_soft_refs,
|
clear_all_soft_refs);
|
||||||
word_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -471,26 +471,20 @@ protected:
|
||||||
void retire_gc_alloc_region(HeapRegion* alloc_region,
|
void retire_gc_alloc_region(HeapRegion* alloc_region,
|
||||||
size_t allocated_bytes, InCSetState dest);
|
size_t allocated_bytes, InCSetState dest);
|
||||||
|
|
||||||
// - if explicit_gc is true, the GC is for a System.gc() or a heap
|
// - if explicit_gc is true, the GC is for a System.gc() etc,
|
||||||
// inspection request and should collect the entire heap
|
// otherwise it's for a failed allocation.
|
||||||
// - if clear_all_soft_refs is true, all soft references should be
|
// - if clear_all_soft_refs is true, all soft references should be
|
||||||
// cleared during the GC
|
// cleared during the GC.
|
||||||
// - if explicit_gc is false, word_size describes the allocation that
|
|
||||||
// the GC should attempt (at least) to satisfy
|
|
||||||
// - it returns false if it is unable to do the collection due to the
|
// - it returns false if it is unable to do the collection due to the
|
||||||
// GC locker being active, true otherwise
|
// GC locker being active, true otherwise.
|
||||||
bool do_collection(bool explicit_gc,
|
bool do_full_collection(bool explicit_gc,
|
||||||
bool clear_all_soft_refs,
|
bool clear_all_soft_refs);
|
||||||
size_t word_size);
|
|
||||||
|
|
||||||
// Callback from VM_G1CollectFull operation.
|
// Callback from VM_G1CollectFull operation, or collect_as_vm_thread.
|
||||||
// Perform a full collection.
|
|
||||||
virtual void do_full_collection(bool clear_all_soft_refs);
|
virtual void do_full_collection(bool clear_all_soft_refs);
|
||||||
|
|
||||||
// Resize the heap if necessary after a full collection. If this is
|
// Resize the heap if necessary after a full collection.
|
||||||
// after a collect-for allocation, "word_size" is the allocation size,
|
void resize_if_necessary_after_full_collection();
|
||||||
// and will be considered part of the used portion of the heap.
|
|
||||||
void resize_if_necessary_after_full_collection(size_t word_size);
|
|
||||||
|
|
||||||
// Callback from VM_G1CollectForAllocation operation.
|
// Callback from VM_G1CollectForAllocation operation.
|
||||||
// This function does everything necessary/possible to satisfy a
|
// This function does everything necessary/possible to satisfy a
|
||||||
|
@ -1150,9 +1144,6 @@ public:
|
||||||
// "CollectedHeap" supports.
|
// "CollectedHeap" supports.
|
||||||
virtual void collect(GCCause::Cause cause);
|
virtual void collect(GCCause::Cause cause);
|
||||||
|
|
||||||
// The same as above but assume that the caller holds the Heap_lock.
|
|
||||||
void collect_locked(GCCause::Cause cause);
|
|
||||||
|
|
||||||
virtual bool copy_allocation_context_stats(const jint* contexts,
|
virtual bool copy_allocation_context_stats(const jint* contexts,
|
||||||
jlong* totals,
|
jlong* totals,
|
||||||
jbyte* accuracy,
|
jbyte* accuracy,
|
||||||
|
@ -1352,14 +1343,6 @@ public:
|
||||||
return (region_size / 2);
|
return (region_size / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update mod union table with the set of dirty cards.
|
|
||||||
void updateModUnion();
|
|
||||||
|
|
||||||
// Set the mod union bits corresponding to the given memRegion. Note
|
|
||||||
// that this is always a safe operation, since it doesn't clear any
|
|
||||||
// bits.
|
|
||||||
void markModUnionRange(MemRegion mr);
|
|
||||||
|
|
||||||
// Print the maximum heap capacity.
|
// Print the maximum heap capacity.
|
||||||
virtual size_t max_capacity() const;
|
virtual size_t max_capacity() const;
|
||||||
|
|
||||||
|
|
|
@ -123,16 +123,13 @@ enum G1Mark {
|
||||||
|
|
||||||
template <G1Barrier barrier, G1Mark do_mark_object>
|
template <G1Barrier barrier, G1Mark do_mark_object>
|
||||||
class G1ParCopyClosure : public G1ParCopyHelper {
|
class G1ParCopyClosure : public G1ParCopyHelper {
|
||||||
private:
|
|
||||||
template <class T> void do_oop_work(T* p);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
|
G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
|
||||||
G1ParCopyHelper(g1, par_scan_state) {
|
G1ParCopyHelper(g1, par_scan_state) {
|
||||||
assert(ref_processor() == NULL, "sanity");
|
assert(ref_processor() == NULL, "sanity");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> void do_oop_nv(T* p) { do_oop_work(p); }
|
template <class T> void do_oop_nv(T* p);
|
||||||
virtual void do_oop(oop* p) { do_oop_nv(p); }
|
virtual void do_oop(oop* p) { do_oop_nv(p); }
|
||||||
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
|
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -251,7 +251,7 @@ void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) {
|
||||||
|
|
||||||
template <G1Barrier barrier, G1Mark do_mark_object>
|
template <G1Barrier barrier, G1Mark do_mark_object>
|
||||||
template <class T>
|
template <class T>
|
||||||
void G1ParCopyClosure<barrier, do_mark_object>::do_oop_work(T* p) {
|
void G1ParCopyClosure<barrier, do_mark_object>::do_oop_nv(T* p) {
|
||||||
T heap_oop = oopDesc::load_heap_oop(p);
|
T heap_oop = oopDesc::load_heap_oop(p);
|
||||||
|
|
||||||
if (oopDesc::is_null(heap_oop)) {
|
if (oopDesc::is_null(heap_oop)) {
|
||||||
|
|
|
@ -73,23 +73,7 @@ G1RemSet::~G1RemSet() {
|
||||||
FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl);
|
FREE_C_HEAP_ARRAY(G1ParPushHeapRSClosure*, _cset_rs_update_cl);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScanRSClosure : public HeapRegionClosure {
|
ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc,
|
||||||
size_t _cards_done, _cards;
|
|
||||||
G1CollectedHeap* _g1h;
|
|
||||||
|
|
||||||
G1ParPushHeapRSClosure* _oc;
|
|
||||||
CodeBlobClosure* _code_root_cl;
|
|
||||||
|
|
||||||
G1BlockOffsetSharedArray* _bot_shared;
|
|
||||||
G1SATBCardTableModRefBS *_ct_bs;
|
|
||||||
|
|
||||||
double _strong_code_root_scan_time_sec;
|
|
||||||
uint _worker_i;
|
|
||||||
size_t _block_size;
|
|
||||||
bool _try_claimed;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ScanRSClosure(G1ParPushHeapRSClosure* oc,
|
|
||||||
CodeBlobClosure* code_root_cl,
|
CodeBlobClosure* code_root_cl,
|
||||||
uint worker_i) :
|
uint worker_i) :
|
||||||
_oc(oc),
|
_oc(oc),
|
||||||
|
@ -98,17 +82,14 @@ public:
|
||||||
_cards(0),
|
_cards(0),
|
||||||
_cards_done(0),
|
_cards_done(0),
|
||||||
_worker_i(worker_i),
|
_worker_i(worker_i),
|
||||||
_try_claimed(false)
|
_try_claimed(false) {
|
||||||
{
|
|
||||||
_g1h = G1CollectedHeap::heap();
|
_g1h = G1CollectedHeap::heap();
|
||||||
_bot_shared = _g1h->bot_shared();
|
_bot_shared = _g1h->bot_shared();
|
||||||
_ct_bs = _g1h->g1_barrier_set();
|
_ct_bs = _g1h->g1_barrier_set();
|
||||||
_block_size = MAX2<size_t>(G1RSetScanBlockSize, 1);
|
_block_size = MAX2<size_t>(G1RSetScanBlockSize, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_try_claimed() { _try_claimed = true; }
|
void ScanRSClosure::scanCard(size_t index, HeapRegion *r) {
|
||||||
|
|
||||||
void scanCard(size_t index, HeapRegion *r) {
|
|
||||||
// Stack allocate the DirtyCardToOopClosure instance
|
// Stack allocate the DirtyCardToOopClosure instance
|
||||||
HeapRegionDCTOC cl(_g1h, r, _oc,
|
HeapRegionDCTOC cl(_g1h, r, _oc,
|
||||||
CardTableModRefBS::Precise);
|
CardTableModRefBS::Precise);
|
||||||
|
@ -128,7 +109,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printCard(HeapRegion* card_region, size_t card_index,
|
void ScanRSClosure::printCard(HeapRegion* card_region, size_t card_index,
|
||||||
HeapWord* card_start) {
|
HeapWord* card_start) {
|
||||||
gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") "
|
gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") "
|
||||||
"RS names card " SIZE_FORMAT_HEX ": "
|
"RS names card " SIZE_FORMAT_HEX ": "
|
||||||
|
@ -139,13 +120,13 @@ public:
|
||||||
p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words));
|
p2i(card_start), p2i(card_start + G1BlockOffsetSharedArray::N_words));
|
||||||
}
|
}
|
||||||
|
|
||||||
void scan_strong_code_roots(HeapRegion* r) {
|
void ScanRSClosure::scan_strong_code_roots(HeapRegion* r) {
|
||||||
double scan_start = os::elapsedTime();
|
double scan_start = os::elapsedTime();
|
||||||
r->strong_code_roots_do(_code_root_cl);
|
r->strong_code_roots_do(_code_root_cl);
|
||||||
_strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start);
|
_strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doHeapRegion(HeapRegion* r) {
|
bool ScanRSClosure::doHeapRegion(HeapRegion* r) {
|
||||||
assert(r->in_collection_set(), "should only be called on elements of CS.");
|
assert(r->in_collection_set(), "should only be called on elements of CS.");
|
||||||
HeapRegionRemSet* hrrs = r->rem_set();
|
HeapRegionRemSet* hrrs = r->rem_set();
|
||||||
if (hrrs->iter_is_complete()) return false; // All done.
|
if (hrrs->iter_is_complete()) return false; // All done.
|
||||||
|
@ -198,14 +179,6 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double strong_code_root_scan_time_sec() {
|
|
||||||
return _strong_code_root_scan_time_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t cards_done() { return _cards_done;}
|
|
||||||
size_t cards_looked_up() { return _cards;}
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t G1RemSet::scanRS(G1ParPushHeapRSClosure* oc,
|
size_t G1RemSet::scanRS(G1ParPushHeapRSClosure* oc,
|
||||||
CodeBlobClosure* heap_region_codeblobs,
|
CodeBlobClosure* heap_region_codeblobs,
|
||||||
uint worker_i) {
|
uint worker_i) {
|
||||||
|
|
|
@ -156,6 +156,41 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ScanRSClosure : public HeapRegionClosure {
|
||||||
|
size_t _cards_done, _cards;
|
||||||
|
G1CollectedHeap* _g1h;
|
||||||
|
|
||||||
|
G1ParPushHeapRSClosure* _oc;
|
||||||
|
CodeBlobClosure* _code_root_cl;
|
||||||
|
|
||||||
|
G1BlockOffsetSharedArray* _bot_shared;
|
||||||
|
G1SATBCardTableModRefBS *_ct_bs;
|
||||||
|
|
||||||
|
double _strong_code_root_scan_time_sec;
|
||||||
|
uint _worker_i;
|
||||||
|
size_t _block_size;
|
||||||
|
bool _try_claimed;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScanRSClosure(G1ParPushHeapRSClosure* oc,
|
||||||
|
CodeBlobClosure* code_root_cl,
|
||||||
|
uint worker_i);
|
||||||
|
|
||||||
|
bool doHeapRegion(HeapRegion* r);
|
||||||
|
|
||||||
|
double strong_code_root_scan_time_sec() {
|
||||||
|
return _strong_code_root_scan_time_sec;
|
||||||
|
}
|
||||||
|
size_t cards_done() { return _cards_done;}
|
||||||
|
size_t cards_looked_up() { return _cards;}
|
||||||
|
void set_try_claimed() { _try_claimed = true; }
|
||||||
|
private:
|
||||||
|
void scanCard(size_t index, HeapRegion *r);
|
||||||
|
void printCard(HeapRegion* card_region, size_t card_index,
|
||||||
|
HeapWord* card_start);
|
||||||
|
void scan_strong_code_roots(HeapRegion* r);
|
||||||
|
};
|
||||||
|
|
||||||
class UpdateRSOopClosure: public ExtendedOopClosure {
|
class UpdateRSOopClosure: public ExtendedOopClosure {
|
||||||
HeapRegion* _from;
|
HeapRegion* _from;
|
||||||
G1RemSet* _rs;
|
G1RemSet* _rs;
|
||||||
|
|
|
@ -211,14 +211,14 @@ void HeapRegion::calc_gc_efficiency() {
|
||||||
_gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
|
_gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeapRegion::set_starts_humongous(HeapWord* obj_top) {
|
void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||||
assert(!is_humongous(), "sanity / pre-condition");
|
assert(!is_humongous(), "sanity / pre-condition");
|
||||||
assert(top() == bottom(), "should be empty");
|
assert(top() == bottom(), "should be empty");
|
||||||
|
|
||||||
_type.set_starts_humongous();
|
_type.set_starts_humongous();
|
||||||
_humongous_start_region = this;
|
_humongous_start_region = this;
|
||||||
|
|
||||||
_offsets.set_for_starts_humongous(obj_top);
|
_offsets.set_for_starts_humongous(obj_top, fill_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeapRegion::set_continues_humongous(HeapRegion* first_hr) {
|
void HeapRegion::set_continues_humongous(HeapRegion* first_hr) {
|
||||||
|
@ -756,16 +756,6 @@ void HeapRegion::verify(VerifyOption vo,
|
||||||
size_t obj_size = block_size(p);
|
size_t obj_size = block_size(p);
|
||||||
object_num += 1;
|
object_num += 1;
|
||||||
|
|
||||||
if (is_region_humongous != g1->is_humongous(obj_size) &&
|
|
||||||
!g1->is_obj_dead(obj, this)) { // Dead objects may have bigger block_size since they span several objects.
|
|
||||||
gclog_or_tty->print_cr("obj " PTR_FORMAT " is of %shumongous size ("
|
|
||||||
SIZE_FORMAT " words) in a %shumongous region",
|
|
||||||
p2i(p), g1->is_humongous(obj_size) ? "" : "non-",
|
|
||||||
obj_size, is_region_humongous ? "" : "non-");
|
|
||||||
*failures = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g1->is_obj_dead_cond(obj, this, vo)) {
|
if (!g1->is_obj_dead_cond(obj, this, vo)) {
|
||||||
if (obj->is_oop()) {
|
if (obj->is_oop()) {
|
||||||
Klass* klass = obj->klass();
|
Klass* klass = obj->klass();
|
||||||
|
@ -876,14 +866,6 @@ void HeapRegion::verify(VerifyOption vo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_region_humongous && object_num > 1) {
|
|
||||||
gclog_or_tty->print_cr("region [" PTR_FORMAT "," PTR_FORMAT "] is humongous "
|
|
||||||
"but has " SIZE_FORMAT ", objects",
|
|
||||||
p2i(bottom()), p2i(end()), object_num);
|
|
||||||
*failures = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_strong_code_roots(vo, failures);
|
verify_strong_code_roots(vo, failures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -455,9 +455,9 @@ class HeapRegion: public G1OffsetTableContigSpace {
|
||||||
// the first region in a series of one or more contiguous regions
|
// the first region in a series of one or more contiguous regions
|
||||||
// that will contain a single "humongous" object.
|
// that will contain a single "humongous" object.
|
||||||
//
|
//
|
||||||
// obj_top : points to the end of the humongous object that's being
|
// obj_top : points to the top of the humongous object.
|
||||||
// allocated.
|
// fill_size : size of the filler object at the end of the region series.
|
||||||
void set_starts_humongous(HeapWord* obj_top);
|
void set_starts_humongous(HeapWord* obj_top, size_t fill_size);
|
||||||
|
|
||||||
// Makes the current region be a "continues humongous'
|
// Makes the current region be a "continues humongous'
|
||||||
// region. first_hr is the "start humongous" region of the series
|
// region. first_hr is the "start humongous" region of the series
|
||||||
|
|
|
@ -37,10 +37,10 @@ void Test_log_length() {
|
||||||
|
|
||||||
// Write long message to output file
|
// Write long message to output file
|
||||||
MutexLocker ml(LogConfiguration_lock);
|
MutexLocker ml(LogConfiguration_lock);
|
||||||
LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=develop",
|
LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace",
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
outputStream* logstream = LogHandle(logging)::develop_stream();
|
outputStream* logstream = LogHandle(logging)::trace_stream();
|
||||||
logstream->print_cr("01:1234567890-"
|
logstream->print_cr("01:1234567890-"
|
||||||
"02:1234567890-"
|
"02:1234567890-"
|
||||||
"03:1234567890-"
|
"03:1234567890-"
|
||||||
|
|
|
@ -49,11 +49,21 @@
|
||||||
#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
|
#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
|
||||||
#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
|
#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
|
||||||
#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
|
#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
|
||||||
|
|
||||||
|
// Macros for logging that should be excluded in product builds.
|
||||||
|
// Available for levels Info, Debug and Trace. Includes test macro that
|
||||||
|
// evaluates to false in product builds.
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Develop>
|
#define log_develop_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
|
||||||
|
#define log_develop_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
|
||||||
|
#define log_develop_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
|
||||||
|
#define develop_log_is_enabled(level, ...) log_is_enabled(level, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define DUMMY_ARGUMENT_CONSUMER(...)
|
#define DUMMY_ARGUMENT_CONSUMER(...)
|
||||||
#define log_develop(...) DUMMY_ARGUMENT_CONSUMER
|
#define log_develop_info(...) DUMMY_ARGUMENT_CONSUMER
|
||||||
|
#define log_develop_debug(...) DUMMY_ARGUMENT_CONSUMER
|
||||||
|
#define log_develop_trace(...) DUMMY_ARGUMENT_CONSUMER
|
||||||
|
#define develop_log_is_enabled(...) false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Convenience macro to test if the logging is enabled on the specified level for given tags.
|
// Convenience macro to test if the logging is enabled on the specified level for given tags.
|
||||||
|
@ -88,6 +98,11 @@ class Log VALUE_OBJ_CLASS_SPEC {
|
||||||
// is not __NO_TAG, the number of tags given exceeds the maximum allowed.
|
// is not __NO_TAG, the number of tags given exceeds the maximum allowed.
|
||||||
STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported!
|
STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported!
|
||||||
|
|
||||||
|
// Empty constructor to avoid warnings on MSVC about unused variables
|
||||||
|
// when the log instance is only used for static functions.
|
||||||
|
Log() {
|
||||||
|
}
|
||||||
|
|
||||||
static bool is_level(LogLevelType level) {
|
static bool is_level(LogLevelType level) {
|
||||||
return LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().is_level(level);
|
return LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().is_level(level);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ void LogConfiguration::post_initialize() {
|
||||||
LogDiagnosticCommand::registerCommand();
|
LogDiagnosticCommand::registerCommand();
|
||||||
LogHandle(logging) log;
|
LogHandle(logging) log;
|
||||||
log.info("Log configuration fully initialized.");
|
log.info("Log configuration fully initialized.");
|
||||||
|
log_develop_info(logging)("Develop logging is available.");
|
||||||
if (log.is_trace()) {
|
if (log.is_trace()) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
MutexLocker ml(LogConfiguration_lock);
|
MutexLocker ml(LogConfiguration_lock);
|
||||||
|
|
|
@ -29,14 +29,8 @@
|
||||||
|
|
||||||
// The list of log levels:
|
// The list of log levels:
|
||||||
//
|
//
|
||||||
// develop - A non-product level that is finer than trace.
|
// trace - Finest level of logging. Use for extensive/noisy
|
||||||
// Should be used for really expensive and/or
|
// logging that can give slow-down when enabled.
|
||||||
// extensive logging, or logging that shouldn't
|
|
||||||
// or can't be included in a product build.
|
|
||||||
//
|
|
||||||
// trace - Finest level of logging in product builds.
|
|
||||||
// Use for extensive/noisy logging that can
|
|
||||||
// give slow-down when enabled.
|
|
||||||
//
|
//
|
||||||
// debug - A finer level of logging. Use for semi-noisy
|
// debug - A finer level of logging. Use for semi-noisy
|
||||||
// logging that is does not fit the info level.
|
// logging that is does not fit the info level.
|
||||||
|
@ -49,7 +43,6 @@
|
||||||
// error - Critical messages caused by errors.
|
// error - Critical messages caused by errors.
|
||||||
//
|
//
|
||||||
#define LOG_LEVEL_LIST \
|
#define LOG_LEVEL_LIST \
|
||||||
NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \
|
|
||||||
LOG_LEVEL(Trace, trace) \
|
LOG_LEVEL(Trace, trace) \
|
||||||
LOG_LEVEL(Debug, debug) \
|
LOG_LEVEL(Debug, debug) \
|
||||||
LOG_LEVEL(Info, info) \
|
LOG_LEVEL(Info, info) \
|
||||||
|
|
|
@ -3230,36 +3230,6 @@ void Metaspace::global_initialize() {
|
||||||
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
|
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
|
||||||
SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment);
|
SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment);
|
||||||
|
|
||||||
// make sure SharedReadOnlySize and SharedReadWriteSize are not less than
|
|
||||||
// the minimum values.
|
|
||||||
if (SharedReadOnlySize < MetaspaceShared::min_ro_size){
|
|
||||||
report_out_of_shared_space(SharedReadOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SharedReadWriteSize < MetaspaceShared::min_rw_size){
|
|
||||||
report_out_of_shared_space(SharedReadWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the min_misc_data_size and min_misc_code_size estimates are based on
|
|
||||||
// MetaspaceShared::generate_vtable_methods().
|
|
||||||
// The minimum size only accounts for the vtable methods. Any size less than the
|
|
||||||
// minimum required size would cause vm crash when allocating the vtable methods.
|
|
||||||
uint min_misc_data_size = align_size_up(
|
|
||||||
MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment);
|
|
||||||
|
|
||||||
if (SharedMiscDataSize < min_misc_data_size) {
|
|
||||||
report_out_of_shared_space(SharedMiscData);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintx min_misc_code_size = align_size_up(
|
|
||||||
(MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size) *
|
|
||||||
(sizeof(void*) + MetaspaceShared::vtbl_method_size) + MetaspaceShared::vtbl_common_code_size,
|
|
||||||
max_alignment);
|
|
||||||
|
|
||||||
if (SharedMiscCodeSize < min_misc_code_size) {
|
|
||||||
report_out_of_shared_space(SharedMiscCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize with the sum of the shared space sizes. The read-only
|
// Initialize with the sum of the shared space sizes. The read-only
|
||||||
// and read write metaspace chunks will be allocated out of this and the
|
// and read write metaspace chunks will be allocated out of this and the
|
||||||
// remainder is the misc code and data chunks.
|
// remainder is the misc code and data chunks.
|
||||||
|
|
|
@ -32,6 +32,47 @@
|
||||||
#include "utilities/exceptions.hpp"
|
#include "utilities/exceptions.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
|
|
||||||
|
#define DEFAULT_VTBL_LIST_SIZE (17) // number of entries in the shared space vtable list.
|
||||||
|
#define DEFAULT_VTBL_VIRTUALS_COUNT (200) // maximum number of virtual functions
|
||||||
|
// If virtual functions are added to Metadata,
|
||||||
|
// this number needs to be increased. Also,
|
||||||
|
// SharedMiscCodeSize will need to be increased.
|
||||||
|
// The following 2 sizes were based on
|
||||||
|
// MetaspaceShared::generate_vtable_methods()
|
||||||
|
#define DEFAULT_VTBL_METHOD_SIZE (16) // conservative size of the mov1 and jmp instructions
|
||||||
|
// for the x64 platform
|
||||||
|
#define DEFAULT_VTBL_COMMON_CODE_SIZE (1*K) // conservative size of the "common_code" for the x64 platform
|
||||||
|
|
||||||
|
#define DEFAULT_SHARED_READ_WRITE_SIZE (NOT_LP64(12*M) LP64_ONLY(16*M))
|
||||||
|
#define MIN_SHARED_READ_WRITE_SIZE (NOT_LP64(7*M) LP64_ONLY(12*M))
|
||||||
|
|
||||||
|
#define DEFAULT_SHARED_READ_ONLY_SIZE (NOT_LP64(12*M) LP64_ONLY(16*M))
|
||||||
|
#define MIN_SHARED_READ_ONLY_SIZE (NOT_LP64(8*M) LP64_ONLY(9*M))
|
||||||
|
|
||||||
|
// the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on
|
||||||
|
// MetaspaceShared::generate_vtable_methods().
|
||||||
|
// The minimum size only accounts for the vtable methods. Any size less than the
|
||||||
|
// minimum required size would cause vm crash when allocating the vtable methods.
|
||||||
|
#define SHARED_MISC_SIZE_FOR(size) (DEFAULT_VTBL_VIRTUALS_COUNT*DEFAULT_VTBL_LIST_SIZE*size)
|
||||||
|
|
||||||
|
#define DEFAULT_SHARED_MISC_DATA_SIZE (NOT_LP64(2*M) LP64_ONLY(4*M))
|
||||||
|
#define MIN_SHARED_MISC_DATA_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*)))
|
||||||
|
|
||||||
|
#define DEFAULT_SHARED_MISC_CODE_SIZE (120*K)
|
||||||
|
#define MIN_SHARED_MISC_CODE_SIZE (SHARED_MISC_SIZE_FOR(sizeof(void*))+SHARED_MISC_SIZE_FOR(DEFAULT_VTBL_METHOD_SIZE)+DEFAULT_VTBL_COMMON_CODE_SIZE)
|
||||||
|
|
||||||
|
#define DEFAULT_COMBINED_SIZE (DEFAULT_SHARED_READ_WRITE_SIZE+DEFAULT_SHARED_READ_ONLY_SIZE+DEFAULT_SHARED_MISC_DATA_SIZE+DEFAULT_SHARED_MISC_CODE_SIZE)
|
||||||
|
|
||||||
|
// the max size is the MAX size (ie. 0x7FFFFFFF) - the total size of
|
||||||
|
// the other 3 sections - page size (to avoid overflow in case the final
|
||||||
|
// size will get aligned up on page size)
|
||||||
|
#define SHARED_PAGE ((size_t)os::vm_page_size())
|
||||||
|
#define MAX_SHARED_DELTA (0x7FFFFFFF)
|
||||||
|
#define MAX_SHARED_READ_WRITE_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
|
||||||
|
#define MAX_SHARED_READ_ONLY_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_MISC_DATA_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
|
||||||
|
#define MAX_SHARED_MISC_DATA_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_CODE_SIZE)-SHARED_PAGE)
|
||||||
|
#define MAX_SHARED_MISC_CODE_SIZE (MAX_SHARED_DELTA-(MIN_SHARED_READ_WRITE_SIZE+MIN_SHARED_READ_ONLY_SIZE+MIN_SHARED_MISC_DATA_SIZE)-SHARED_PAGE)
|
||||||
|
|
||||||
#define LargeSharedArchiveSize (300*M)
|
#define LargeSharedArchiveSize (300*M)
|
||||||
#define HugeSharedArchiveSize (800*M)
|
#define HugeSharedArchiveSize (800*M)
|
||||||
#define ReadOnlyRegionPercentage 0.4
|
#define ReadOnlyRegionPercentage 0.4
|
||||||
|
@ -69,21 +110,10 @@ class MetaspaceShared : AllStatic {
|
||||||
static bool _archive_loading_failed;
|
static bool _archive_loading_failed;
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
vtbl_list_size = 17, // number of entries in the shared space vtable list.
|
vtbl_list_size = DEFAULT_VTBL_LIST_SIZE,
|
||||||
num_virtuals = 200, // maximum number of virtual functions
|
num_virtuals = DEFAULT_VTBL_VIRTUALS_COUNT,
|
||||||
// If virtual functions are added to Metadata,
|
vtbl_method_size = DEFAULT_VTBL_METHOD_SIZE,
|
||||||
// this number needs to be increased. Also,
|
vtbl_common_code_size = DEFAULT_VTBL_COMMON_CODE_SIZE
|
||||||
// SharedMiscCodeSize will need to be increased.
|
|
||||||
// The following 2 sizes were based on
|
|
||||||
// MetaspaceShared::generate_vtable_methods()
|
|
||||||
vtbl_method_size = 16, // conservative size of the mov1 and jmp instructions
|
|
||||||
// for the x64 platform
|
|
||||||
vtbl_common_code_size = (1*K) // conservative size of the "common_code" for the x64 platform
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
min_ro_size = NOT_LP64(8*M) LP64_ONLY(9*M), // minimum ro and rw regions sizes based on dumping
|
|
||||||
min_rw_size = NOT_LP64(7*M) LP64_ONLY(12*M) // of a shared archive using the default classlist
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -223,7 +223,7 @@ void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_doub
|
||||||
#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type
|
#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type
|
||||||
|
|
||||||
// the "name" argument must be a string literal
|
// the "name" argument must be a string literal
|
||||||
#define INITIAL_CONSTRAINTS_SIZE 45
|
#define INITIAL_CONSTRAINTS_SIZE 69
|
||||||
GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
|
GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
|
||||||
CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse;
|
CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse;
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,7 @@ void emit_range_double(const char* name, double min, double max) {
|
||||||
// Generate func argument to pass into emit_range_xxx functions
|
// Generate func argument to pass into emit_range_xxx functions
|
||||||
#define EMIT_RANGE_CHECK(a, b) , a, b
|
#define EMIT_RANGE_CHECK(a, b) , a, b
|
||||||
|
|
||||||
#define INITIAL_RANGES_SIZE 205
|
#define INITIAL_RANGES_SIZE 320
|
||||||
GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
|
GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
|
||||||
|
|
||||||
// Check the ranges of all flags that have them
|
// Check the ranges of all flags that have them
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
|
#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
|
||||||
#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
|
#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
|
||||||
|
|
||||||
|
#include "memory/metaspaceShared.hpp"
|
||||||
#include "runtime/globals.hpp"
|
#include "runtime/globals.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
|
|
||||||
|
|
|
@ -4110,21 +4110,26 @@ public:
|
||||||
"If PrintSharedArchiveAndExit is true, also print the shared " \
|
"If PrintSharedArchiveAndExit is true, also print the shared " \
|
||||||
"dictionary") \
|
"dictionary") \
|
||||||
\
|
\
|
||||||
product(size_t, SharedReadWriteSize, NOT_LP64(12*M) LP64_ONLY(16*M), \
|
product(size_t, SharedReadWriteSize, DEFAULT_SHARED_READ_WRITE_SIZE, \
|
||||||
"Size of read-write space for metadata (in bytes)") \
|
"Size of read-write space for metadata (in bytes)") \
|
||||||
|
range(MIN_SHARED_READ_WRITE_SIZE, MAX_SHARED_READ_WRITE_SIZE) \
|
||||||
\
|
\
|
||||||
product(size_t, SharedReadOnlySize, NOT_LP64(12*M) LP64_ONLY(16*M), \
|
product(size_t, SharedReadOnlySize, DEFAULT_SHARED_READ_ONLY_SIZE, \
|
||||||
"Size of read-only space for metadata (in bytes)") \
|
"Size of read-only space for metadata (in bytes)") \
|
||||||
|
range(MIN_SHARED_READ_ONLY_SIZE, MAX_SHARED_READ_ONLY_SIZE) \
|
||||||
\
|
\
|
||||||
product(uintx, SharedMiscDataSize, NOT_LP64(2*M) LP64_ONLY(4*M), \
|
product(size_t, SharedMiscDataSize, DEFAULT_SHARED_MISC_DATA_SIZE, \
|
||||||
"Size of the shared miscellaneous data area (in bytes)") \
|
"Size of the shared miscellaneous data area (in bytes)") \
|
||||||
|
range(MIN_SHARED_MISC_DATA_SIZE, MAX_SHARED_MISC_DATA_SIZE) \
|
||||||
\
|
\
|
||||||
product(uintx, SharedMiscCodeSize, 120*K, \
|
product(size_t, SharedMiscCodeSize, DEFAULT_SHARED_MISC_CODE_SIZE, \
|
||||||
"Size of the shared miscellaneous code area (in bytes)") \
|
"Size of the shared miscellaneous code area (in bytes)") \
|
||||||
|
range(MIN_SHARED_MISC_CODE_SIZE, MAX_SHARED_MISC_CODE_SIZE) \
|
||||||
\
|
\
|
||||||
product(uintx, SharedBaseAddress, LP64_ONLY(32*G) \
|
product(size_t, SharedBaseAddress, LP64_ONLY(32*G) \
|
||||||
NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \
|
NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \
|
||||||
"Address to allocate shared memory region for class data") \
|
"Address to allocate shared memory region for class data") \
|
||||||
|
range(0, SIZE_MAX) \
|
||||||
\
|
\
|
||||||
product(uintx, SharedSymbolTableBucketSize, 4, \
|
product(uintx, SharedSymbolTableBucketSize, 4, \
|
||||||
"Average number of symbols per bucket in shared table") \
|
"Average number of symbols per bucket in shared table") \
|
||||||
|
|
|
@ -58,6 +58,25 @@ public class TestOptionsWithRanges {
|
||||||
*/
|
*/
|
||||||
allOptionsAsMap.remove("ThreadStackSize");
|
allOptionsAsMap.remove("ThreadStackSize");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JDK-8141650
|
||||||
|
* Temporarily exclude SharedMiscDataSize as it will exit the VM with exit code 2 and
|
||||||
|
* "The shared miscellaneous data space is not large enough to preload requested classes."
|
||||||
|
* message at min value.
|
||||||
|
*/
|
||||||
|
allOptionsAsMap.remove("SharedMiscDataSize");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* JDK-8142874
|
||||||
|
* Temporarily exclude Shared* flagse as they will exit the VM with exit code 2 and
|
||||||
|
* "The shared miscellaneous data space is not large enough to preload requested classes."
|
||||||
|
* message at max values.
|
||||||
|
*/
|
||||||
|
allOptionsAsMap.remove("SharedReadWriteSize");
|
||||||
|
allOptionsAsMap.remove("SharedReadOnlySize");
|
||||||
|
allOptionsAsMap.remove("SharedMiscDataSize");
|
||||||
|
allOptionsAsMap.remove("SharedMiscCodeSize");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0)
|
* Exclude MallocMaxTestWords as it is expected to exit VM at small values (>=0)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -223,7 +223,7 @@ public class IntJVMOption extends JVMOption {
|
||||||
validValues.add("1");
|
validValues.add("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1) {
|
if ((min.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1)) {
|
||||||
/*
|
/*
|
||||||
* Check for overflow when flag is assigned to the
|
* Check for overflow when flag is assigned to the
|
||||||
* 4 byte int variable
|
* 4 byte int variable
|
||||||
|
@ -231,7 +231,7 @@ public class IntJVMOption extends JVMOption {
|
||||||
validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString());
|
validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1) {
|
if ((min.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == -1) && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1)) {
|
||||||
/*
|
/*
|
||||||
* Check for overflow when flag is assigned to the
|
* Check for overflow when flag is assigned to the
|
||||||
* 4 byte unsigned int variable
|
* 4 byte unsigned int variable
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -49,6 +50,8 @@ public class JVMOptionsUtils {
|
||||||
/* Used to start the JVM with the same type as current */
|
/* Used to start the JVM with the same type as current */
|
||||||
static String VMType;
|
static String VMType;
|
||||||
|
|
||||||
|
private static Map<String, JVMOption> optionsAsMap;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
if (Platform.isServer()) {
|
if (Platform.isServer()) {
|
||||||
VMType = "-server";
|
VMType = "-server";
|
||||||
|
@ -63,6 +66,84 @@ public class JVMOptionsUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean fitsRange(String optionName, BigDecimal number) throws Exception {
|
||||||
|
JVMOption option;
|
||||||
|
String minRangeString = null;
|
||||||
|
String maxRangeString = null;
|
||||||
|
boolean fits = true;
|
||||||
|
|
||||||
|
if (optionsAsMap == null) {
|
||||||
|
optionsAsMap = getOptionsWithRangeAsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
option = optionsAsMap.get(optionName);
|
||||||
|
if (option != null) {
|
||||||
|
minRangeString = option.getMin();
|
||||||
|
if (minRangeString != null) {
|
||||||
|
fits = (number.compareTo(new BigDecimal(minRangeString)) >= 0);
|
||||||
|
}
|
||||||
|
maxRangeString = option.getMax();
|
||||||
|
if (maxRangeString != null) {
|
||||||
|
fits &= (number.compareTo(new BigDecimal(maxRangeString)) <= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean fitsRange(String optionName, String number) throws Exception {
|
||||||
|
String lowerCase = number.toLowerCase();
|
||||||
|
String multiplier = "1";
|
||||||
|
if (lowerCase.endsWith("k")) {
|
||||||
|
multiplier = "1024";
|
||||||
|
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
|
||||||
|
} else if (lowerCase.endsWith("m")) {
|
||||||
|
multiplier = "1048576"; //1024*1024
|
||||||
|
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
|
||||||
|
} else if (lowerCase.endsWith("g")) {
|
||||||
|
multiplier = "1073741824"; //1024*1024*1024
|
||||||
|
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
|
||||||
|
} else if (lowerCase.endsWith("t")) {
|
||||||
|
multiplier = "1099511627776"; //1024*1024*1024*1024
|
||||||
|
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
|
||||||
|
}
|
||||||
|
BigDecimal valueBig = new BigDecimal(lowerCase);
|
||||||
|
BigDecimal multiplierBig = new BigDecimal(multiplier);
|
||||||
|
return fitsRange(optionName, valueBig.multiply(multiplierBig));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMinOptionRange(String optionName) throws Exception {
|
||||||
|
JVMOption option;
|
||||||
|
String minRange = null;
|
||||||
|
|
||||||
|
if (optionsAsMap == null) {
|
||||||
|
optionsAsMap = getOptionsWithRangeAsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
option = optionsAsMap.get(optionName);
|
||||||
|
if (option != null) {
|
||||||
|
minRange = option.getMin();
|
||||||
|
}
|
||||||
|
|
||||||
|
return minRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getMaxOptionRange(String optionName) throws Exception {
|
||||||
|
JVMOption option;
|
||||||
|
String maxRange = null;
|
||||||
|
|
||||||
|
if (optionsAsMap == null) {
|
||||||
|
optionsAsMap = getOptionsWithRangeAsMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
option = optionsAsMap.get(optionName);
|
||||||
|
if (option != null) {
|
||||||
|
maxRange = option.getMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxRange;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add dependency for option depending on it's name. E.g. enable G1 GC for
|
* Add dependency for option depending on it's name. E.g. enable G1 GC for
|
||||||
* G1 options or add prepend options to not hit constraints.
|
* G1 options or add prepend options to not hit constraints.
|
||||||
|
@ -80,6 +161,13 @@ public class JVMOptionsUtils {
|
||||||
option.addPrepend("-XX:+UseConcMarkSweepGC");
|
option.addPrepend("-XX:+UseConcMarkSweepGC");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name.startsWith("Shared")) {
|
||||||
|
option.addPrepend("-XX:+UnlockDiagnosticVMOptions");
|
||||||
|
String fileName = "Test" + name + ".jsa";
|
||||||
|
option.addPrepend("-XX:SharedArchiveFile=" + fileName);
|
||||||
|
option.addPrepend("-Xshare:dump");
|
||||||
|
}
|
||||||
|
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "MinHeapFreeRatio":
|
case "MinHeapFreeRatio":
|
||||||
option.addPrepend("-XX:MaxHeapFreeRatio=100");
|
option.addPrepend("-XX:MaxHeapFreeRatio=100");
|
||||||
|
@ -112,7 +200,6 @@ public class JVMOptionsUtils {
|
||||||
/* Do nothing */
|
/* Do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,50 +23,72 @@
|
||||||
|
|
||||||
/* @test LimitSharedSizes
|
/* @test LimitSharedSizes
|
||||||
* @summary Test handling of limits on shared space size
|
* @summary Test handling of limits on shared space size
|
||||||
* @library /testlibrary
|
* @library /testlibrary /runtime/CommandLine/OptionsValidation/common
|
||||||
* @modules java.base/sun.misc
|
* @modules java.base/sun.misc
|
||||||
* java.management
|
* java.management
|
||||||
* @run main LimitSharedSizes
|
* @run main LimitSharedSizes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import jdk.test.lib.*;
|
import jdk.test.lib.*;
|
||||||
|
import optionsvalidation.JVMOptionsUtils;
|
||||||
|
|
||||||
public class LimitSharedSizes {
|
public class LimitSharedSizes {
|
||||||
|
static enum Result {
|
||||||
|
OUT_OF_RANGE,
|
||||||
|
TOO_SMALL,
|
||||||
|
VALID,
|
||||||
|
VALID_ARCHIVE
|
||||||
|
}
|
||||||
|
|
||||||
static enum Region {
|
static enum Region {
|
||||||
RO, RW, MD, MC
|
RO, RW, MD, MC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final boolean fitsRange(String name, String value) throws RuntimeException {
|
||||||
|
boolean fits = true;
|
||||||
|
try {
|
||||||
|
fits = JVMOptionsUtils.fitsRange(name, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
return fits;
|
||||||
|
}
|
||||||
|
|
||||||
private static class SharedSizeTestData {
|
private static class SharedSizeTestData {
|
||||||
public String optionName;
|
public String optionName;
|
||||||
public String optionValue;
|
public String optionValue;
|
||||||
public String expectedErrorMsg;
|
public Result optionResult;
|
||||||
|
|
||||||
public SharedSizeTestData(Region region, String value, String msg) {
|
public SharedSizeTestData(Region region, String value) {
|
||||||
optionName = getName(region);
|
optionName = "-XX:"+getName(region);
|
||||||
optionValue = value;
|
optionValue = value;
|
||||||
expectedErrorMsg = msg;
|
if (fitsRange(getName(region), value) == false) {
|
||||||
|
optionResult = Result.OUT_OF_RANGE;
|
||||||
|
} else {
|
||||||
|
optionResult = Result.TOO_SMALL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharedSizeTestData(Region region, String msg) {
|
public SharedSizeTestData(Region region, String value, Result result) {
|
||||||
optionName = getName(region);
|
optionName = "-XX:"+getName(region);
|
||||||
optionValue = getValue(region);
|
optionValue = value;
|
||||||
expectedErrorMsg = msg;
|
optionResult = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getName(Region region) {
|
private String getName(Region region) {
|
||||||
String name;
|
String name;
|
||||||
switch (region) {
|
switch (region) {
|
||||||
case RO:
|
case RO:
|
||||||
name = "-XX:SharedReadOnlySize";
|
name = "SharedReadOnlySize";
|
||||||
break;
|
break;
|
||||||
case RW:
|
case RW:
|
||||||
name = "-XX:SharedReadWriteSize";
|
name = "SharedReadWriteSize";
|
||||||
break;
|
break;
|
||||||
case MD:
|
case MD:
|
||||||
name = "-XX:SharedMiscDataSize";
|
name = "SharedMiscDataSize";
|
||||||
break;
|
break;
|
||||||
case MC:
|
case MC:
|
||||||
name = "-XX:SharedMiscCodeSize";
|
name = "SharedMiscCodeSize";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
name = "Unknown";
|
name = "Unknown";
|
||||||
|
@ -75,53 +97,37 @@ public class LimitSharedSizes {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getValue(Region region) {
|
public Result getResult() {
|
||||||
String value;
|
return optionResult;
|
||||||
switch (region) {
|
|
||||||
case RO:
|
|
||||||
value = Platform.is64bit() ? "9M" : "8M";
|
|
||||||
break;
|
|
||||||
case RW:
|
|
||||||
value = Platform.is64bit() ? "12M" : "7M";
|
|
||||||
break;
|
|
||||||
case MD:
|
|
||||||
value = Platform.is64bit() ? "4M" : "2M";
|
|
||||||
break;
|
|
||||||
case MC:
|
|
||||||
value = "120k";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
value = "0M";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final SharedSizeTestData[] testTable = {
|
private static final SharedSizeTestData[] testTable = {
|
||||||
// Too small of a region size should not cause a vm crash.
|
// Too small of a region size should not cause a vm crash.
|
||||||
// It should result in an error message like the following:
|
// It should result in an error message either like the following #1:
|
||||||
// The shared miscellaneous code space is not large enough
|
// The shared miscellaneous code space is not large enough
|
||||||
// to preload requested classes. Use -XX:SharedMiscCodeSize=
|
// to preload requested classes. Use -XX:SharedMiscCodeSize=
|
||||||
// to increase the initial size of shared miscellaneous code space.
|
// to increase the initial size of shared miscellaneous code space.
|
||||||
new SharedSizeTestData(Region.RO, "4M", "read only"),
|
// or #2:
|
||||||
new SharedSizeTestData(Region.RW, "4M", "read write"),
|
// The shared miscellaneous code space is outside the allowed range
|
||||||
new SharedSizeTestData(Region.MD, "50k", "miscellaneous data"),
|
new SharedSizeTestData(Region.RO, "4M"),
|
||||||
new SharedSizeTestData(Region.MC, "20k", "miscellaneous code"),
|
new SharedSizeTestData(Region.RW, "4M"),
|
||||||
|
new SharedSizeTestData(Region.MD, "50k"),
|
||||||
|
new SharedSizeTestData(Region.MC, "20k"),
|
||||||
|
|
||||||
// these values are larger than default ones, but should
|
// these values are larger than default ones, and should
|
||||||
// be acceptable and not cause failure
|
// be acceptable and not cause failure
|
||||||
new SharedSizeTestData(Region.RO, "20M", null),
|
new SharedSizeTestData(Region.RO, "20M", Result.VALID),
|
||||||
new SharedSizeTestData(Region.RW, "20M", null),
|
new SharedSizeTestData(Region.RW, "20M", Result.VALID),
|
||||||
new SharedSizeTestData(Region.MD, "20M", null),
|
new SharedSizeTestData(Region.MD, "20M", Result.VALID),
|
||||||
new SharedSizeTestData(Region.MC, "20M", null),
|
new SharedSizeTestData(Region.MC, "20M", Result.VALID),
|
||||||
|
|
||||||
// test with sizes which just meet the minimum required sizes
|
// test with sizes which just meet the minimum required sizes
|
||||||
// the following tests also attempt to use the shared archive
|
// the following tests also attempt to use the shared archive
|
||||||
new SharedSizeTestData(Region.RO, "UseArchive"),
|
new SharedSizeTestData(Region.RO, Platform.is64bit() ? "9M":"8M", Result.VALID_ARCHIVE),
|
||||||
new SharedSizeTestData(Region.RW, "UseArchive"),
|
new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
|
||||||
new SharedSizeTestData(Region.MD, "UseArchive"),
|
new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
|
||||||
new SharedSizeTestData(Region.MC, "UseArchive")
|
new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
@ -131,6 +137,7 @@ public class LimitSharedSizes {
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
String option = td.optionName + "=" + td.optionValue;
|
String option = td.optionName + "=" + td.optionValue;
|
||||||
|
System.out.println("testing option number <" + counter + ">");
|
||||||
System.out.println("testing option <" + option + ">");
|
System.out.println("testing option <" + option + ">");
|
||||||
|
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||||
|
@ -141,16 +148,14 @@ public class LimitSharedSizes {
|
||||||
|
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
|
|
||||||
if (td.expectedErrorMsg != null) {
|
switch (td.getResult()) {
|
||||||
if (!td.expectedErrorMsg.equals("UseArchive")) {
|
case VALID:
|
||||||
output.shouldContain("The shared " + td.expectedErrorMsg
|
case VALID_ARCHIVE:
|
||||||
+ " space is not large enough");
|
{
|
||||||
|
|
||||||
output.shouldHaveExitValue(2);
|
|
||||||
} else {
|
|
||||||
output.shouldNotContain("space is not large enough");
|
output.shouldNotContain("space is not large enough");
|
||||||
output.shouldHaveExitValue(0);
|
output.shouldHaveExitValue(0);
|
||||||
|
|
||||||
|
if (td.getResult() == Result.VALID_ARCHIVE) {
|
||||||
// try to use the archive
|
// try to use the archive
|
||||||
pb = ProcessTools.createJavaProcessBuilder(
|
pb = ProcessTools.createJavaProcessBuilder(
|
||||||
"-XX:+UnlockDiagnosticVMOptions",
|
"-XX:+UnlockDiagnosticVMOptions",
|
||||||
|
@ -175,9 +180,20 @@ public class LimitSharedSizes {
|
||||||
}
|
}
|
||||||
output.shouldHaveExitValue(0);
|
output.shouldHaveExitValue(0);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
output.shouldNotContain("space is not large enough");
|
break;
|
||||||
output.shouldHaveExitValue(0);
|
case TOO_SMALL:
|
||||||
|
{
|
||||||
|
output.shouldContain("space is not large enough");
|
||||||
|
output.shouldHaveExitValue(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OUT_OF_RANGE:
|
||||||
|
{
|
||||||
|
output.shouldContain("outside the allowed range");
|
||||||
|
output.shouldHaveExitValue(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
29
hotspot/test/runtime/ThreadSignalMask/Prog.java
Normal file
29
hotspot/test/runtime/ThreadSignalMask/Prog.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Prog {
|
||||||
|
|
||||||
|
public static void main(String args[]) {
|
||||||
|
System.out.println("Java class invoked: " + args[0]);
|
||||||
|
}
|
||||||
|
}
|
118
hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java
Normal file
118
hotspot/test/runtime/ThreadSignalMask/ThreadSignalMask.java
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, 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.lang.ProcessBuilder.Redirect;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @key cte_test
|
||||||
|
* @bug 4345157
|
||||||
|
* @summary JDK 1.3.0 alters thread signal mask
|
||||||
|
* @requires (os.simpleArch == "sparcv9")
|
||||||
|
* @library /testlibrary
|
||||||
|
* @compile Prog.java
|
||||||
|
* @run main/native ThreadSignalMask
|
||||||
|
*/
|
||||||
|
public class ThreadSignalMask {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
|
||||||
|
String testClasses = getSystemProperty("test.classes");
|
||||||
|
|
||||||
|
String testNativePath = getSystemProperty("test.nativepath");
|
||||||
|
|
||||||
|
String testJdk = getSystemProperty("test.jdk");
|
||||||
|
|
||||||
|
Path currentDirPath = Paths.get(".");
|
||||||
|
|
||||||
|
Path classFilePath = Paths.get(testClasses,
|
||||||
|
Prog.class.getSimpleName() + ".class");
|
||||||
|
|
||||||
|
// copy Prog.class file to be invoked from native
|
||||||
|
Files.copy(classFilePath,
|
||||||
|
currentDirPath.resolve(Prog.class.getSimpleName() + ".class"),
|
||||||
|
StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
|
Path executableFilePath = Paths.get(testNativePath,
|
||||||
|
ThreadSignalMask.class.getSimpleName());
|
||||||
|
|
||||||
|
Path executableFileLocalPath = currentDirPath.resolve(
|
||||||
|
ThreadSignalMask.class.getSimpleName());
|
||||||
|
|
||||||
|
// copy compiled native executable ThreadSignalMask
|
||||||
|
Files.copy(executableFilePath,
|
||||||
|
executableFileLocalPath,
|
||||||
|
StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
|
||||||
|
executableFileLocalPath.toFile().setExecutable(true);
|
||||||
|
|
||||||
|
long[] intervalsArray = {2000, 5000, 10000, 20000};
|
||||||
|
|
||||||
|
List<String> processArgs = Arrays.asList(
|
||||||
|
executableFileLocalPath.toString(),
|
||||||
|
testJdk);
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(processArgs);
|
||||||
|
pb.redirectOutput(Redirect.INHERIT);
|
||||||
|
pb.redirectError(Redirect.INHERIT);
|
||||||
|
int result = 0;
|
||||||
|
for (long interval : intervalsArray) {
|
||||||
|
Process p = pb.start();
|
||||||
|
|
||||||
|
// sleep for a specified period of time to let native run
|
||||||
|
sleep(interval);
|
||||||
|
p.destroy();
|
||||||
|
|
||||||
|
// wait for process to finish, get exit value and validate it
|
||||||
|
result = p.waitFor();
|
||||||
|
System.out.println("Result = " + result);
|
||||||
|
if (result == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Asserts.assertEquals(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility method to handle Thread.sleep
|
||||||
|
private static void sleep(long millis) throws InterruptedException {
|
||||||
|
System.out.println("Sleep for " + millis);
|
||||||
|
Thread.sleep(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility method to retrieve and validate system properties
|
||||||
|
private static String getSystemProperty(String propertyName) throws Error {
|
||||||
|
String systemProperty = System.getProperty(propertyName, "").trim();
|
||||||
|
System.out.println(propertyName + " = " + systemProperty);
|
||||||
|
if (systemProperty.isEmpty()) {
|
||||||
|
throw new Error("TESTBUG: property " + propertyName + " is empty");
|
||||||
|
}
|
||||||
|
return systemProperty;
|
||||||
|
}
|
||||||
|
}
|
253
hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
Normal file
253
hotspot/test/runtime/ThreadSignalMask/exeThreadSignalMask.c
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _POSIX_PTHREAD_SEMANTICS // to enable POSIX semantics for certain common APIs
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void *handle;
|
||||||
|
char *error;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
jint(JNICALL *jni_create_java_vm)(JavaVM **, JNIEnv **, void *) = NULL;
|
||||||
|
|
||||||
|
JavaVM *jvm;
|
||||||
|
|
||||||
|
// method to perform dlclose on an open dynamic library handle
|
||||||
|
void closeHandle() {
|
||||||
|
dlclose(handle);
|
||||||
|
if ((error = dlerror()) != NULL) {
|
||||||
|
fputs("Error occurred while closing handle\n", stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// method to exit with a fail status
|
||||||
|
void fail() {
|
||||||
|
if (handle) {
|
||||||
|
closeHandle();
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method to handle occurred error and fail
|
||||||
|
void handleError(char *messageTitle, char *messageBody) {
|
||||||
|
fprintf(stderr, "%s: %s\n", messageTitle, messageBody);
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// method to load the dynamic library libjvm
|
||||||
|
void loadJVM() {
|
||||||
|
char lib[PATH_MAX];
|
||||||
|
snprintf(lib, sizeof (lib), "%s/lib/sparcv9/server/libjvm.so", path);
|
||||||
|
handle = dlopen(lib, RTLD_LAZY);
|
||||||
|
if (!handle) {
|
||||||
|
handleError(dlerror(), "2");
|
||||||
|
}
|
||||||
|
fputs("Will load JVM...\n", stdout);
|
||||||
|
|
||||||
|
// find the address of function
|
||||||
|
*(void **) (&jni_create_java_vm) = dlsym(handle, "JNI_CreateJavaVM");
|
||||||
|
if ((error = dlerror()) != NULL) {
|
||||||
|
handleError(error, "3");
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("JVM loaded okay.\n", stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// method to get created jvm environment
|
||||||
|
JNIEnv* initJVM() {
|
||||||
|
JNIEnv *env = NULL;
|
||||||
|
JavaVMInitArgs vm_args;
|
||||||
|
JavaVMOption options[1];
|
||||||
|
jint res;
|
||||||
|
|
||||||
|
options[0].optionString = "-Xrs";
|
||||||
|
|
||||||
|
vm_args.version = JNI_VERSION_1_2;
|
||||||
|
vm_args.nOptions = 1;
|
||||||
|
vm_args.options = options;
|
||||||
|
vm_args.ignoreUnrecognized = JNI_FALSE;
|
||||||
|
|
||||||
|
fputs("Will create JVM...\n", stdout);
|
||||||
|
|
||||||
|
res = (*jni_create_java_vm)(&jvm, &env, &vm_args);
|
||||||
|
if (res < 0) {
|
||||||
|
handleError("Can't create Java VM", strerror(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
fputs("JVM created OK!\n", stdout);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
// method to invoke java method from java class
|
||||||
|
void callJava(JNIEnv *env) {
|
||||||
|
jclass cls;
|
||||||
|
jmethodID mid;
|
||||||
|
jstring jstr;
|
||||||
|
jobjectArray args;
|
||||||
|
|
||||||
|
cls = (*env)->FindClass(env, "Prog");
|
||||||
|
if (cls == 0) {
|
||||||
|
handleError("FindClass", "Can't find Prog class");
|
||||||
|
}
|
||||||
|
|
||||||
|
mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
|
||||||
|
if (mid == 0) {
|
||||||
|
handleError("GetStaticMethodID", "Can't find Prog.main");
|
||||||
|
}
|
||||||
|
|
||||||
|
jstr = (*env)->NewStringUTF(env, "from C!");
|
||||||
|
if (jstr == 0) {
|
||||||
|
handleError("NewStringUTF", "Out of memory");
|
||||||
|
}
|
||||||
|
args = (*env)->NewObjectArray(env, 1,
|
||||||
|
(*env)->FindClass(env, "java/lang/String"), jstr);
|
||||||
|
if (args == 0) {
|
||||||
|
handleError("NewObjectArray", "Out of memory");
|
||||||
|
}
|
||||||
|
(*env)->CallStaticVoidMethod(env, cls, mid, args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// method to load, init jvm and then invoke java method
|
||||||
|
void* loadAndCallJava(void* x) {
|
||||||
|
JNIEnv *env;
|
||||||
|
|
||||||
|
fputs("Some thread will create JVM.\n", stdout);
|
||||||
|
loadJVM();
|
||||||
|
env = initJVM();
|
||||||
|
|
||||||
|
fputs("Some thread will call Java.\n", stdout);
|
||||||
|
|
||||||
|
callJava(env);
|
||||||
|
|
||||||
|
if ((*jvm)->DetachCurrentThread(jvm) != 0)
|
||||||
|
fputs("Error: thread not detached!\n", stderr);
|
||||||
|
fputs("Some thread exiting.\n", stdout);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
JNIEnv *env;
|
||||||
|
sigset_t set;
|
||||||
|
pthread_t thr1;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
size_t ss = 0;
|
||||||
|
int sig;
|
||||||
|
int rc; // return code for pthread_* methods
|
||||||
|
|
||||||
|
// verify input
|
||||||
|
if (argc != 2) {
|
||||||
|
handleError("usage", "a.out jdk_path");
|
||||||
|
}
|
||||||
|
// copy input jdk path into a char buffer
|
||||||
|
strncpy(path, argv[1], PATH_MAX);
|
||||||
|
// add null termination character
|
||||||
|
path[PATH_MAX - 1] = '\0';
|
||||||
|
|
||||||
|
fputs("Main thread will set signal mask.\n", stdout);
|
||||||
|
|
||||||
|
// initialize the signal set
|
||||||
|
sigemptyset(&set);
|
||||||
|
// add a number of signals to a signal set
|
||||||
|
sigaddset(&set, SIGPIPE);
|
||||||
|
sigaddset(&set, SIGTERM);
|
||||||
|
sigaddset(&set, SIGHUP);
|
||||||
|
sigaddset(&set, SIGINT);
|
||||||
|
|
||||||
|
// examine and change mask of blocked signal
|
||||||
|
if ((rc = pthread_sigmask(SIG_BLOCK, &set, NULL))) {
|
||||||
|
// handle error if occurred
|
||||||
|
handleError("main: pthread_sigmask() error", strerror(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializes the thread attributes object with default attribute values
|
||||||
|
if ((rc = pthread_attr_init(&attr))) {
|
||||||
|
// handle error if occurred
|
||||||
|
handleError("main: pthread_attr_init() error", strerror(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
ss = 1024 * 1024;
|
||||||
|
// set the stack size attribute of the thread attributes object
|
||||||
|
if ((rc = pthread_attr_setstacksize(&attr, ss))) {
|
||||||
|
// handle error if occurred
|
||||||
|
handleError("main: pthread_attr_setstacksize() error", strerror(rc));
|
||||||
|
}
|
||||||
|
// get the stack size attribute of the thread attributes object
|
||||||
|
if ((rc = pthread_attr_getstacksize(&attr, &ss))) {
|
||||||
|
// handle error if occurred
|
||||||
|
handleError("main: pthread_attr_getstacksize() error", strerror(rc));
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Stack size: %zu\n", ss);
|
||||||
|
|
||||||
|
// start a new thread in the calling process,
|
||||||
|
// loadAndCallJava logic is passed as a start_routine argument
|
||||||
|
if ((rc = pthread_create(&thr1, NULL, loadAndCallJava, NULL))) {
|
||||||
|
// handle error if occurred
|
||||||
|
handleError("main: pthread_create() error", strerror(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize the signal set
|
||||||
|
sigemptyset(&set);
|
||||||
|
// add a number of signals to a signal set
|
||||||
|
sigaddset(&set, SIGTERM);
|
||||||
|
sigaddset(&set, SIGHUP);
|
||||||
|
sigaddset(&set, SIGINT);
|
||||||
|
|
||||||
|
fputs("Main thread waiting for signal.\n", stdout);
|
||||||
|
|
||||||
|
do {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
sig = 0;
|
||||||
|
err = sigwait(&set, &sig);
|
||||||
|
if (err != 0) {
|
||||||
|
// print error message if unexpected signal occurred
|
||||||
|
fprintf(stderr, "main: sigwait() error: %s\n", strerror(err));
|
||||||
|
} else {
|
||||||
|
// print success message and exit if expected signal occurred
|
||||||
|
// this branch generally acts when JVM executes destroy()
|
||||||
|
fprintf(stdout, "main: sigwait() got: %d\nSucceed!\n", sig);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
} while (sig != SIGTERM && sig != SIGINT); // exit the loop condition
|
||||||
|
|
||||||
|
// join with a terminated thread
|
||||||
|
if ((rc = pthread_join(thr1, NULL))) {
|
||||||
|
// handle error if occurred
|
||||||
|
handleError("main: pthread_join() error", strerror(rc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// close an open dynamic library handle
|
||||||
|
closeHandle();
|
||||||
|
fputs("Main thread exiting.\n", stdout);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue