Merge
This commit is contained in:
commit
6b5de282db
.hgtags-top-repo
corba
hotspot
.hgtags
make
src
cpu
os
share/vm
adlc
asm
classfile
gc_implementation
g1
collectionSetChooser.hppconcurrentG1Refine.hppconcurrentMark.hppg1CollectedHeap.cppg1CollectedHeap.hppg1CollectorPolicy.cppg1CollectorPolicy.hppg1MMUTracker.hppg1RemSet.cppg1RemSet.hppg1_globals.hppheapRegion.hppheapRegionRemSet.cppheapRegionRemSet.hppptrQueue.hppsparsePRT.hppsurvRateGroup.cppsurvRateGroup.hpp
includeDB_gc_g1parallelScavenge
shared
gc_interface
interpreter
libadt
memory
oops
opto
block.cppc2_globals.hppcfgnode.cppchaitin.cppchaitin.hppclasses.hppcompile.cppdivnode.cppgcm.cppgraphKit.cppgraphKit.hppifg.cpplcm.cpplive.cpploopnode.cppmacro.cppmatcher.cppmemnode.cppmemnode.hppmulnode.cppsuperword.cpptype.cpptype.hppvectornode.cpp
runtime
utilities
test
jdk
@ -22,3 +22,4 @@ a395e3aac4744cc9033fcd819fad1239a45add52 jdk7-b44
|
|||||||
99846f001ca214015578d593802d26e27246a802 jdk7-b45
|
99846f001ca214015578d593802d26e27246a802 jdk7-b45
|
||||||
e8a2a4d187773a62f3309b0fa265c13425bc2258 jdk7-b46
|
e8a2a4d187773a62f3309b0fa265c13425bc2258 jdk7-b46
|
||||||
d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47
|
d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47
|
||||||
|
4ae9f4bfdb98f65bd957e3fe72471b320150b38e jdk7-b48
|
||||||
|
@ -22,3 +22,4 @@ ccd6a16502e0650d91d85c4b86be05cbcd461a87 jdk7-b42
|
|||||||
68814aa5b44b1f16931a97e7cd4028c70eb9586b jdk7-b45
|
68814aa5b44b1f16931a97e7cd4028c70eb9586b jdk7-b45
|
||||||
1691dbfc08f8ee3f4e23a1ff30cdff920718696c jdk7-b46
|
1691dbfc08f8ee3f4e23a1ff30cdff920718696c jdk7-b46
|
||||||
167ad0164301f318b069a947e1c9c07ed667748a jdk7-b47
|
167ad0164301f318b069a947e1c9c07ed667748a jdk7-b47
|
||||||
|
0be222241fd405e48915647facfaa176621b39b9 jdk7-b48
|
||||||
|
@ -22,3 +22,4 @@ fc6a5ae3fef5ebacfa896dbb3ae37715e388e282 jdk7-b43
|
|||||||
945bf754069766e76873c53102fae48abf04cf5b jdk7-b45
|
945bf754069766e76873c53102fae48abf04cf5b jdk7-b45
|
||||||
16bb38eeda35b46268eefa4c1f829eb086e0ca46 jdk7-b46
|
16bb38eeda35b46268eefa4c1f829eb086e0ca46 jdk7-b46
|
||||||
fcb923bad68e2b10380a030ea83a723f4dc3d4d6 jdk7-b47
|
fcb923bad68e2b10380a030ea83a723f4dc3d4d6 jdk7-b47
|
||||||
|
bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48
|
||||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2008
|
|||||||
|
|
||||||
HS_MAJOR_VER=15
|
HS_MAJOR_VER=15
|
||||||
HS_MINOR_VER=0
|
HS_MINOR_VER=0
|
||||||
HS_BUILD_NUMBER=01
|
HS_BUILD_NUMBER=02
|
||||||
|
|
||||||
JDK_MAJOR_VER=1
|
JDK_MAJOR_VER=1
|
||||||
JDK_MINOR_VER=7
|
JDK_MINOR_VER=7
|
||||||
|
@ -762,7 +762,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
|
|||||||
case Assembler::stdf_op3: st_op = Op_StoreD; break;
|
case Assembler::stdf_op3: st_op = Op_StoreD; break;
|
||||||
|
|
||||||
case Assembler::ldsb_op3: ld_op = Op_LoadB; break;
|
case Assembler::ldsb_op3: ld_op = Op_LoadB; break;
|
||||||
case Assembler::lduh_op3: ld_op = Op_LoadC; break;
|
case Assembler::lduh_op3: ld_op = Op_LoadUS; break;
|
||||||
case Assembler::ldsh_op3: ld_op = Op_LoadS; break;
|
case Assembler::ldsh_op3: ld_op = Op_LoadS; break;
|
||||||
case Assembler::ldx_op3: // may become LoadP or stay LoadI
|
case Assembler::ldx_op3: // may become LoadP or stay LoadI
|
||||||
case Assembler::ldsw_op3: // may become LoadP or stay LoadI
|
case Assembler::ldsw_op3: // may become LoadP or stay LoadI
|
||||||
@ -3869,6 +3869,8 @@ operand regD() %{
|
|||||||
constraint(ALLOC_IN_RC(dflt_reg));
|
constraint(ALLOC_IN_RC(dflt_reg));
|
||||||
match(RegD);
|
match(RegD);
|
||||||
|
|
||||||
|
match(regD_low);
|
||||||
|
|
||||||
format %{ %}
|
format %{ %}
|
||||||
interface(REG_INTER);
|
interface(REG_INTER);
|
||||||
%}
|
%}
|
||||||
@ -3883,7 +3885,7 @@ operand regF() %{
|
|||||||
|
|
||||||
operand regD_low() %{
|
operand regD_low() %{
|
||||||
constraint(ALLOC_IN_RC(dflt_low_reg));
|
constraint(ALLOC_IN_RC(dflt_low_reg));
|
||||||
match(RegD);
|
match(regD);
|
||||||
|
|
||||||
format %{ %}
|
format %{ %}
|
||||||
interface(REG_INTER);
|
interface(REG_INTER);
|
||||||
@ -5314,9 +5316,9 @@ instruct loadUBL(iRegL dst, memory mem, immL_FF bytemask) %{
|
|||||||
ins_pipe(iload_mask_mem);
|
ins_pipe(iload_mask_mem);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Load Char (16bit UNsigned) into a Long Register
|
// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
|
||||||
instruct loadUCL(iRegL dst, memory mem, immL_FFFF bytemask) %{
|
instruct loadUS2L(iRegL dst, memory mem, immL_FFFF bytemask) %{
|
||||||
match(Set dst (AndL (ConvI2L (LoadC mem)) bytemask));
|
match(Set dst (AndL (ConvI2L (LoadUS mem)) bytemask));
|
||||||
ins_cost(MEMORY_REF_COST);
|
ins_cost(MEMORY_REF_COST);
|
||||||
|
|
||||||
size(4);
|
size(4);
|
||||||
@ -5326,9 +5328,9 @@ instruct loadUCL(iRegL dst, memory mem, immL_FFFF bytemask) %{
|
|||||||
ins_pipe(iload_mask_mem);
|
ins_pipe(iload_mask_mem);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Load Char (16bit unsigned)
|
// Load Unsigned Short/Char (16bit unsigned)
|
||||||
instruct loadC(iRegI dst, memory mem) %{
|
instruct loadUS(iRegI dst, memory mem) %{
|
||||||
match(Set dst (LoadC mem));
|
match(Set dst (LoadUS mem));
|
||||||
ins_cost(MEMORY_REF_COST);
|
ins_cost(MEMORY_REF_COST);
|
||||||
|
|
||||||
size(4);
|
size(4);
|
||||||
|
@ -6413,9 +6413,9 @@ instruct loadUB(xRegI dst, memory mem, immI_255 bytemask) %{
|
|||||||
ins_pipe( ialu_reg_mem );
|
ins_pipe( ialu_reg_mem );
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Load Char (16bit unsigned)
|
// Load Unsigned Short/Char (16bit unsigned)
|
||||||
instruct loadC(eRegI dst, memory mem) %{
|
instruct loadUS(eRegI dst, memory mem) %{
|
||||||
match(Set dst (LoadC mem));
|
match(Set dst (LoadUS mem));
|
||||||
|
|
||||||
ins_cost(125);
|
ins_cost(125);
|
||||||
format %{ "MOVZX $dst,$mem" %}
|
format %{ "MOVZX $dst,$mem" %}
|
||||||
|
@ -6096,25 +6096,25 @@ instruct loadS(rRegI dst, memory mem)
|
|||||||
// ins_pipe(ialu_reg_mem);
|
// ins_pipe(ialu_reg_mem);
|
||||||
// %}
|
// %}
|
||||||
|
|
||||||
// Load Char (16 bit UNsigned)
|
// Load Unsigned Short/Char (16 bit UNsigned)
|
||||||
instruct loadC(rRegI dst, memory mem)
|
instruct loadUS(rRegI dst, memory mem)
|
||||||
%{
|
%{
|
||||||
match(Set dst (LoadC mem));
|
match(Set dst (LoadUS mem));
|
||||||
|
|
||||||
ins_cost(125);
|
ins_cost(125);
|
||||||
format %{ "movzwl $dst, $mem\t# char" %}
|
format %{ "movzwl $dst, $mem\t# ushort/char" %}
|
||||||
opcode(0x0F, 0xB7);
|
opcode(0x0F, 0xB7);
|
||||||
ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
|
ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
|
||||||
ins_pipe(ialu_reg_mem);
|
ins_pipe(ialu_reg_mem);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Load Char (16 bit UNsigned) into long
|
// Load Unsigned Short/Char (16 bit UNsigned) into long
|
||||||
// instruct loadC2L(rRegL dst, memory mem)
|
// instruct loadUS2L(rRegL dst, memory mem)
|
||||||
// %{
|
// %{
|
||||||
// match(Set dst (ConvI2L (LoadC mem)));
|
// match(Set dst (ConvI2L (LoadUS mem)));
|
||||||
|
|
||||||
// ins_cost(125);
|
// ins_cost(125);
|
||||||
// format %{ "movzwl $dst, $mem\t# char -> long" %}
|
// format %{ "movzwl $dst, $mem\t# ushort/char -> long" %}
|
||||||
// opcode(0x0F, 0xB7);
|
// opcode(0x0F, 0xB7);
|
||||||
// ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
|
// ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
|
||||||
// ins_pipe(ialu_reg_mem);
|
// ins_pipe(ialu_reg_mem);
|
||||||
@ -9490,14 +9490,14 @@ instruct andL_rReg_imm255(rRegL dst, immL_255 src)
|
|||||||
%{
|
%{
|
||||||
match(Set dst (AndL dst src));
|
match(Set dst (AndL dst src));
|
||||||
|
|
||||||
format %{ "movzbq $dst, $src\t# long & 0xFF" %}
|
format %{ "movzbq $dst, $dst\t# long & 0xFF" %}
|
||||||
opcode(0x0F, 0xB6);
|
opcode(0x0F, 0xB6);
|
||||||
ins_encode(REX_reg_reg_wide(dst, dst), OpcP, OpcS, reg_reg(dst, dst));
|
ins_encode(REX_reg_reg_wide(dst, dst), OpcP, OpcS, reg_reg(dst, dst));
|
||||||
ins_pipe(ialu_reg);
|
ins_pipe(ialu_reg);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// And Register with Immediate 65535
|
// And Register with Immediate 65535
|
||||||
instruct andL_rReg_imm65535(rRegI dst, immL_65535 src)
|
instruct andL_rReg_imm65535(rRegL dst, immL_65535 src)
|
||||||
%{
|
%{
|
||||||
match(Set dst (AndL dst src));
|
match(Set dst (AndL dst src));
|
||||||
|
|
||||||
|
@ -1432,6 +1432,10 @@ char * os::local_time_string(char *buf, size_t buflen) {
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
|
||||||
|
return localtime_r(clock, res);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// runtime exit support
|
// runtime exit support
|
||||||
|
|
||||||
|
@ -323,6 +323,10 @@ size_t os::current_stack_size() {
|
|||||||
return (size_t)(base - bottom);
|
return (size_t)(base - bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
|
||||||
|
return localtime_r(clock, res);
|
||||||
|
}
|
||||||
|
|
||||||
// interruptible infrastructure
|
// interruptible infrastructure
|
||||||
|
|
||||||
// setup_interruptible saves the thread state before going into an
|
// setup_interruptible saves the thread state before going into an
|
||||||
|
@ -327,6 +327,14 @@ size_t os::current_stack_size() {
|
|||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
|
||||||
|
const struct tm* time_struct_ptr = localtime(clock);
|
||||||
|
if (time_struct_ptr != NULL) {
|
||||||
|
*res = *time_struct_ptr;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
|
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
|
||||||
|
|
||||||
|
@ -316,9 +316,12 @@ int cmpstr(const void *k1, const void *k2) {
|
|||||||
return strcmp((const char *)k1,(const char *)k2);
|
return strcmp((const char *)k1,(const char *)k2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slimey cheap key comparator.
|
// Cheap key comparator.
|
||||||
int cmpkey(const void *key1, const void *key2) {
|
int cmpkey(const void *key1, const void *key2) {
|
||||||
return (int)((intptr_t)key1 - (intptr_t)key2);
|
if (key1 == key2) return 0;
|
||||||
|
intptr_t delta = (intptr_t)key1 - (intptr_t)key2;
|
||||||
|
if (delta > 0) return 1;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -248,7 +248,7 @@ Form::DataType Form::ideal_to_Reg_type(const char *name) const {
|
|||||||
// True if 'opType', an ideal name, loads or stores.
|
// True if 'opType', an ideal name, loads or stores.
|
||||||
Form::DataType Form::is_load_from_memory(const char *opType) const {
|
Form::DataType Form::is_load_from_memory(const char *opType) const {
|
||||||
if( strcmp(opType,"LoadB")==0 ) return Form::idealB;
|
if( strcmp(opType,"LoadB")==0 ) return Form::idealB;
|
||||||
if( strcmp(opType,"LoadC")==0 ) return Form::idealC;
|
if( strcmp(opType,"LoadUS")==0 ) return Form::idealC;
|
||||||
if( strcmp(opType,"LoadD")==0 ) return Form::idealD;
|
if( strcmp(opType,"LoadD")==0 ) return Form::idealD;
|
||||||
if( strcmp(opType,"LoadD_unaligned")==0 ) return Form::idealD;
|
if( strcmp(opType,"LoadD_unaligned")==0 ) return Form::idealD;
|
||||||
if( strcmp(opType,"LoadF")==0 ) return Form::idealF;
|
if( strcmp(opType,"LoadF")==0 ) return Form::idealF;
|
||||||
|
@ -3314,7 +3314,7 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {
|
|||||||
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
|
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
|
||||||
"StoreB","StoreC","Store" ,"StoreFP",
|
"StoreB","StoreC","Store" ,"StoreFP",
|
||||||
"LoadI" ,"LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
|
"LoadI" ,"LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
|
||||||
"LoadB" ,"LoadC" ,"LoadS" ,"Load" ,
|
"LoadB" ,"LoadUS" ,"LoadS" ,"Load" ,
|
||||||
"Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B",
|
"Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B",
|
||||||
"Store8B","Store4B","Store8C","Store4C","Store2C",
|
"Store8B","Store4B","Store8C","Store4C","Store2C",
|
||||||
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
|
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
|
||||||
|
@ -123,6 +123,10 @@ CodeBuffer::~CodeBuffer() {
|
|||||||
// addresses constructed before expansions will not be confused.
|
// addresses constructed before expansions will not be confused.
|
||||||
cb->free_blob();
|
cb->free_blob();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// free any overflow storage
|
||||||
|
delete _overflow_arena;
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
Copy::fill_to_bytes(this, sizeof(*this), badResourceValue);
|
Copy::fill_to_bytes(this, sizeof(*this), badResourceValue);
|
||||||
#endif
|
#endif
|
||||||
|
@ -846,6 +846,12 @@ klassOop SystemDictionary::find(symbolHandle class_name,
|
|||||||
Handle protection_domain,
|
Handle protection_domain,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
|
||||||
|
// UseNewReflection
|
||||||
|
// The result of this call should be consistent with the result
|
||||||
|
// of the call to resolve_instance_class_or_null().
|
||||||
|
// See evaluation 6790209 and 4474172 for more details.
|
||||||
|
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
|
||||||
|
|
||||||
unsigned int d_hash = dictionary()->compute_hash(class_name, class_loader);
|
unsigned int d_hash = dictionary()->compute_hash(class_name, class_loader);
|
||||||
int d_index = dictionary()->hash_to_index(d_hash);
|
int d_index = dictionary()->hash_to_index(d_hash);
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
// We need to sort heap regions by collection desirability.
|
// We need to sort heap regions by collection desirability.
|
||||||
|
|
||||||
class CSetChooserCache {
|
class CSetChooserCache VALUE_OBJ_CLASS_SPEC {
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
CacheLength = 16
|
CacheLength = 16
|
||||||
|
@ -33,7 +33,7 @@ enum PostYieldAction {
|
|||||||
PYA_cancel // It's been completed by somebody else: cancel.
|
PYA_cancel // It's been completed by somebody else: cancel.
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConcurrentG1Refine {
|
class ConcurrentG1Refine: public CHeapObj {
|
||||||
ConcurrentG1RefineThread* _cg1rThread;
|
ConcurrentG1RefineThread* _cg1rThread;
|
||||||
|
|
||||||
volatile jint _pya;
|
volatile jint _pya;
|
||||||
|
@ -30,7 +30,7 @@ typedef GenericTaskQueueSet<oop> CMTaskQueueSet;
|
|||||||
// A generic CM bit map. This is essentially a wrapper around the BitMap
|
// A generic CM bit map. This is essentially a wrapper around the BitMap
|
||||||
// class, with one bit per (1<<_shifter) HeapWords.
|
// class, with one bit per (1<<_shifter) HeapWords.
|
||||||
|
|
||||||
class CMBitMapRO {
|
class CMBitMapRO VALUE_OBJ_CLASS_SPEC {
|
||||||
protected:
|
protected:
|
||||||
HeapWord* _bmStartWord; // base address of range covered by map
|
HeapWord* _bmStartWord; // base address of range covered by map
|
||||||
size_t _bmWordSize; // map size (in #HeapWords covered)
|
size_t _bmWordSize; // map size (in #HeapWords covered)
|
||||||
@ -139,7 +139,7 @@ class CMBitMap : public CMBitMapRO {
|
|||||||
|
|
||||||
// Represents a marking stack used by the CM collector.
|
// Represents a marking stack used by the CM collector.
|
||||||
// Ideally this should be GrowableArray<> just like MSC's marking stack(s).
|
// Ideally this should be GrowableArray<> just like MSC's marking stack(s).
|
||||||
class CMMarkStack {
|
class CMMarkStack VALUE_OBJ_CLASS_SPEC {
|
||||||
ConcurrentMark* _cm;
|
ConcurrentMark* _cm;
|
||||||
oop* _base; // bottom of stack
|
oop* _base; // bottom of stack
|
||||||
jint _index; // one more than last occupied index
|
jint _index; // one more than last occupied index
|
||||||
@ -237,7 +237,7 @@ class CMMarkStack {
|
|||||||
void oops_do(OopClosure* f);
|
void oops_do(OopClosure* f);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CMRegionStack {
|
class CMRegionStack VALUE_OBJ_CLASS_SPEC {
|
||||||
MemRegion* _base;
|
MemRegion* _base;
|
||||||
jint _capacity;
|
jint _capacity;
|
||||||
jint _index;
|
jint _index;
|
||||||
@ -312,7 +312,7 @@ typedef enum {
|
|||||||
|
|
||||||
class ConcurrentMarkThread;
|
class ConcurrentMarkThread;
|
||||||
|
|
||||||
class ConcurrentMark {
|
class ConcurrentMark: public CHeapObj {
|
||||||
friend class ConcurrentMarkThread;
|
friend class ConcurrentMarkThread;
|
||||||
friend class CMTask;
|
friend class CMTask;
|
||||||
friend class CMBitMapClosure;
|
friend class CMBitMapClosure;
|
||||||
|
@ -141,7 +141,7 @@ YoungList::YoungList(G1CollectedHeap* g1h)
|
|||||||
_scan_only_head(NULL), _scan_only_tail(NULL), _curr_scan_only(NULL),
|
_scan_only_head(NULL), _scan_only_tail(NULL), _curr_scan_only(NULL),
|
||||||
_length(0), _scan_only_length(0),
|
_length(0), _scan_only_length(0),
|
||||||
_last_sampled_rs_lengths(0),
|
_last_sampled_rs_lengths(0),
|
||||||
_survivor_head(NULL), _survivors_tail(NULL), _survivor_length(0)
|
_survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0)
|
||||||
{
|
{
|
||||||
guarantee( check_list_empty(false), "just making sure..." );
|
guarantee( check_list_empty(false), "just making sure..." );
|
||||||
}
|
}
|
||||||
@ -159,16 +159,15 @@ void YoungList::push_region(HeapRegion *hr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void YoungList::add_survivor_region(HeapRegion* hr) {
|
void YoungList::add_survivor_region(HeapRegion* hr) {
|
||||||
assert(!hr->is_survivor(), "should not already be for survived");
|
assert(hr->is_survivor(), "should be flagged as survivor region");
|
||||||
assert(hr->get_next_young_region() == NULL, "cause it should!");
|
assert(hr->get_next_young_region() == NULL, "cause it should!");
|
||||||
|
|
||||||
hr->set_next_young_region(_survivor_head);
|
hr->set_next_young_region(_survivor_head);
|
||||||
if (_survivor_head == NULL) {
|
if (_survivor_head == NULL) {
|
||||||
_survivors_tail = hr;
|
_survivor_tail = hr;
|
||||||
}
|
}
|
||||||
_survivor_head = hr;
|
_survivor_head = hr;
|
||||||
|
|
||||||
hr->set_survivor();
|
|
||||||
++_survivor_length;
|
++_survivor_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +238,7 @@ void YoungList::empty_list() {
|
|||||||
|
|
||||||
empty_list(_survivor_head);
|
empty_list(_survivor_head);
|
||||||
_survivor_head = NULL;
|
_survivor_head = NULL;
|
||||||
_survivors_tail = NULL;
|
_survivor_tail = NULL;
|
||||||
_survivor_length = 0;
|
_survivor_length = 0;
|
||||||
|
|
||||||
_last_sampled_rs_lengths = 0;
|
_last_sampled_rs_lengths = 0;
|
||||||
@ -391,6 +390,7 @@ YoungList::reset_auxilary_lists() {
|
|||||||
|
|
||||||
// Add survivor regions to SurvRateGroup.
|
// Add survivor regions to SurvRateGroup.
|
||||||
_g1h->g1_policy()->note_start_adding_survivor_regions();
|
_g1h->g1_policy()->note_start_adding_survivor_regions();
|
||||||
|
_g1h->g1_policy()->finished_recalculating_age_indexes(true /* is_survivors */);
|
||||||
for (HeapRegion* curr = _survivor_head;
|
for (HeapRegion* curr = _survivor_head;
|
||||||
curr != NULL;
|
curr != NULL;
|
||||||
curr = curr->get_next_young_region()) {
|
curr = curr->get_next_young_region()) {
|
||||||
@ -401,7 +401,7 @@ YoungList::reset_auxilary_lists() {
|
|||||||
if (_survivor_head != NULL) {
|
if (_survivor_head != NULL) {
|
||||||
_head = _survivor_head;
|
_head = _survivor_head;
|
||||||
_length = _survivor_length + _scan_only_length;
|
_length = _survivor_length + _scan_only_length;
|
||||||
_survivors_tail->set_next_young_region(_scan_only_head);
|
_survivor_tail->set_next_young_region(_scan_only_head);
|
||||||
} else {
|
} else {
|
||||||
_head = _scan_only_head;
|
_head = _scan_only_head;
|
||||||
_length = _scan_only_length;
|
_length = _scan_only_length;
|
||||||
@ -418,9 +418,9 @@ YoungList::reset_auxilary_lists() {
|
|||||||
_curr_scan_only = NULL;
|
_curr_scan_only = NULL;
|
||||||
|
|
||||||
_survivor_head = NULL;
|
_survivor_head = NULL;
|
||||||
_survivors_tail = NULL;
|
_survivor_tail = NULL;
|
||||||
_survivor_length = 0;
|
_survivor_length = 0;
|
||||||
_g1h->g1_policy()->finished_recalculating_age_indexes();
|
_g1h->g1_policy()->finished_recalculating_age_indexes(false /* is_survivors */);
|
||||||
|
|
||||||
assert(check_list_well_formed(), "young list should be well formed");
|
assert(check_list_well_formed(), "young list should be well formed");
|
||||||
}
|
}
|
||||||
@ -553,7 +553,7 @@ HeapRegion* G1CollectedHeap::newAllocRegionWithExpansion(int purpose,
|
|||||||
if (_gc_alloc_region_counts[purpose] < g1_policy()->max_regions(purpose)) {
|
if (_gc_alloc_region_counts[purpose] < g1_policy()->max_regions(purpose)) {
|
||||||
alloc_region = newAllocRegion_work(word_size, true, zero_filled);
|
alloc_region = newAllocRegion_work(word_size, true, zero_filled);
|
||||||
if (purpose == GCAllocForSurvived && alloc_region != NULL) {
|
if (purpose == GCAllocForSurvived && alloc_region != NULL) {
|
||||||
_young_list->add_survivor_region(alloc_region);
|
alloc_region->set_survivor();
|
||||||
}
|
}
|
||||||
++_gc_alloc_region_counts[purpose];
|
++_gc_alloc_region_counts[purpose];
|
||||||
} else {
|
} else {
|
||||||
@ -949,6 +949,10 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
|
|||||||
GCOverheadReporter::recordSTWEnd(end);
|
GCOverheadReporter::recordSTWEnd(end);
|
||||||
g1_policy()->record_full_collection_end();
|
g1_policy()->record_full_collection_end();
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
ParallelTaskTerminator::print_termination_counts();
|
||||||
|
#endif
|
||||||
|
|
||||||
gc_epilogue(true);
|
gc_epilogue(true);
|
||||||
|
|
||||||
// Abandon concurrent refinement. This must happen last: in the
|
// Abandon concurrent refinement. This must happen last: in the
|
||||||
@ -2593,6 +2597,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
|
|||||||
_young_list->print();
|
_young_list->print();
|
||||||
#endif // SCAN_ONLY_VERBOSE
|
#endif // SCAN_ONLY_VERBOSE
|
||||||
|
|
||||||
|
g1_policy()->record_survivor_regions(_young_list->survivor_length(),
|
||||||
|
_young_list->first_survivor_region(),
|
||||||
|
_young_list->last_survivor_region());
|
||||||
_young_list->reset_auxilary_lists();
|
_young_list->reset_auxilary_lists();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2619,7 +2626,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
|
|||||||
#endif // SCAN_ONLY_VERBOSE
|
#endif // SCAN_ONLY_VERBOSE
|
||||||
|
|
||||||
double end_time_sec = os::elapsedTime();
|
double end_time_sec = os::elapsedTime();
|
||||||
g1_policy()->record_pause_time((end_time_sec - start_time_sec)*1000.0);
|
if (!evacuation_failed()) {
|
||||||
|
g1_policy()->record_pause_time((end_time_sec - start_time_sec)*1000.0);
|
||||||
|
}
|
||||||
GCOverheadReporter::recordSTWEnd(end_time_sec);
|
GCOverheadReporter::recordSTWEnd(end_time_sec);
|
||||||
g1_policy()->record_collection_pause_end(popular_region != NULL,
|
g1_policy()->record_collection_pause_end(popular_region != NULL,
|
||||||
abandoned);
|
abandoned);
|
||||||
@ -2642,8 +2651,13 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mark_in_progress())
|
if (mark_in_progress()) {
|
||||||
concurrent_mark()->update_g1_committed();
|
concurrent_mark()->update_g1_committed();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
ParallelTaskTerminator::print_termination_counts();
|
||||||
|
#endif
|
||||||
|
|
||||||
gc_epilogue(false);
|
gc_epilogue(false);
|
||||||
}
|
}
|
||||||
@ -2754,6 +2768,13 @@ void G1CollectedHeap::forget_alloc_region_list() {
|
|||||||
_gc_alloc_region_list = r->next_gc_alloc_region();
|
_gc_alloc_region_list = r->next_gc_alloc_region();
|
||||||
r->set_next_gc_alloc_region(NULL);
|
r->set_next_gc_alloc_region(NULL);
|
||||||
r->set_is_gc_alloc_region(false);
|
r->set_is_gc_alloc_region(false);
|
||||||
|
if (r->is_survivor()) {
|
||||||
|
if (r->is_empty()) {
|
||||||
|
r->set_not_young();
|
||||||
|
} else {
|
||||||
|
_young_list->add_survivor_region(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (r->is_empty()) {
|
if (r->is_empty()) {
|
||||||
++_free_regions;
|
++_free_regions;
|
||||||
}
|
}
|
||||||
@ -3150,6 +3171,20 @@ HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose,
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void G1CollectedHeap::retire_alloc_region(HeapRegion* alloc_region,
|
||||||
|
bool par) {
|
||||||
|
// Another thread might have obtained alloc_region for the given
|
||||||
|
// purpose, and might be attempting to allocate in it, and might
|
||||||
|
// succeed. Therefore, we can't do the "finalization" stuff on the
|
||||||
|
// region below until we're sure the last allocation has happened.
|
||||||
|
// We ensure this by allocating the remaining space with a garbage
|
||||||
|
// object.
|
||||||
|
if (par) par_allocate_remaining_space(alloc_region);
|
||||||
|
// Now we can do the post-GC stuff on the region.
|
||||||
|
alloc_region->note_end_of_copying();
|
||||||
|
g1_policy()->record_after_bytes(alloc_region->used());
|
||||||
|
}
|
||||||
|
|
||||||
HeapWord*
|
HeapWord*
|
||||||
G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose,
|
G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose,
|
||||||
HeapRegion* alloc_region,
|
HeapRegion* alloc_region,
|
||||||
@ -3167,16 +3202,7 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose,
|
|||||||
// Otherwise, continue; this new region is empty, too.
|
// Otherwise, continue; this new region is empty, too.
|
||||||
}
|
}
|
||||||
assert(alloc_region != NULL, "We better have an allocation region");
|
assert(alloc_region != NULL, "We better have an allocation region");
|
||||||
// Another thread might have obtained alloc_region for the given
|
retire_alloc_region(alloc_region, par);
|
||||||
// purpose, and might be attempting to allocate in it, and might
|
|
||||||
// succeed. Therefore, we can't do the "finalization" stuff on the
|
|
||||||
// region below until we're sure the last allocation has happened.
|
|
||||||
// We ensure this by allocating the remaining space with a garbage
|
|
||||||
// object.
|
|
||||||
if (par) par_allocate_remaining_space(alloc_region);
|
|
||||||
// Now we can do the post-GC stuff on the region.
|
|
||||||
alloc_region->note_end_of_copying();
|
|
||||||
g1_policy()->record_after_bytes(alloc_region->used());
|
|
||||||
|
|
||||||
if (_gc_alloc_region_counts[purpose] >= g1_policy()->max_regions(purpose)) {
|
if (_gc_alloc_region_counts[purpose] >= g1_policy()->max_regions(purpose)) {
|
||||||
// Cannot allocate more regions for the given purpose.
|
// Cannot allocate more regions for the given purpose.
|
||||||
@ -3185,7 +3211,7 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose,
|
|||||||
if (purpose != alt_purpose) {
|
if (purpose != alt_purpose) {
|
||||||
HeapRegion* alt_region = _gc_alloc_regions[alt_purpose];
|
HeapRegion* alt_region = _gc_alloc_regions[alt_purpose];
|
||||||
// Has not the alternative region been aliased?
|
// Has not the alternative region been aliased?
|
||||||
if (alloc_region != alt_region) {
|
if (alloc_region != alt_region && alt_region != NULL) {
|
||||||
// Try to allocate in the alternative region.
|
// Try to allocate in the alternative region.
|
||||||
if (par) {
|
if (par) {
|
||||||
block = alt_region->par_allocate(word_size);
|
block = alt_region->par_allocate(word_size);
|
||||||
@ -3194,9 +3220,10 @@ G1CollectedHeap::allocate_during_gc_slow(GCAllocPurpose purpose,
|
|||||||
}
|
}
|
||||||
// Make an alias.
|
// Make an alias.
|
||||||
_gc_alloc_regions[purpose] = _gc_alloc_regions[alt_purpose];
|
_gc_alloc_regions[purpose] = _gc_alloc_regions[alt_purpose];
|
||||||
}
|
if (block != NULL) {
|
||||||
if (block != NULL) {
|
return block;
|
||||||
return block;
|
}
|
||||||
|
retire_alloc_region(alt_region, par);
|
||||||
}
|
}
|
||||||
// Both the allocation region and the alternative one are full
|
// Both the allocation region and the alternative one are full
|
||||||
// and aliased, replace them with a new allocation region.
|
// and aliased, replace them with a new allocation region.
|
||||||
@ -3497,6 +3524,7 @@ protected:
|
|||||||
OverflowQueue* _overflowed_refs;
|
OverflowQueue* _overflowed_refs;
|
||||||
|
|
||||||
G1ParGCAllocBuffer _alloc_buffers[GCAllocPurposeCount];
|
G1ParGCAllocBuffer _alloc_buffers[GCAllocPurposeCount];
|
||||||
|
ageTable _age_table;
|
||||||
|
|
||||||
size_t _alloc_buffer_waste;
|
size_t _alloc_buffer_waste;
|
||||||
size_t _undo_waste;
|
size_t _undo_waste;
|
||||||
@ -3538,6 +3566,7 @@ public:
|
|||||||
_refs(g1h->task_queue(queue_num)),
|
_refs(g1h->task_queue(queue_num)),
|
||||||
_hash_seed(17), _queue_num(queue_num),
|
_hash_seed(17), _queue_num(queue_num),
|
||||||
_term_attempts(0),
|
_term_attempts(0),
|
||||||
|
_age_table(false),
|
||||||
#if G1_DETAILED_STATS
|
#if G1_DETAILED_STATS
|
||||||
_pushes(0), _pops(0), _steals(0),
|
_pushes(0), _pops(0), _steals(0),
|
||||||
_steal_attempts(0), _overflow_pushes(0),
|
_steal_attempts(0), _overflow_pushes(0),
|
||||||
@ -3572,8 +3601,9 @@ public:
|
|||||||
|
|
||||||
RefToScanQueue* refs() { return _refs; }
|
RefToScanQueue* refs() { return _refs; }
|
||||||
OverflowQueue* overflowed_refs() { return _overflowed_refs; }
|
OverflowQueue* overflowed_refs() { return _overflowed_refs; }
|
||||||
|
ageTable* age_table() { return &_age_table; }
|
||||||
|
|
||||||
inline G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) {
|
G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) {
|
||||||
return &_alloc_buffers[purpose];
|
return &_alloc_buffers[purpose];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3834,7 +3864,9 @@ oop G1ParCopyHelper::copy_to_survivor_space(oop old) {
|
|||||||
(!from_region->is_young() && young_index == 0), "invariant" );
|
(!from_region->is_young() && young_index == 0), "invariant" );
|
||||||
G1CollectorPolicy* g1p = _g1->g1_policy();
|
G1CollectorPolicy* g1p = _g1->g1_policy();
|
||||||
markOop m = old->mark();
|
markOop m = old->mark();
|
||||||
GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, m->age(),
|
int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age()
|
||||||
|
: m->age();
|
||||||
|
GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age,
|
||||||
word_sz);
|
word_sz);
|
||||||
HeapWord* obj_ptr = _par_scan_state->allocate(alloc_purpose, word_sz);
|
HeapWord* obj_ptr = _par_scan_state->allocate(alloc_purpose, word_sz);
|
||||||
oop obj = oop(obj_ptr);
|
oop obj = oop(obj_ptr);
|
||||||
@ -3872,9 +3904,12 @@ oop G1ParCopyHelper::copy_to_survivor_space(oop old) {
|
|||||||
obj->incr_age();
|
obj->incr_age();
|
||||||
} else {
|
} else {
|
||||||
m = m->incr_age();
|
m = m->incr_age();
|
||||||
|
obj->set_mark(m);
|
||||||
}
|
}
|
||||||
|
_par_scan_state->age_table()->add(obj, word_sz);
|
||||||
|
} else {
|
||||||
|
obj->set_mark(m);
|
||||||
}
|
}
|
||||||
obj->set_mark(m);
|
|
||||||
|
|
||||||
// preserve "next" mark bit
|
// preserve "next" mark bit
|
||||||
if (_g1->mark_in_progress() && !_g1->is_obj_ill(old)) {
|
if (_g1->mark_in_progress() && !_g1->is_obj_ill(old)) {
|
||||||
@ -4129,6 +4164,9 @@ public:
|
|||||||
_g1h->g1_policy()->record_obj_copy_time(i, elapsed_ms-term_ms);
|
_g1h->g1_policy()->record_obj_copy_time(i, elapsed_ms-term_ms);
|
||||||
_g1h->g1_policy()->record_termination_time(i, term_ms);
|
_g1h->g1_policy()->record_termination_time(i, term_ms);
|
||||||
}
|
}
|
||||||
|
if (G1UseSurvivorSpace) {
|
||||||
|
_g1h->g1_policy()->record_thread_age_table(pss.age_table());
|
||||||
|
}
|
||||||
_g1h->update_surviving_young_words(pss.surviving_young_words()+1);
|
_g1h->update_surviving_young_words(pss.surviving_young_words()+1);
|
||||||
|
|
||||||
// Clean up any par-expanded rem sets.
|
// Clean up any par-expanded rem sets.
|
||||||
@ -4368,7 +4406,7 @@ void G1CollectedHeap::evacuate_collection_set() {
|
|||||||
// Is this the right thing to do here? We don't save marks
|
// Is this the right thing to do here? We don't save marks
|
||||||
// on individual heap regions when we allocate from
|
// on individual heap regions when we allocate from
|
||||||
// them in parallel, so this seems like the correct place for this.
|
// them in parallel, so this seems like the correct place for this.
|
||||||
all_alloc_regions_note_end_of_copying();
|
retire_all_alloc_regions();
|
||||||
{
|
{
|
||||||
G1IsAliveClosure is_alive(this);
|
G1IsAliveClosure is_alive(this);
|
||||||
G1KeepAliveClosure keep_alive(this);
|
G1KeepAliveClosure keep_alive(this);
|
||||||
@ -5008,7 +5046,7 @@ bool G1CollectedHeap::all_alloc_regions_no_allocs_since_save_marks() {
|
|||||||
return no_allocs;
|
return no_allocs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CollectedHeap::all_alloc_regions_note_end_of_copying() {
|
void G1CollectedHeap::retire_all_alloc_regions() {
|
||||||
for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
|
for (int ap = 0; ap < GCAllocPurposeCount; ++ap) {
|
||||||
HeapRegion* r = _gc_alloc_regions[ap];
|
HeapRegion* r = _gc_alloc_regions[ap];
|
||||||
if (r != NULL) {
|
if (r != NULL) {
|
||||||
@ -5021,8 +5059,7 @@ void G1CollectedHeap::all_alloc_regions_note_end_of_copying() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!has_processed_alias) {
|
if (!has_processed_alias) {
|
||||||
r->note_end_of_copying();
|
retire_alloc_region(r, false /* par */);
|
||||||
g1_policy()->record_after_bytes(r->used());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ private:
|
|||||||
HeapRegion* _curr_scan_only;
|
HeapRegion* _curr_scan_only;
|
||||||
|
|
||||||
HeapRegion* _survivor_head;
|
HeapRegion* _survivor_head;
|
||||||
HeapRegion* _survivors_tail;
|
HeapRegion* _survivor_tail;
|
||||||
size_t _survivor_length;
|
size_t _survivor_length;
|
||||||
|
|
||||||
void empty_list(HeapRegion* list);
|
void empty_list(HeapRegion* list);
|
||||||
@ -105,6 +105,7 @@ public:
|
|||||||
bool is_empty() { return _length == 0; }
|
bool is_empty() { return _length == 0; }
|
||||||
size_t length() { return _length; }
|
size_t length() { return _length; }
|
||||||
size_t scan_only_length() { return _scan_only_length; }
|
size_t scan_only_length() { return _scan_only_length; }
|
||||||
|
size_t survivor_length() { return _survivor_length; }
|
||||||
|
|
||||||
void rs_length_sampling_init();
|
void rs_length_sampling_init();
|
||||||
bool rs_length_sampling_more();
|
bool rs_length_sampling_more();
|
||||||
@ -120,6 +121,7 @@ public:
|
|||||||
HeapRegion* first_region() { return _head; }
|
HeapRegion* first_region() { return _head; }
|
||||||
HeapRegion* first_scan_only_region() { return _scan_only_head; }
|
HeapRegion* first_scan_only_region() { return _scan_only_head; }
|
||||||
HeapRegion* first_survivor_region() { return _survivor_head; }
|
HeapRegion* first_survivor_region() { return _survivor_head; }
|
||||||
|
HeapRegion* last_survivor_region() { return _survivor_tail; }
|
||||||
HeapRegion* par_get_next_scan_only_region() {
|
HeapRegion* par_get_next_scan_only_region() {
|
||||||
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
|
||||||
HeapRegion* ret = _curr_scan_only;
|
HeapRegion* ret = _curr_scan_only;
|
||||||
@ -219,7 +221,7 @@ private:
|
|||||||
// The to-space memory regions into which objects are being copied during
|
// The to-space memory regions into which objects are being copied during
|
||||||
// a GC.
|
// a GC.
|
||||||
HeapRegion* _gc_alloc_regions[GCAllocPurposeCount];
|
HeapRegion* _gc_alloc_regions[GCAllocPurposeCount];
|
||||||
uint _gc_alloc_region_counts[GCAllocPurposeCount];
|
size_t _gc_alloc_region_counts[GCAllocPurposeCount];
|
||||||
|
|
||||||
// A list of the regions that have been set to be alloc regions in the
|
// A list of the regions that have been set to be alloc regions in the
|
||||||
// current collection.
|
// current collection.
|
||||||
@ -281,8 +283,8 @@ protected:
|
|||||||
// Returns "true" iff none of the gc alloc regions have any allocations
|
// Returns "true" iff none of the gc alloc regions have any allocations
|
||||||
// since the last call to "save_marks".
|
// since the last call to "save_marks".
|
||||||
bool all_alloc_regions_no_allocs_since_save_marks();
|
bool all_alloc_regions_no_allocs_since_save_marks();
|
||||||
// Calls "note_end_of_copying on all gc alloc_regions.
|
// Perform finalization stuff on all allocation regions.
|
||||||
void all_alloc_regions_note_end_of_copying();
|
void retire_all_alloc_regions();
|
||||||
|
|
||||||
// The number of regions allocated to hold humongous objects.
|
// The number of regions allocated to hold humongous objects.
|
||||||
int _num_humongous_regions;
|
int _num_humongous_regions;
|
||||||
@ -351,6 +353,10 @@ protected:
|
|||||||
// that parallel threads might be attempting allocations.
|
// that parallel threads might be attempting allocations.
|
||||||
void par_allocate_remaining_space(HeapRegion* r);
|
void par_allocate_remaining_space(HeapRegion* r);
|
||||||
|
|
||||||
|
// Retires an allocation region when it is full or at the end of a
|
||||||
|
// GC pause.
|
||||||
|
void retire_alloc_region(HeapRegion* alloc_region, bool par);
|
||||||
|
|
||||||
// Helper function for two callbacks below.
|
// Helper function for two callbacks below.
|
||||||
// "full", if true, indicates that the GC is for a System.gc() request,
|
// "full", if true, indicates that the GC is for a System.gc() request,
|
||||||
// and should collect the entire heap. If "clear_all_soft_refs" is true,
|
// and should collect the entire heap. If "clear_all_soft_refs" is true,
|
||||||
|
@ -196,8 +196,13 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
|||||||
_short_lived_surv_rate_group(new SurvRateGroup(this, "Short Lived",
|
_short_lived_surv_rate_group(new SurvRateGroup(this, "Short Lived",
|
||||||
G1YoungSurvRateNumRegionsSummary)),
|
G1YoungSurvRateNumRegionsSummary)),
|
||||||
_survivor_surv_rate_group(new SurvRateGroup(this, "Survivor",
|
_survivor_surv_rate_group(new SurvRateGroup(this, "Survivor",
|
||||||
G1YoungSurvRateNumRegionsSummary))
|
G1YoungSurvRateNumRegionsSummary)),
|
||||||
// add here any more surv rate groups
|
// add here any more surv rate groups
|
||||||
|
_recorded_survivor_regions(0),
|
||||||
|
_recorded_survivor_head(NULL),
|
||||||
|
_recorded_survivor_tail(NULL),
|
||||||
|
_survivors_age_table(true)
|
||||||
|
|
||||||
{
|
{
|
||||||
_recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
|
_recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
|
||||||
_prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;
|
_prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;
|
||||||
@ -272,6 +277,15 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
|||||||
_concurrent_mark_cleanup_times_ms->add(0.20);
|
_concurrent_mark_cleanup_times_ms->add(0.20);
|
||||||
_tenuring_threshold = MaxTenuringThreshold;
|
_tenuring_threshold = MaxTenuringThreshold;
|
||||||
|
|
||||||
|
if (G1UseSurvivorSpace) {
|
||||||
|
// if G1FixedSurvivorSpaceSize is 0 which means the size is not
|
||||||
|
// fixed, then _max_survivor_regions will be calculated at
|
||||||
|
// calculate_young_list_target_config during initialization
|
||||||
|
_max_survivor_regions = G1FixedSurvivorSpaceSize / HeapRegion::GrainBytes;
|
||||||
|
} else {
|
||||||
|
_max_survivor_regions = 0;
|
||||||
|
}
|
||||||
|
|
||||||
initialize_all();
|
initialize_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +297,9 @@ static void inc_mod(int& i, int len) {
|
|||||||
void G1CollectorPolicy::initialize_flags() {
|
void G1CollectorPolicy::initialize_flags() {
|
||||||
set_min_alignment(HeapRegion::GrainBytes);
|
set_min_alignment(HeapRegion::GrainBytes);
|
||||||
set_max_alignment(GenRemSet::max_alignment_constraint(rem_set_name()));
|
set_max_alignment(GenRemSet::max_alignment_constraint(rem_set_name()));
|
||||||
|
if (SurvivorRatio < 1) {
|
||||||
|
vm_exit_during_initialization("Invalid survivor ratio specified");
|
||||||
|
}
|
||||||
CollectorPolicy::initialize_flags();
|
CollectorPolicy::initialize_flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +318,8 @@ void G1CollectorPolicy::init() {
|
|||||||
"-XX:+UseConcMarkSweepGC.");
|
"-XX:+UseConcMarkSweepGC.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialize_gc_policy_counters();
|
||||||
|
|
||||||
if (G1Gen) {
|
if (G1Gen) {
|
||||||
_in_young_gc_mode = true;
|
_in_young_gc_mode = true;
|
||||||
|
|
||||||
@ -322,6 +341,12 @@ void G1CollectorPolicy::init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the jstat counters for the policy.
|
||||||
|
void G1CollectorPolicy::initialize_gc_policy_counters()
|
||||||
|
{
|
||||||
|
_gc_policy_counters = new GCPolicyCounters("GarbageFirst", 1, 2 + G1Gen);
|
||||||
|
}
|
||||||
|
|
||||||
void G1CollectorPolicy::calculate_young_list_min_length() {
|
void G1CollectorPolicy::calculate_young_list_min_length() {
|
||||||
_young_list_min_length = 0;
|
_young_list_min_length = 0;
|
||||||
|
|
||||||
@ -352,6 +377,7 @@ void G1CollectorPolicy::calculate_young_list_target_config() {
|
|||||||
guarantee( so_length < _young_list_target_length, "invariant" );
|
guarantee( so_length < _young_list_target_length, "invariant" );
|
||||||
_young_list_so_prefix_length = so_length;
|
_young_list_so_prefix_length = so_length;
|
||||||
}
|
}
|
||||||
|
calculate_survivors_policy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method calculate the optimal scan-only set for a fixed young
|
// This method calculate the optimal scan-only set for a fixed young
|
||||||
@ -448,6 +474,9 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
if (full_young_gcs() && _free_regions_at_end_of_collection > 0) {
|
if (full_young_gcs() && _free_regions_at_end_of_collection > 0) {
|
||||||
// we are in fully-young mode and there are free regions in the heap
|
// we are in fully-young mode and there are free regions in the heap
|
||||||
|
|
||||||
|
double survivor_regions_evac_time =
|
||||||
|
predict_survivor_regions_evac_time();
|
||||||
|
|
||||||
size_t min_so_length = 0;
|
size_t min_so_length = 0;
|
||||||
size_t max_so_length = 0;
|
size_t max_so_length = 0;
|
||||||
|
|
||||||
@ -497,9 +526,8 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
scanned_cards = predict_non_young_card_num(adj_rs_lengths);
|
scanned_cards = predict_non_young_card_num(adj_rs_lengths);
|
||||||
// calculate this once, so that we don't have to recalculate it in
|
// calculate this once, so that we don't have to recalculate it in
|
||||||
// the innermost loop
|
// the innermost loop
|
||||||
double base_time_ms = predict_base_elapsed_time_ms(pending_cards,
|
double base_time_ms = predict_base_elapsed_time_ms(pending_cards, scanned_cards)
|
||||||
scanned_cards);
|
+ survivor_regions_evac_time;
|
||||||
|
|
||||||
// the result
|
// the result
|
||||||
size_t final_young_length = 0;
|
size_t final_young_length = 0;
|
||||||
size_t final_so_length = 0;
|
size_t final_so_length = 0;
|
||||||
@ -548,14 +576,14 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
bool done = false;
|
bool done = false;
|
||||||
// this is the outermost loop
|
// this is the outermost loop
|
||||||
while (!done) {
|
while (!done) {
|
||||||
#if 0
|
#ifdef TRACE_CALC_YOUNG_CONFIG
|
||||||
// leave this in for debugging, just in case
|
// leave this in for debugging, just in case
|
||||||
gclog_or_tty->print_cr("searching between " SIZE_FORMAT " and " SIZE_FORMAT
|
gclog_or_tty->print_cr("searching between " SIZE_FORMAT " and " SIZE_FORMAT
|
||||||
", incr " SIZE_FORMAT ", pass %s",
|
", incr " SIZE_FORMAT ", pass %s",
|
||||||
from_so_length, to_so_length, so_length_incr,
|
from_so_length, to_so_length, so_length_incr,
|
||||||
(pass == pass_type_coarse) ? "coarse" :
|
(pass == pass_type_coarse) ? "coarse" :
|
||||||
(pass == pass_type_fine) ? "fine" : "final");
|
(pass == pass_type_fine) ? "fine" : "final");
|
||||||
#endif // 0
|
#endif // TRACE_CALC_YOUNG_CONFIG
|
||||||
|
|
||||||
size_t so_length = from_so_length;
|
size_t so_length = from_so_length;
|
||||||
size_t init_free_regions =
|
size_t init_free_regions =
|
||||||
@ -651,11 +679,11 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
guarantee( so_length_incr == so_coarse_increments, "invariant" );
|
guarantee( so_length_incr == so_coarse_increments, "invariant" );
|
||||||
guarantee( final_so_length >= min_so_length, "invariant" );
|
guarantee( final_so_length >= min_so_length, "invariant" );
|
||||||
|
|
||||||
#if 0
|
#ifdef TRACE_CALC_YOUNG_CONFIG
|
||||||
// leave this in for debugging, just in case
|
// leave this in for debugging, just in case
|
||||||
gclog_or_tty->print_cr(" coarse pass: SO length " SIZE_FORMAT,
|
gclog_or_tty->print_cr(" coarse pass: SO length " SIZE_FORMAT,
|
||||||
final_so_length);
|
final_so_length);
|
||||||
#endif // 0
|
#endif // TRACE_CALC_YOUNG_CONFIG
|
||||||
|
|
||||||
from_so_length =
|
from_so_length =
|
||||||
(final_so_length - min_so_length > so_coarse_increments) ?
|
(final_so_length - min_so_length > so_coarse_increments) ?
|
||||||
@ -687,12 +715,12 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
// of the optimal
|
// of the optimal
|
||||||
size_t new_so_length = 950 * final_so_length / 1000;
|
size_t new_so_length = 950 * final_so_length / 1000;
|
||||||
|
|
||||||
#if 0
|
#ifdef TRACE_CALC_YOUNG_CONFIG
|
||||||
// leave this in for debugging, just in case
|
// leave this in for debugging, just in case
|
||||||
gclog_or_tty->print_cr(" fine pass: SO length " SIZE_FORMAT
|
gclog_or_tty->print_cr(" fine pass: SO length " SIZE_FORMAT
|
||||||
", setting it to " SIZE_FORMAT,
|
", setting it to " SIZE_FORMAT,
|
||||||
final_so_length, new_so_length);
|
final_so_length, new_so_length);
|
||||||
#endif // 0
|
#endif // TRACE_CALC_YOUNG_CONFIG
|
||||||
|
|
||||||
from_so_length = new_so_length;
|
from_so_length = new_so_length;
|
||||||
to_so_length = new_so_length;
|
to_so_length = new_so_length;
|
||||||
@ -719,7 +747,8 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we should have at least one region in the target young length
|
// we should have at least one region in the target young length
|
||||||
_young_list_target_length = MAX2((size_t) 1, final_young_length);
|
_young_list_target_length =
|
||||||
|
MAX2((size_t) 1, final_young_length + _recorded_survivor_regions);
|
||||||
if (final_so_length >= final_young_length)
|
if (final_so_length >= final_young_length)
|
||||||
// and we need to ensure that the S-O length is not greater than
|
// and we need to ensure that the S-O length is not greater than
|
||||||
// the target young length (this is being a bit careful)
|
// the target young length (this is being a bit careful)
|
||||||
@ -734,7 +763,7 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
double end_time_sec = os::elapsedTime();
|
double end_time_sec = os::elapsedTime();
|
||||||
double elapsed_time_ms = (end_time_sec - start_time_sec) * 1000.0;
|
double elapsed_time_ms = (end_time_sec - start_time_sec) * 1000.0;
|
||||||
|
|
||||||
#if 0
|
#ifdef TRACE_CALC_YOUNG_CONFIG
|
||||||
// leave this in for debugging, just in case
|
// leave this in for debugging, just in case
|
||||||
gclog_or_tty->print_cr("target = %1.1lf ms, young = " SIZE_FORMAT
|
gclog_or_tty->print_cr("target = %1.1lf ms, young = " SIZE_FORMAT
|
||||||
", SO = " SIZE_FORMAT ", "
|
", SO = " SIZE_FORMAT ", "
|
||||||
@ -747,9 +776,9 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
calculations,
|
calculations,
|
||||||
full_young_gcs() ? "full" : "partial",
|
full_young_gcs() ? "full" : "partial",
|
||||||
should_initiate_conc_mark() ? " i-m" : "",
|
should_initiate_conc_mark() ? " i-m" : "",
|
||||||
in_marking_window(),
|
_in_marking_window,
|
||||||
in_marking_window_im());
|
_in_marking_window_im);
|
||||||
#endif // 0
|
#endif // TRACE_CALC_YOUNG_CONFIG
|
||||||
|
|
||||||
if (_young_list_target_length < _young_list_min_length) {
|
if (_young_list_target_length < _young_list_min_length) {
|
||||||
// bummer; this means that, if we do a pause when the optimal
|
// bummer; this means that, if we do a pause when the optimal
|
||||||
@ -768,14 +797,14 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
// S-O length
|
// S-O length
|
||||||
so_length = calculate_optimal_so_length(_young_list_min_length);
|
so_length = calculate_optimal_so_length(_young_list_min_length);
|
||||||
|
|
||||||
#if 0
|
#ifdef TRACE_CALC_YOUNG_CONFIG
|
||||||
// leave this in for debugging, just in case
|
// leave this in for debugging, just in case
|
||||||
gclog_or_tty->print_cr("adjusted target length from "
|
gclog_or_tty->print_cr("adjusted target length from "
|
||||||
SIZE_FORMAT " to " SIZE_FORMAT
|
SIZE_FORMAT " to " SIZE_FORMAT
|
||||||
", SO " SIZE_FORMAT,
|
", SO " SIZE_FORMAT,
|
||||||
_young_list_target_length, _young_list_min_length,
|
_young_list_target_length, _young_list_min_length,
|
||||||
so_length);
|
so_length);
|
||||||
#endif // 0
|
#endif // TRACE_CALC_YOUNG_CONFIG
|
||||||
|
|
||||||
_young_list_target_length =
|
_young_list_target_length =
|
||||||
MAX2(_young_list_min_length, (size_t)1);
|
MAX2(_young_list_min_length, (size_t)1);
|
||||||
@ -785,12 +814,12 @@ void G1CollectorPolicy::calculate_young_list_target_config(size_t rs_lengths) {
|
|||||||
// we are in a partially-young mode or we've run out of regions (due
|
// we are in a partially-young mode or we've run out of regions (due
|
||||||
// to evacuation failure)
|
// to evacuation failure)
|
||||||
|
|
||||||
#if 0
|
#ifdef TRACE_CALC_YOUNG_CONFIG
|
||||||
// leave this in for debugging, just in case
|
// leave this in for debugging, just in case
|
||||||
gclog_or_tty->print_cr("(partial) setting target to " SIZE_FORMAT
|
gclog_or_tty->print_cr("(partial) setting target to " SIZE_FORMAT
|
||||||
", SO " SIZE_FORMAT,
|
", SO " SIZE_FORMAT,
|
||||||
_young_list_min_length, 0);
|
_young_list_min_length, 0);
|
||||||
#endif // 0
|
#endif // TRACE_CALC_YOUNG_CONFIG
|
||||||
|
|
||||||
// we'll do the pause as soon as possible and with no S-O prefix
|
// we'll do the pause as soon as possible and with no S-O prefix
|
||||||
// (see above for the reasons behind the latter)
|
// (see above for the reasons behind the latter)
|
||||||
@ -884,6 +913,16 @@ G1CollectorPolicy::predict_gc_eff(size_t young_length,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double G1CollectorPolicy::predict_survivor_regions_evac_time() {
|
||||||
|
double survivor_regions_evac_time = 0.0;
|
||||||
|
for (HeapRegion * r = _recorded_survivor_head;
|
||||||
|
r != NULL && r != _recorded_survivor_tail->get_next_young_region();
|
||||||
|
r = r->get_next_young_region()) {
|
||||||
|
survivor_regions_evac_time += predict_region_elapsed_time_ms(r, true);
|
||||||
|
}
|
||||||
|
return survivor_regions_evac_time;
|
||||||
|
}
|
||||||
|
|
||||||
void G1CollectorPolicy::check_prediction_validity() {
|
void G1CollectorPolicy::check_prediction_validity() {
|
||||||
guarantee( adaptive_young_list_length(), "should not call this otherwise" );
|
guarantee( adaptive_young_list_length(), "should not call this otherwise" );
|
||||||
|
|
||||||
@ -995,11 +1034,15 @@ void G1CollectorPolicy::record_full_collection_end() {
|
|||||||
_short_lived_surv_rate_group->start_adding_regions();
|
_short_lived_surv_rate_group->start_adding_regions();
|
||||||
// also call this on any additional surv rate groups
|
// also call this on any additional surv rate groups
|
||||||
|
|
||||||
|
record_survivor_regions(0, NULL, NULL);
|
||||||
|
|
||||||
_prev_region_num_young = _region_num_young;
|
_prev_region_num_young = _region_num_young;
|
||||||
_prev_region_num_tenured = _region_num_tenured;
|
_prev_region_num_tenured = _region_num_tenured;
|
||||||
|
|
||||||
_free_regions_at_end_of_collection = _g1->free_regions();
|
_free_regions_at_end_of_collection = _g1->free_regions();
|
||||||
_scan_only_regions_at_end_of_collection = 0;
|
_scan_only_regions_at_end_of_collection = 0;
|
||||||
|
// Reset survivors SurvRateGroup.
|
||||||
|
_survivor_surv_rate_group->reset();
|
||||||
calculate_young_list_min_length();
|
calculate_young_list_min_length();
|
||||||
calculate_young_list_target_config();
|
calculate_young_list_target_config();
|
||||||
}
|
}
|
||||||
@ -1104,6 +1147,10 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec,
|
|||||||
_short_lived_surv_rate_group->record_scan_only_prefix(short_lived_so_length);
|
_short_lived_surv_rate_group->record_scan_only_prefix(short_lived_so_length);
|
||||||
tag_scan_only(short_lived_so_length);
|
tag_scan_only(short_lived_so_length);
|
||||||
|
|
||||||
|
if (G1UseSurvivorSpace) {
|
||||||
|
_survivors_age_table.clear();
|
||||||
|
}
|
||||||
|
|
||||||
assert( verify_young_ages(), "region age verification" );
|
assert( verify_young_ages(), "region age verification" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1965,9 +2012,6 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular,
|
|||||||
// </NEW PREDICTION>
|
// </NEW PREDICTION>
|
||||||
|
|
||||||
_target_pause_time_ms = -1.0;
|
_target_pause_time_ms = -1.0;
|
||||||
|
|
||||||
// TODO: calculate tenuring threshold
|
|
||||||
_tenuring_threshold = MaxTenuringThreshold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// <NEW PREDICTION>
|
// <NEW PREDICTION>
|
||||||
@ -2058,7 +2102,7 @@ G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) {
|
|||||||
guarantee( hr->is_young() && hr->age_in_surv_rate_group() != -1,
|
guarantee( hr->is_young() && hr->age_in_surv_rate_group() != -1,
|
||||||
"invariant" );
|
"invariant" );
|
||||||
int age = hr->age_in_surv_rate_group();
|
int age = hr->age_in_surv_rate_group();
|
||||||
double yg_surv_rate = predict_yg_surv_rate(age);
|
double yg_surv_rate = predict_yg_surv_rate(age, hr->surv_rate_group());
|
||||||
bytes_to_copy = (size_t) ((double) hr->used() * yg_surv_rate);
|
bytes_to_copy = (size_t) ((double) hr->used() * yg_surv_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2091,7 +2135,7 @@ G1CollectorPolicy::record_cset_region(HeapRegion* hr, bool young) {
|
|||||||
}
|
}
|
||||||
#if PREDICTIONS_VERBOSE
|
#if PREDICTIONS_VERBOSE
|
||||||
if (young) {
|
if (young) {
|
||||||
_recorded_young_bytes += hr->asSpace()->used();
|
_recorded_young_bytes += hr->used();
|
||||||
} else {
|
} else {
|
||||||
_recorded_marked_bytes += hr->max_live_bytes();
|
_recorded_marked_bytes += hr->max_live_bytes();
|
||||||
}
|
}
|
||||||
@ -2119,11 +2163,6 @@ G1CollectorPolicy::end_recording_regions() {
|
|||||||
predict_non_young_card_num(_predicted_rs_lengths);
|
predict_non_young_card_num(_predicted_rs_lengths);
|
||||||
_recorded_region_num = _recorded_young_regions + _recorded_non_young_regions;
|
_recorded_region_num = _recorded_young_regions + _recorded_non_young_regions;
|
||||||
|
|
||||||
_predicted_young_survival_ratio = 0.0;
|
|
||||||
for (int i = 0; i < _recorded_young_regions; ++i)
|
|
||||||
_predicted_young_survival_ratio += predict_yg_surv_rate(i);
|
|
||||||
_predicted_young_survival_ratio /= (double) _recorded_young_regions;
|
|
||||||
|
|
||||||
_predicted_scan_only_scan_time_ms =
|
_predicted_scan_only_scan_time_ms =
|
||||||
predict_scan_only_time_ms(_recorded_scan_only_regions);
|
predict_scan_only_time_ms(_recorded_scan_only_regions);
|
||||||
_predicted_rs_update_time_ms =
|
_predicted_rs_update_time_ms =
|
||||||
@ -2673,8 +2712,11 @@ G1CollectorPolicy::should_add_next_region_to_young_list() {
|
|||||||
assert(in_young_gc_mode(), "should be in young GC mode");
|
assert(in_young_gc_mode(), "should be in young GC mode");
|
||||||
bool ret;
|
bool ret;
|
||||||
size_t young_list_length = _g1->young_list_length();
|
size_t young_list_length = _g1->young_list_length();
|
||||||
|
size_t young_list_max_length = _young_list_target_length;
|
||||||
if (young_list_length < _young_list_target_length) {
|
if (G1FixedEdenSize) {
|
||||||
|
young_list_max_length -= _max_survivor_regions;
|
||||||
|
}
|
||||||
|
if (young_list_length < young_list_max_length) {
|
||||||
ret = true;
|
ret = true;
|
||||||
++_region_num_young;
|
++_region_num_young;
|
||||||
} else {
|
} else {
|
||||||
@ -2710,17 +2752,39 @@ G1CollectorPolicy::checkpoint_conc_overhead() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint G1CollectorPolicy::max_regions(int purpose) {
|
size_t G1CollectorPolicy::max_regions(int purpose) {
|
||||||
switch (purpose) {
|
switch (purpose) {
|
||||||
case GCAllocForSurvived:
|
case GCAllocForSurvived:
|
||||||
return G1MaxSurvivorRegions;
|
return _max_survivor_regions;
|
||||||
case GCAllocForTenured:
|
case GCAllocForTenured:
|
||||||
return UINT_MAX;
|
return REGIONS_UNLIMITED;
|
||||||
default:
|
default:
|
||||||
return UINT_MAX;
|
ShouldNotReachHere();
|
||||||
|
return REGIONS_UNLIMITED;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculates survivor space parameters.
|
||||||
|
void G1CollectorPolicy::calculate_survivors_policy()
|
||||||
|
{
|
||||||
|
if (!G1UseSurvivorSpace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (G1FixedSurvivorSpaceSize == 0) {
|
||||||
|
_max_survivor_regions = _young_list_target_length / SurvivorRatio;
|
||||||
|
} else {
|
||||||
|
_max_survivor_regions = G1FixedSurvivorSpaceSize / HeapRegion::GrainBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G1FixedTenuringThreshold) {
|
||||||
|
_tenuring_threshold = MaxTenuringThreshold;
|
||||||
|
} else {
|
||||||
|
_tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(
|
||||||
|
HeapRegion::GrainWords * _max_survivor_regions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
G1CollectorPolicy_BestRegionsFirst::
|
G1CollectorPolicy_BestRegionsFirst::
|
||||||
set_single_region_collection_set(HeapRegion* hr) {
|
set_single_region_collection_set(HeapRegion* hr) {
|
||||||
@ -2743,7 +2807,11 @@ G1CollectorPolicy_BestRegionsFirst::should_do_collection_pause(size_t
|
|||||||
double max_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
|
double max_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
|
||||||
|
|
||||||
size_t young_list_length = _g1->young_list_length();
|
size_t young_list_length = _g1->young_list_length();
|
||||||
bool reached_target_length = young_list_length >= _young_list_target_length;
|
size_t young_list_max_length = _young_list_target_length;
|
||||||
|
if (G1FixedEdenSize) {
|
||||||
|
young_list_max_length -= _max_survivor_regions;
|
||||||
|
}
|
||||||
|
bool reached_target_length = young_list_length >= young_list_max_length;
|
||||||
|
|
||||||
if (in_young_gc_mode()) {
|
if (in_young_gc_mode()) {
|
||||||
if (reached_target_length) {
|
if (reached_target_length) {
|
||||||
|
@ -49,7 +49,7 @@ public: \
|
|||||||
class MainBodySummary;
|
class MainBodySummary;
|
||||||
class PopPreambleSummary;
|
class PopPreambleSummary;
|
||||||
|
|
||||||
class PauseSummary {
|
class PauseSummary: public CHeapObj {
|
||||||
define_num_seq(total)
|
define_num_seq(total)
|
||||||
define_num_seq(other)
|
define_num_seq(other)
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ public:
|
|||||||
virtual PopPreambleSummary* pop_preamble_summary() { return NULL; }
|
virtual PopPreambleSummary* pop_preamble_summary() { return NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MainBodySummary {
|
class MainBodySummary: public CHeapObj {
|
||||||
define_num_seq(satb_drain) // optional
|
define_num_seq(satb_drain) // optional
|
||||||
define_num_seq(parallel) // parallel only
|
define_num_seq(parallel) // parallel only
|
||||||
define_num_seq(ext_root_scan)
|
define_num_seq(ext_root_scan)
|
||||||
@ -75,7 +75,7 @@ class MainBodySummary {
|
|||||||
define_num_seq(clear_ct) // parallel only
|
define_num_seq(clear_ct) // parallel only
|
||||||
};
|
};
|
||||||
|
|
||||||
class PopPreambleSummary {
|
class PopPreambleSummary: public CHeapObj {
|
||||||
define_num_seq(pop_preamble)
|
define_num_seq(pop_preamble)
|
||||||
define_num_seq(pop_update_rs)
|
define_num_seq(pop_update_rs)
|
||||||
define_num_seq(pop_scan_rs)
|
define_num_seq(pop_scan_rs)
|
||||||
@ -557,6 +557,8 @@ public:
|
|||||||
return get_new_neg_prediction(_young_gc_eff_seq);
|
return get_new_neg_prediction(_young_gc_eff_seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double predict_survivor_regions_evac_time();
|
||||||
|
|
||||||
// </NEW PREDICTION>
|
// </NEW PREDICTION>
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -599,8 +601,8 @@ public:
|
|||||||
|
|
||||||
// Returns an estimate of the survival rate of the region at yg-age
|
// Returns an estimate of the survival rate of the region at yg-age
|
||||||
// "yg_age".
|
// "yg_age".
|
||||||
double predict_yg_surv_rate(int age) {
|
double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) {
|
||||||
TruncatedSeq* seq = _short_lived_surv_rate_group->get_seq(age);
|
TruncatedSeq* seq = surv_rate_group->get_seq(age);
|
||||||
if (seq->num() == 0)
|
if (seq->num() == 0)
|
||||||
gclog_or_tty->print("BARF! age is %d", age);
|
gclog_or_tty->print("BARF! age is %d", age);
|
||||||
guarantee( seq->num() > 0, "invariant" );
|
guarantee( seq->num() > 0, "invariant" );
|
||||||
@ -610,6 +612,10 @@ public:
|
|||||||
return pred;
|
return pred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double predict_yg_surv_rate(int age) {
|
||||||
|
return predict_yg_surv_rate(age, _short_lived_surv_rate_group);
|
||||||
|
}
|
||||||
|
|
||||||
double accum_yg_surv_rate_pred(int age) {
|
double accum_yg_surv_rate_pred(int age) {
|
||||||
return _short_lived_surv_rate_group->accum_surv_rate_pred(age);
|
return _short_lived_surv_rate_group->accum_surv_rate_pred(age);
|
||||||
}
|
}
|
||||||
@ -822,6 +828,9 @@ public:
|
|||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
|
// Create jstat counters for the policy.
|
||||||
|
virtual void initialize_gc_policy_counters();
|
||||||
|
|
||||||
virtual HeapWord* mem_allocate_work(size_t size,
|
virtual HeapWord* mem_allocate_work(size_t size,
|
||||||
bool is_tlab,
|
bool is_tlab,
|
||||||
bool* gc_overhead_limit_was_exceeded);
|
bool* gc_overhead_limit_was_exceeded);
|
||||||
@ -1047,8 +1056,12 @@ public:
|
|||||||
// Print stats on young survival ratio
|
// Print stats on young survival ratio
|
||||||
void print_yg_surv_rate_info() const;
|
void print_yg_surv_rate_info() const;
|
||||||
|
|
||||||
void finished_recalculating_age_indexes() {
|
void finished_recalculating_age_indexes(bool is_survivors) {
|
||||||
_short_lived_surv_rate_group->finished_recalculating_age_indexes();
|
if (is_survivors) {
|
||||||
|
_survivor_surv_rate_group->finished_recalculating_age_indexes();
|
||||||
|
} else {
|
||||||
|
_short_lived_surv_rate_group->finished_recalculating_age_indexes();
|
||||||
|
}
|
||||||
// do that for any other surv rate groups
|
// do that for any other surv rate groups
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1097,6 +1110,17 @@ protected:
|
|||||||
// maximum amount of suvivors regions.
|
// maximum amount of suvivors regions.
|
||||||
int _tenuring_threshold;
|
int _tenuring_threshold;
|
||||||
|
|
||||||
|
// The limit on the number of regions allocated for survivors.
|
||||||
|
size_t _max_survivor_regions;
|
||||||
|
|
||||||
|
// The amount of survor regions after a collection.
|
||||||
|
size_t _recorded_survivor_regions;
|
||||||
|
// List of survivor regions.
|
||||||
|
HeapRegion* _recorded_survivor_head;
|
||||||
|
HeapRegion* _recorded_survivor_tail;
|
||||||
|
|
||||||
|
ageTable _survivors_age_table;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
inline GCAllocPurpose
|
inline GCAllocPurpose
|
||||||
@ -1116,7 +1140,9 @@ public:
|
|||||||
return GCAllocForTenured;
|
return GCAllocForTenured;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint max_regions(int purpose);
|
static const size_t REGIONS_UNLIMITED = ~(size_t)0;
|
||||||
|
|
||||||
|
size_t max_regions(int purpose);
|
||||||
|
|
||||||
// The limit on regions for a particular purpose is reached.
|
// The limit on regions for a particular purpose is reached.
|
||||||
void note_alloc_region_limit_reached(int purpose) {
|
void note_alloc_region_limit_reached(int purpose) {
|
||||||
@ -1132,6 +1158,23 @@ public:
|
|||||||
void note_stop_adding_survivor_regions() {
|
void note_stop_adding_survivor_regions() {
|
||||||
_survivor_surv_rate_group->stop_adding_regions();
|
_survivor_surv_rate_group->stop_adding_regions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void record_survivor_regions(size_t regions,
|
||||||
|
HeapRegion* head,
|
||||||
|
HeapRegion* tail) {
|
||||||
|
_recorded_survivor_regions = regions;
|
||||||
|
_recorded_survivor_head = head;
|
||||||
|
_recorded_survivor_tail = tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
void record_thread_age_table(ageTable* age_table)
|
||||||
|
{
|
||||||
|
_survivors_age_table.merge_par(age_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates survivor space parameters.
|
||||||
|
void calculate_survivors_policy();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This encapsulates a particular strategy for a g1 Collector.
|
// This encapsulates a particular strategy for a g1 Collector.
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
/***** ALL TIMES ARE IN SECS!!!!!!! *****/
|
/***** ALL TIMES ARE IN SECS!!!!!!! *****/
|
||||||
|
|
||||||
// this is the "interface"
|
// this is the "interface"
|
||||||
class G1MMUTracker {
|
class G1MMUTracker: public CHeapObj {
|
||||||
protected:
|
protected:
|
||||||
double _time_slice;
|
double _time_slice;
|
||||||
double _max_gc_time; // this is per time slice
|
double _max_gc_time; // this is per time slice
|
||||||
@ -67,7 +67,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class G1MMUTrackerQueueElem {
|
class G1MMUTrackerQueueElem VALUE_OBJ_CLASS_SPEC {
|
||||||
private:
|
private:
|
||||||
double _start_time;
|
double _start_time;
|
||||||
double _end_time;
|
double _end_time;
|
||||||
|
@ -572,6 +572,9 @@ prepare_for_oops_into_collection_set_do() {
|
|||||||
}
|
}
|
||||||
guarantee( _cards_scanned == NULL, "invariant" );
|
guarantee( _cards_scanned == NULL, "invariant" );
|
||||||
_cards_scanned = NEW_C_HEAP_ARRAY(size_t, n_workers());
|
_cards_scanned = NEW_C_HEAP_ARRAY(size_t, n_workers());
|
||||||
|
for (uint i = 0; i < n_workers(); ++i) {
|
||||||
|
_cards_scanned[i] = 0;
|
||||||
|
}
|
||||||
_total_cards_scanned = 0;
|
_total_cards_scanned = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class CardTableModRefBarrierSet;
|
|||||||
class HRInto_G1RemSet;
|
class HRInto_G1RemSet;
|
||||||
class ConcurrentG1Refine;
|
class ConcurrentG1Refine;
|
||||||
|
|
||||||
class G1RemSet {
|
class G1RemSet: public CHeapObj {
|
||||||
protected:
|
protected:
|
||||||
G1CollectedHeap* _g1;
|
G1CollectedHeap* _g1;
|
||||||
|
|
||||||
|
@ -281,7 +281,17 @@
|
|||||||
develop(bool, G1HRRSFlushLogBuffersOnVerify, false, \
|
develop(bool, G1HRRSFlushLogBuffersOnVerify, false, \
|
||||||
"Forces flushing of log buffers before verification.") \
|
"Forces flushing of log buffers before verification.") \
|
||||||
\
|
\
|
||||||
product(intx, G1MaxSurvivorRegions, 0, \
|
product(bool, G1UseSurvivorSpace, true, \
|
||||||
"The maximum number of survivor regions")
|
"When true, use survivor space.") \
|
||||||
|
\
|
||||||
|
product(bool, G1FixedTenuringThreshold, false, \
|
||||||
|
"When set, G1 will not adjust the tenuring threshold") \
|
||||||
|
\
|
||||||
|
product(bool, G1FixedEdenSize, false, \
|
||||||
|
"When set, G1 will not allocate unused survivor space regions") \
|
||||||
|
\
|
||||||
|
product(uintx, G1FixedSurvivorSpaceSize, 0, \
|
||||||
|
"If non-0 is the size of the G1 survivor space, " \
|
||||||
|
"otherwise SurvivorRatio is used to determine the size")
|
||||||
|
|
||||||
G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
|
G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
|
||||||
|
@ -566,7 +566,11 @@ class HeapRegion: public G1OffsetTableContigSpace {
|
|||||||
void note_end_of_copying() {
|
void note_end_of_copying() {
|
||||||
assert(top() >= _next_top_at_mark_start,
|
assert(top() >= _next_top_at_mark_start,
|
||||||
"Increase only");
|
"Increase only");
|
||||||
_next_top_at_mark_start = top();
|
// Survivor regions will be scanned on the start of concurrent
|
||||||
|
// marking.
|
||||||
|
if (!is_survivor()) {
|
||||||
|
_next_top_at_mark_start = top();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns "false" iff no object in the region was allocated when the
|
// Returns "false" iff no object in the region was allocated when the
|
||||||
@ -829,7 +833,7 @@ class HeapRegionClosure : public StackObj {
|
|||||||
|
|
||||||
// A linked lists of heap regions. It leaves the "next" field
|
// A linked lists of heap regions. It leaves the "next" field
|
||||||
// unspecified; that's up to subtypes.
|
// unspecified; that's up to subtypes.
|
||||||
class RegionList {
|
class RegionList VALUE_OBJ_CLASS_SPEC {
|
||||||
protected:
|
protected:
|
||||||
virtual HeapRegion* get_next(HeapRegion* chr) = 0;
|
virtual HeapRegion* get_next(HeapRegion* chr) = 0;
|
||||||
virtual void set_next(HeapRegion* chr,
|
virtual void set_next(HeapRegion* chr,
|
||||||
|
@ -65,9 +65,11 @@ protected:
|
|||||||
// We need access in order to union things into the base table.
|
// We need access in order to union things into the base table.
|
||||||
BitMap* bm() { return &_bm; }
|
BitMap* bm() { return &_bm; }
|
||||||
|
|
||||||
|
#if PRT_COUNT_OCCUPIED
|
||||||
void recount_occupied() {
|
void recount_occupied() {
|
||||||
_occupied = (jint) bm()->count_one_bits();
|
_occupied = (jint) bm()->count_one_bits();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
PerRegionTable(HeapRegion* hr) :
|
PerRegionTable(HeapRegion* hr) :
|
||||||
_hr(hr),
|
_hr(hr),
|
||||||
@ -1144,7 +1146,9 @@ void HeapRegionRemSet::clear_outgoing_entries() {
|
|||||||
size_t i = _outgoing_region_map.get_next_one_offset(0);
|
size_t i = _outgoing_region_map.get_next_one_offset(0);
|
||||||
while (i < _outgoing_region_map.size()) {
|
while (i < _outgoing_region_map.size()) {
|
||||||
HeapRegion* to_region = g1h->region_at(i);
|
HeapRegion* to_region = g1h->region_at(i);
|
||||||
to_region->rem_set()->clear_incoming_entry(hr());
|
if (!to_region->in_collection_set()) {
|
||||||
|
to_region->rem_set()->clear_incoming_entry(hr());
|
||||||
|
}
|
||||||
i = _outgoing_region_map.get_next_one_offset(i+1);
|
i = _outgoing_region_map.get_next_one_offset(i+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ class SparsePRT;
|
|||||||
// is represented. If a deleted PRT is re-used, a thread adding a bit,
|
// is represented. If a deleted PRT is re-used, a thread adding a bit,
|
||||||
// thinking the PRT is for a different region, does no harm.
|
// thinking the PRT is for a different region, does no harm.
|
||||||
|
|
||||||
class OtherRegionsTable: public CHeapObj {
|
class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
|
||||||
friend class HeapRegionRemSetIterator;
|
friend class HeapRegionRemSetIterator;
|
||||||
|
|
||||||
G1CollectedHeap* _g1h;
|
G1CollectedHeap* _g1h;
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
class PtrQueueSet;
|
class PtrQueueSet;
|
||||||
|
|
||||||
class PtrQueue: public CHeapObj {
|
class PtrQueue VALUE_OBJ_CLASS_SPEC {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The ptr queue set to which this queue belongs.
|
// The ptr queue set to which this queue belongs.
|
||||||
@ -130,7 +130,7 @@ public:
|
|||||||
// In particular, the individual queues allocate buffers from this shared
|
// In particular, the individual queues allocate buffers from this shared
|
||||||
// set, and return completed buffers to the set.
|
// set, and return completed buffers to the set.
|
||||||
// All these variables are are protected by the TLOQ_CBL_mon. XXX ???
|
// All these variables are are protected by the TLOQ_CBL_mon. XXX ???
|
||||||
class PtrQueueSet: public CHeapObj {
|
class PtrQueueSet VALUE_OBJ_CLASS_SPEC {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
// old versions synchronously.
|
// old versions synchronously.
|
||||||
|
|
||||||
|
|
||||||
class SparsePRTEntry {
|
class SparsePRTEntry: public CHeapObj {
|
||||||
public:
|
public:
|
||||||
enum SomePublicConstants {
|
enum SomePublicConstants {
|
||||||
CardsPerEntry = (short)4,
|
CardsPerEntry = (short)4,
|
||||||
@ -167,7 +167,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ValueObj because will be embedded in HRRS iterator.
|
// ValueObj because will be embedded in HRRS iterator.
|
||||||
class RSHashTableIter: public CHeapObj {
|
class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
|
||||||
short _tbl_ind;
|
short _tbl_ind;
|
||||||
short _bl_ind;
|
short _bl_ind;
|
||||||
short _card_ind;
|
short _card_ind;
|
||||||
@ -213,7 +213,7 @@ class RSHashTableIter: public CHeapObj {
|
|||||||
|
|
||||||
class SparsePRTIter;
|
class SparsePRTIter;
|
||||||
|
|
||||||
class SparsePRT : public CHeapObj {
|
class SparsePRT VALUE_OBJ_CLASS_SPEC {
|
||||||
// Iterations are done on the _cur hash table, since they only need to
|
// Iterations are done on the _cur hash table, since they only need to
|
||||||
// see entries visible at the start of a collection pause.
|
// see entries visible at the start of a collection pause.
|
||||||
// All other operations are done using the _next hash table.
|
// All other operations are done using the _next hash table.
|
||||||
|
@ -29,23 +29,14 @@ SurvRateGroup::SurvRateGroup(G1CollectorPolicy* g1p,
|
|||||||
const char* name,
|
const char* name,
|
||||||
size_t summary_surv_rates_len) :
|
size_t summary_surv_rates_len) :
|
||||||
_g1p(g1p), _name(name),
|
_g1p(g1p), _name(name),
|
||||||
_all_regions_allocated(0),
|
|
||||||
_curr_length(0), _scan_only_prefix(0), _setup_seq_num(0),
|
|
||||||
_array_length(0), _surv_rate(NULL), _accum_surv_rate_pred(NULL),
|
|
||||||
_accum_surv_rate(0.0), _surv_rate_pred(NULL), _last_pred(0.0),
|
|
||||||
_summary_surv_rates_len(summary_surv_rates_len),
|
_summary_surv_rates_len(summary_surv_rates_len),
|
||||||
_summary_surv_rates_max_len(0),
|
_summary_surv_rates_max_len(0),
|
||||||
_summary_surv_rates(NULL) {
|
_summary_surv_rates(NULL),
|
||||||
|
_surv_rate(NULL),
|
||||||
// the following will set up the arrays with length 1
|
_accum_surv_rate_pred(NULL),
|
||||||
_curr_length = 1;
|
_surv_rate_pred(NULL)
|
||||||
stop_adding_regions();
|
{
|
||||||
guarantee( _array_length == 1, "invariant" );
|
reset();
|
||||||
guarantee( _surv_rate_pred[0] != NULL, "invariant" );
|
|
||||||
_surv_rate_pred[0]->add(0.4);
|
|
||||||
all_surviving_words_recorded(false);
|
|
||||||
_curr_length = 0;
|
|
||||||
|
|
||||||
if (summary_surv_rates_len > 0) {
|
if (summary_surv_rates_len > 0) {
|
||||||
size_t length = summary_surv_rates_len;
|
size_t length = summary_surv_rates_len;
|
||||||
_summary_surv_rates = NEW_C_HEAP_ARRAY(NumberSeq*, length);
|
_summary_surv_rates = NEW_C_HEAP_ARRAY(NumberSeq*, length);
|
||||||
@ -60,61 +51,80 @@ SurvRateGroup::SurvRateGroup(G1CollectorPolicy* g1p,
|
|||||||
start_adding_regions();
|
start_adding_regions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SurvRateGroup::reset()
|
||||||
|
{
|
||||||
|
_all_regions_allocated = 0;
|
||||||
|
_scan_only_prefix = 0;
|
||||||
|
_setup_seq_num = 0;
|
||||||
|
_stats_arrays_length = 0;
|
||||||
|
_accum_surv_rate = 0.0;
|
||||||
|
_last_pred = 0.0;
|
||||||
|
// the following will set up the arrays with length 1
|
||||||
|
_region_num = 1;
|
||||||
|
stop_adding_regions();
|
||||||
|
guarantee( _stats_arrays_length == 1, "invariant" );
|
||||||
|
guarantee( _surv_rate_pred[0] != NULL, "invariant" );
|
||||||
|
_surv_rate_pred[0]->add(0.4);
|
||||||
|
all_surviving_words_recorded(false);
|
||||||
|
_region_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SurvRateGroup::start_adding_regions() {
|
SurvRateGroup::start_adding_regions() {
|
||||||
_setup_seq_num = _array_length;
|
_setup_seq_num = _stats_arrays_length;
|
||||||
_curr_length = _scan_only_prefix;
|
_region_num = _scan_only_prefix;
|
||||||
_accum_surv_rate = 0.0;
|
_accum_surv_rate = 0.0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
gclog_or_tty->print_cr("start adding regions, seq num %d, length %d",
|
gclog_or_tty->print_cr("[%s] start adding regions, seq num %d, length %d",
|
||||||
_setup_seq_num, _curr_length);
|
_name, _setup_seq_num, _region_num);
|
||||||
#endif // 0
|
#endif // 0
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SurvRateGroup::stop_adding_regions() {
|
SurvRateGroup::stop_adding_regions() {
|
||||||
size_t length = _curr_length;
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
gclog_or_tty->print_cr("stop adding regions, length %d", length);
|
gclog_or_tty->print_cr("[%s] stop adding regions, length %d", _name, _region_num);
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
if (length > _array_length) {
|
if (_region_num > _stats_arrays_length) {
|
||||||
double* old_surv_rate = _surv_rate;
|
double* old_surv_rate = _surv_rate;
|
||||||
double* old_accum_surv_rate_pred = _accum_surv_rate_pred;
|
double* old_accum_surv_rate_pred = _accum_surv_rate_pred;
|
||||||
TruncatedSeq** old_surv_rate_pred = _surv_rate_pred;
|
TruncatedSeq** old_surv_rate_pred = _surv_rate_pred;
|
||||||
|
|
||||||
_surv_rate = NEW_C_HEAP_ARRAY(double, length);
|
_surv_rate = NEW_C_HEAP_ARRAY(double, _region_num);
|
||||||
if (_surv_rate == NULL) {
|
if (_surv_rate == NULL) {
|
||||||
vm_exit_out_of_memory(sizeof(double) * length,
|
vm_exit_out_of_memory(sizeof(double) * _region_num,
|
||||||
"Not enough space for surv rate array.");
|
"Not enough space for surv rate array.");
|
||||||
}
|
}
|
||||||
_accum_surv_rate_pred = NEW_C_HEAP_ARRAY(double, length);
|
_accum_surv_rate_pred = NEW_C_HEAP_ARRAY(double, _region_num);
|
||||||
if (_accum_surv_rate_pred == NULL) {
|
if (_accum_surv_rate_pred == NULL) {
|
||||||
vm_exit_out_of_memory(sizeof(double) * length,
|
vm_exit_out_of_memory(sizeof(double) * _region_num,
|
||||||
"Not enough space for accum surv rate pred array.");
|
"Not enough space for accum surv rate pred array.");
|
||||||
}
|
}
|
||||||
_surv_rate_pred = NEW_C_HEAP_ARRAY(TruncatedSeq*, length);
|
_surv_rate_pred = NEW_C_HEAP_ARRAY(TruncatedSeq*, _region_num);
|
||||||
if (_surv_rate == NULL) {
|
if (_surv_rate == NULL) {
|
||||||
vm_exit_out_of_memory(sizeof(TruncatedSeq*) * length,
|
vm_exit_out_of_memory(sizeof(TruncatedSeq*) * _region_num,
|
||||||
"Not enough space for surv rate pred array.");
|
"Not enough space for surv rate pred array.");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < _array_length; ++i)
|
for (size_t i = 0; i < _stats_arrays_length; ++i)
|
||||||
_surv_rate_pred[i] = old_surv_rate_pred[i];
|
_surv_rate_pred[i] = old_surv_rate_pred[i];
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
gclog_or_tty->print_cr("stop adding regions, new seqs %d to %d",
|
gclog_or_tty->print_cr("[%s] stop adding regions, new seqs %d to %d",
|
||||||
_array_length, length - 1);
|
_name, _array_length, _region_num - 1);
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
for (size_t i = _array_length; i < length; ++i) {
|
for (size_t i = _stats_arrays_length; i < _region_num; ++i) {
|
||||||
_surv_rate_pred[i] = new TruncatedSeq(10);
|
_surv_rate_pred[i] = new TruncatedSeq(10);
|
||||||
// _surv_rate_pred[i]->add(last_pred);
|
// _surv_rate_pred[i]->add(last_pred);
|
||||||
}
|
}
|
||||||
|
|
||||||
_array_length = length;
|
_stats_arrays_length = _region_num;
|
||||||
|
|
||||||
if (old_surv_rate != NULL)
|
if (old_surv_rate != NULL)
|
||||||
FREE_C_HEAP_ARRAY(double, old_surv_rate);
|
FREE_C_HEAP_ARRAY(double, old_surv_rate);
|
||||||
@ -124,7 +134,7 @@ SurvRateGroup::stop_adding_regions() {
|
|||||||
FREE_C_HEAP_ARRAY(NumberSeq*, old_surv_rate_pred);
|
FREE_C_HEAP_ARRAY(NumberSeq*, old_surv_rate_pred);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < _array_length; ++i)
|
for (size_t i = 0; i < _stats_arrays_length; ++i)
|
||||||
_surv_rate[i] = 0.0;
|
_surv_rate[i] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +145,7 @@ SurvRateGroup::accum_surv_rate(size_t adjustment) {
|
|||||||
|
|
||||||
double ret = _accum_surv_rate;
|
double ret = _accum_surv_rate;
|
||||||
if (adjustment > 0) {
|
if (adjustment > 0) {
|
||||||
TruncatedSeq* seq = get_seq(_curr_length+1);
|
TruncatedSeq* seq = get_seq(_region_num+1);
|
||||||
double surv_rate = _g1p->get_new_prediction(seq);
|
double surv_rate = _g1p->get_new_prediction(seq);
|
||||||
ret += surv_rate;
|
ret += surv_rate;
|
||||||
}
|
}
|
||||||
@ -145,23 +155,23 @@ SurvRateGroup::accum_surv_rate(size_t adjustment) {
|
|||||||
|
|
||||||
int
|
int
|
||||||
SurvRateGroup::next_age_index() {
|
SurvRateGroup::next_age_index() {
|
||||||
TruncatedSeq* seq = get_seq(_curr_length);
|
TruncatedSeq* seq = get_seq(_region_num);
|
||||||
double surv_rate = _g1p->get_new_prediction(seq);
|
double surv_rate = _g1p->get_new_prediction(seq);
|
||||||
_accum_surv_rate += surv_rate;
|
_accum_surv_rate += surv_rate;
|
||||||
|
|
||||||
++_curr_length;
|
++_region_num;
|
||||||
return (int) ++_all_regions_allocated;
|
return (int) ++_all_regions_allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SurvRateGroup::record_scan_only_prefix(size_t scan_only_prefix) {
|
SurvRateGroup::record_scan_only_prefix(size_t scan_only_prefix) {
|
||||||
guarantee( scan_only_prefix <= _curr_length, "pre-condition" );
|
guarantee( scan_only_prefix <= _region_num, "pre-condition" );
|
||||||
_scan_only_prefix = scan_only_prefix;
|
_scan_only_prefix = scan_only_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
|
SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
|
||||||
guarantee( 0 <= age_in_group && (size_t) age_in_group < _curr_length,
|
guarantee( 0 <= age_in_group && (size_t) age_in_group < _region_num,
|
||||||
"pre-condition" );
|
"pre-condition" );
|
||||||
guarantee( _surv_rate[age_in_group] <= 0.00001,
|
guarantee( _surv_rate[age_in_group] <= 0.00001,
|
||||||
"should only update each slot once" );
|
"should only update each slot once" );
|
||||||
@ -178,15 +188,15 @@ SurvRateGroup::record_surviving_words(int age_in_group, size_t surv_words) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
SurvRateGroup::all_surviving_words_recorded(bool propagate) {
|
SurvRateGroup::all_surviving_words_recorded(bool propagate) {
|
||||||
if (propagate && _curr_length > 0) { // conservative
|
if (propagate && _region_num > 0) { // conservative
|
||||||
double surv_rate = _surv_rate_pred[_curr_length-1]->last();
|
double surv_rate = _surv_rate_pred[_region_num-1]->last();
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
gclog_or_tty->print_cr("propagating %1.2lf from %d to %d",
|
gclog_or_tty->print_cr("propagating %1.2lf from %d to %d",
|
||||||
surv_rate, _curr_length, _array_length - 1);
|
surv_rate, _curr_length, _array_length - 1);
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
for (size_t i = _curr_length; i < _array_length; ++i) {
|
for (size_t i = _region_num; i < _stats_arrays_length; ++i) {
|
||||||
guarantee( _surv_rate[i] <= 0.00001,
|
guarantee( _surv_rate[i] <= 0.00001,
|
||||||
"the slot should not have been updated" );
|
"the slot should not have been updated" );
|
||||||
_surv_rate_pred[i]->add(surv_rate);
|
_surv_rate_pred[i]->add(surv_rate);
|
||||||
@ -195,7 +205,7 @@ SurvRateGroup::all_surviving_words_recorded(bool propagate) {
|
|||||||
|
|
||||||
double accum = 0.0;
|
double accum = 0.0;
|
||||||
double pred = 0.0;
|
double pred = 0.0;
|
||||||
for (size_t i = 0; i < _array_length; ++i) {
|
for (size_t i = 0; i < _stats_arrays_length; ++i) {
|
||||||
pred = _g1p->get_new_prediction(_surv_rate_pred[i]);
|
pred = _g1p->get_new_prediction(_surv_rate_pred[i]);
|
||||||
if (pred > 1.0) pred = 1.0;
|
if (pred > 1.0) pred = 1.0;
|
||||||
accum += pred;
|
accum += pred;
|
||||||
@ -209,8 +219,8 @@ SurvRateGroup::all_surviving_words_recorded(bool propagate) {
|
|||||||
void
|
void
|
||||||
SurvRateGroup::print() {
|
SurvRateGroup::print() {
|
||||||
gclog_or_tty->print_cr("Surv Rate Group: %s (%d entries, %d scan-only)",
|
gclog_or_tty->print_cr("Surv Rate Group: %s (%d entries, %d scan-only)",
|
||||||
_name, _curr_length, _scan_only_prefix);
|
_name, _region_num, _scan_only_prefix);
|
||||||
for (size_t i = 0; i < _curr_length; ++i) {
|
for (size_t i = 0; i < _region_num; ++i) {
|
||||||
gclog_or_tty->print_cr(" age %4d surv rate %6.2lf %% pred %6.2lf %%%s",
|
gclog_or_tty->print_cr(" age %4d surv rate %6.2lf %% pred %6.2lf %%%s",
|
||||||
i, _surv_rate[i] * 100.0,
|
i, _surv_rate[i] * 100.0,
|
||||||
_g1p->get_new_prediction(_surv_rate_pred[i]) * 100.0,
|
_g1p->get_new_prediction(_surv_rate_pred[i]) * 100.0,
|
||||||
|
@ -29,7 +29,7 @@ private:
|
|||||||
G1CollectorPolicy* _g1p;
|
G1CollectorPolicy* _g1p;
|
||||||
const char* _name;
|
const char* _name;
|
||||||
|
|
||||||
size_t _array_length;
|
size_t _stats_arrays_length;
|
||||||
double* _surv_rate;
|
double* _surv_rate;
|
||||||
double* _accum_surv_rate_pred;
|
double* _accum_surv_rate_pred;
|
||||||
double _last_pred;
|
double _last_pred;
|
||||||
@ -40,7 +40,7 @@ private:
|
|||||||
size_t _summary_surv_rates_max_len;
|
size_t _summary_surv_rates_max_len;
|
||||||
|
|
||||||
int _all_regions_allocated;
|
int _all_regions_allocated;
|
||||||
size_t _curr_length;
|
size_t _region_num;
|
||||||
size_t _scan_only_prefix;
|
size_t _scan_only_prefix;
|
||||||
size_t _setup_seq_num;
|
size_t _setup_seq_num;
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ public:
|
|||||||
SurvRateGroup(G1CollectorPolicy* g1p,
|
SurvRateGroup(G1CollectorPolicy* g1p,
|
||||||
const char* name,
|
const char* name,
|
||||||
size_t summary_surv_rates_len);
|
size_t summary_surv_rates_len);
|
||||||
|
void reset();
|
||||||
void start_adding_regions();
|
void start_adding_regions();
|
||||||
void stop_adding_regions();
|
void stop_adding_regions();
|
||||||
void record_scan_only_prefix(size_t scan_only_prefix);
|
void record_scan_only_prefix(size_t scan_only_prefix);
|
||||||
@ -55,22 +56,21 @@ public:
|
|||||||
void all_surviving_words_recorded(bool propagate);
|
void all_surviving_words_recorded(bool propagate);
|
||||||
const char* name() { return _name; }
|
const char* name() { return _name; }
|
||||||
|
|
||||||
size_t region_num() { return _curr_length; }
|
size_t region_num() { return _region_num; }
|
||||||
size_t scan_only_length() { return _scan_only_prefix; }
|
size_t scan_only_length() { return _scan_only_prefix; }
|
||||||
double accum_surv_rate_pred(int age) {
|
double accum_surv_rate_pred(int age) {
|
||||||
assert(age >= 0, "must be");
|
assert(age >= 0, "must be");
|
||||||
if ((size_t)age < _array_length)
|
if ((size_t)age < _stats_arrays_length)
|
||||||
return _accum_surv_rate_pred[age];
|
return _accum_surv_rate_pred[age];
|
||||||
else {
|
else {
|
||||||
double diff = (double) (age - _array_length + 1);
|
double diff = (double) (age - _stats_arrays_length + 1);
|
||||||
return _accum_surv_rate_pred[_array_length-1] + diff * _last_pred;
|
return _accum_surv_rate_pred[_stats_arrays_length-1] + diff * _last_pred;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double accum_surv_rate(size_t adjustment);
|
double accum_surv_rate(size_t adjustment);
|
||||||
|
|
||||||
TruncatedSeq* get_seq(size_t age) {
|
TruncatedSeq* get_seq(size_t age) {
|
||||||
guarantee( 0 <= age, "pre-condition" );
|
|
||||||
if (age >= _setup_seq_num) {
|
if (age >= _setup_seq_num) {
|
||||||
guarantee( _setup_seq_num > 0, "invariant" );
|
guarantee( _setup_seq_num > 0, "invariant" );
|
||||||
age = _setup_seq_num-1;
|
age = _setup_seq_num-1;
|
||||||
|
@ -48,6 +48,7 @@ concurrentG1Refine.cpp g1RemSet.hpp
|
|||||||
concurrentG1Refine.cpp space.inline.hpp
|
concurrentG1Refine.cpp space.inline.hpp
|
||||||
|
|
||||||
concurrentG1Refine.hpp globalDefinitions.hpp
|
concurrentG1Refine.hpp globalDefinitions.hpp
|
||||||
|
concurrentG1Refine.hpp allocation.hpp
|
||||||
|
|
||||||
concurrentG1RefineThread.cpp concurrentG1Refine.hpp
|
concurrentG1RefineThread.cpp concurrentG1Refine.hpp
|
||||||
concurrentG1RefineThread.cpp concurrentG1RefineThread.hpp
|
concurrentG1RefineThread.cpp concurrentG1RefineThread.hpp
|
||||||
@ -172,6 +173,7 @@ g1CollectorPolicy.cpp g1CollectedHeap.inline.hpp
|
|||||||
g1CollectorPolicy.cpp g1CollectorPolicy.hpp
|
g1CollectorPolicy.cpp g1CollectorPolicy.hpp
|
||||||
g1CollectorPolicy.cpp heapRegionRemSet.hpp
|
g1CollectorPolicy.cpp heapRegionRemSet.hpp
|
||||||
g1CollectorPolicy.cpp mutexLocker.hpp
|
g1CollectorPolicy.cpp mutexLocker.hpp
|
||||||
|
g1CollectorPolicy.cpp gcPolicyCounters.hpp
|
||||||
|
|
||||||
g1CollectorPolicy.hpp collectorPolicy.hpp
|
g1CollectorPolicy.hpp collectorPolicy.hpp
|
||||||
g1CollectorPolicy.hpp collectionSetChooser.hpp
|
g1CollectorPolicy.hpp collectionSetChooser.hpp
|
||||||
@ -228,7 +230,7 @@ g1MMUTracker.cpp ostream.hpp
|
|||||||
g1MMUTracker.cpp mutexLocker.hpp
|
g1MMUTracker.cpp mutexLocker.hpp
|
||||||
|
|
||||||
g1MMUTracker.hpp debug.hpp
|
g1MMUTracker.hpp debug.hpp
|
||||||
|
g1MMUTracker.hpp allocation.hpp
|
||||||
g1RemSet.cpp bufferingOopClosure.hpp
|
g1RemSet.cpp bufferingOopClosure.hpp
|
||||||
g1RemSet.cpp concurrentG1Refine.hpp
|
g1RemSet.cpp concurrentG1Refine.hpp
|
||||||
g1RemSet.cpp concurrentG1RefineThread.hpp
|
g1RemSet.cpp concurrentG1RefineThread.hpp
|
||||||
@ -272,6 +274,7 @@ heapRegion.hpp g1BlockOffsetTable.inline.hpp
|
|||||||
heapRegion.hpp watermark.hpp
|
heapRegion.hpp watermark.hpp
|
||||||
heapRegion.hpp g1_specialized_oop_closures.hpp
|
heapRegion.hpp g1_specialized_oop_closures.hpp
|
||||||
heapRegion.hpp survRateGroup.hpp
|
heapRegion.hpp survRateGroup.hpp
|
||||||
|
heapRegion.hpp ageTable.hpp
|
||||||
|
|
||||||
heapRegionRemSet.hpp sparsePRT.hpp
|
heapRegionRemSet.hpp sparsePRT.hpp
|
||||||
|
|
||||||
|
@ -362,6 +362,10 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
|
|||||||
if (PrintHeapAtGC) {
|
if (PrintHeapAtGC) {
|
||||||
Universe::print_heap_after_gc();
|
Universe::print_heap_after_gc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
ParallelTaskTerminator::print_termination_counts();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy,
|
bool PSMarkSweep::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy,
|
||||||
|
@ -2203,6 +2203,10 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
|
|||||||
collection_exit.ticks());
|
collection_exit.ticks());
|
||||||
gc_task_manager()->print_task_time_stamps();
|
gc_task_manager()->print_task_time_stamps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
ParallelTaskTerminator::print_termination_counts();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PSParallelCompact::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy,
|
bool PSParallelCompact::absorb_live_data_from_eden(PSAdaptiveSizePolicy* size_policy,
|
||||||
|
@ -615,6 +615,10 @@ bool PSScavenge::invoke_no_policy() {
|
|||||||
gc_task_manager()->print_task_time_stamps();
|
gc_task_manager()->print_task_time_stamps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
ParallelTaskTerminator::print_termination_counts();
|
||||||
|
#endif
|
||||||
|
|
||||||
return !promotion_failure_occurred;
|
return !promotion_failure_occurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,12 @@ void ageTable::merge(ageTable* subTable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ageTable::merge_par(ageTable* subTable) {
|
||||||
|
for (int i = 0; i < table_size; i++) {
|
||||||
|
Atomic::add_ptr(subTable->sizes[i], &sizes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
|
int ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
|
||||||
size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
|
size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
|
@ -56,6 +56,7 @@ class ageTable VALUE_OBJ_CLASS_SPEC {
|
|||||||
// Merge another age table with the current one. Used
|
// Merge another age table with the current one. Used
|
||||||
// for parallel young generation gc.
|
// for parallel young generation gc.
|
||||||
void merge(ageTable* subTable);
|
void merge(ageTable* subTable);
|
||||||
|
void merge_par(ageTable* subTable);
|
||||||
|
|
||||||
// calculate new tenuring threshold based on age information
|
// calculate new tenuring threshold based on age information
|
||||||
int compute_tenuring_threshold(size_t survivor_capacity);
|
int compute_tenuring_threshold(size_t survivor_capacity);
|
||||||
|
@ -42,6 +42,7 @@ class Thread;
|
|||||||
class CollectedHeap : public CHeapObj {
|
class CollectedHeap : public CHeapObj {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
friend class IsGCActiveMark; // Block structured external access to _is_gc_active
|
friend class IsGCActiveMark; // Block structured external access to _is_gc_active
|
||||||
|
friend class constantPoolCacheKlass; // allocate() method inserts is_conc_safe
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
static int _fire_out_of_memory_count;
|
static int _fire_out_of_memory_count;
|
||||||
@ -82,8 +83,6 @@ class CollectedHeap : public CHeapObj {
|
|||||||
// Reinitialize tlabs before resuming mutators.
|
// Reinitialize tlabs before resuming mutators.
|
||||||
virtual void resize_all_tlabs();
|
virtual void resize_all_tlabs();
|
||||||
|
|
||||||
debug_only(static void check_for_valid_allocation_state();)
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Allocate from the current thread's TLAB, with broken-out slow path.
|
// Allocate from the current thread's TLAB, with broken-out slow path.
|
||||||
inline static HeapWord* allocate_from_tlab(Thread* thread, size_t size);
|
inline static HeapWord* allocate_from_tlab(Thread* thread, size_t size);
|
||||||
@ -142,6 +141,7 @@ class CollectedHeap : public CHeapObj {
|
|||||||
PRODUCT_RETURN;
|
PRODUCT_RETURN;
|
||||||
virtual void check_for_non_bad_heap_word_value(HeapWord* addr, size_t size)
|
virtual void check_for_non_bad_heap_word_value(HeapWord* addr, size_t size)
|
||||||
PRODUCT_RETURN;
|
PRODUCT_RETURN;
|
||||||
|
debug_only(static void check_for_valid_allocation_state();)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Name {
|
enum Name {
|
||||||
|
@ -48,9 +48,14 @@ void Rewriter::compute_index_maps(constantPoolHandle pool, intArray*& index_map,
|
|||||||
|
|
||||||
|
|
||||||
// Creates a constant pool cache given an inverse_index_map
|
// Creates a constant pool cache given an inverse_index_map
|
||||||
|
// This creates the constant pool cache initially in a state
|
||||||
|
// that is unsafe for concurrent GC processing but sets it to
|
||||||
|
// a safe mode before the constant pool cache is returned.
|
||||||
constantPoolCacheHandle Rewriter::new_constant_pool_cache(intArray& inverse_index_map, TRAPS) {
|
constantPoolCacheHandle Rewriter::new_constant_pool_cache(intArray& inverse_index_map, TRAPS) {
|
||||||
const int length = inverse_index_map.length();
|
const int length = inverse_index_map.length();
|
||||||
constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length, CHECK_(constantPoolCacheHandle()));
|
constantPoolCacheOop cache = oopFactory::new_constantPoolCache(length,
|
||||||
|
methodOopDesc::IsUnsafeConc,
|
||||||
|
CHECK_(constantPoolCacheHandle()));
|
||||||
cache->initialize(inverse_index_map);
|
cache->initialize(inverse_index_map);
|
||||||
return constantPoolCacheHandle(THREAD, cache);
|
return constantPoolCacheHandle(THREAD, cache);
|
||||||
}
|
}
|
||||||
|
@ -346,9 +346,12 @@ int32 cmpstr(const void *k1, const void *k2) {
|
|||||||
return strcmp((const char *)k1,(const char *)k2);
|
return strcmp((const char *)k1,(const char *)k2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slimey cheap key comparator.
|
// Cheap key comparator.
|
||||||
int32 cmpkey(const void *key1, const void *key2) {
|
int32 cmpkey(const void *key1, const void *key2) {
|
||||||
return (int32)((intptr_t)key1 - (intptr_t)key2);
|
if (key1 == key2) return 0;
|
||||||
|
intptr_t delta = (intptr_t)key1 - (intptr_t)key2;
|
||||||
|
if (delta > 0) return 1;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -610,6 +610,10 @@ void GenCollectedHeap::do_collection(bool full,
|
|||||||
Universe::print_heap_after_gc();
|
Universe::print_heap_after_gc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
ParallelTaskTerminator::print_termination_counts();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (ExitAfterGCNum > 0 && total_collections() == ExitAfterGCNum) {
|
if (ExitAfterGCNum > 0 && total_collections() == ExitAfterGCNum) {
|
||||||
tty->print_cr("Stopping after GC #%d", ExitAfterGCNum);
|
tty->print_cr("Stopping after GC #%d", ExitAfterGCNum);
|
||||||
vm_exit(-1);
|
vm_exit(-1);
|
||||||
|
@ -90,9 +90,11 @@ constantPoolOop oopFactory::new_constantPool(int length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constantPoolCacheOop oopFactory::new_constantPoolCache(int length, TRAPS) {
|
constantPoolCacheOop oopFactory::new_constantPoolCache(int length,
|
||||||
|
bool is_conc_safe,
|
||||||
|
TRAPS) {
|
||||||
constantPoolCacheKlass* ck = constantPoolCacheKlass::cast(Universe::constantPoolCacheKlassObj());
|
constantPoolCacheKlass* ck = constantPoolCacheKlass::cast(Universe::constantPoolCacheKlassObj());
|
||||||
return ck->allocate(length, CHECK_NULL);
|
return ck->allocate(length, is_conc_safe, CHECK_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,7 +84,9 @@ class oopFactory: AllStatic {
|
|||||||
static constantPoolOop new_constantPool (int length,
|
static constantPoolOop new_constantPool (int length,
|
||||||
bool is_conc_safe,
|
bool is_conc_safe,
|
||||||
TRAPS);
|
TRAPS);
|
||||||
static constantPoolCacheOop new_constantPoolCache(int length, TRAPS);
|
static constantPoolCacheOop new_constantPoolCache(int length,
|
||||||
|
bool is_conc_safe,
|
||||||
|
TRAPS);
|
||||||
|
|
||||||
// Instance classes
|
// Instance classes
|
||||||
static klassOop new_instanceKlass(int vtable_len, int itable_len, int static_field_size,
|
static klassOop new_instanceKlass(int vtable_len, int itable_len, int static_field_size,
|
||||||
|
@ -32,13 +32,43 @@ int constantPoolCacheKlass::oop_size(oop obj) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constantPoolCacheOop constantPoolCacheKlass::allocate(int length, TRAPS) {
|
constantPoolCacheOop constantPoolCacheKlass::allocate(int length,
|
||||||
|
bool is_conc_safe,
|
||||||
|
TRAPS) {
|
||||||
// allocate memory
|
// allocate memory
|
||||||
int size = constantPoolCacheOopDesc::object_size(length);
|
int size = constantPoolCacheOopDesc::object_size(length);
|
||||||
|
|
||||||
KlassHandle klass (THREAD, as_klassOop());
|
KlassHandle klass (THREAD, as_klassOop());
|
||||||
constantPoolCacheOop cache = (constantPoolCacheOop)
|
|
||||||
CollectedHeap::permanent_obj_allocate(klass, size, CHECK_NULL);
|
// This is the original code. The code from permanent_obj_allocate()
|
||||||
|
// was in-lined to allow the setting of is_conc_safe before the klass
|
||||||
|
// is installed.
|
||||||
|
// constantPoolCacheOop cache = (constantPoolCacheOop)
|
||||||
|
// CollectedHeap::permanent_obj_allocate(klass, size, CHECK_NULL);
|
||||||
|
|
||||||
|
oop obj = CollectedHeap::permanent_obj_allocate_no_klass_install(klass, size, CHECK_NULL);
|
||||||
|
constantPoolCacheOop cache = (constantPoolCacheOop) obj;
|
||||||
|
cache->set_is_conc_safe(is_conc_safe);
|
||||||
|
// The store to is_conc_safe must be visible before the klass
|
||||||
|
// is set. This should be done safely because _is_conc_safe has
|
||||||
|
// been declared volatile. If there are any problems, consider adding
|
||||||
|
// OrderAccess::storestore();
|
||||||
|
CollectedHeap::post_allocation_install_obj_klass(klass, obj, size);
|
||||||
|
NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value((HeapWord*) obj,
|
||||||
|
size));
|
||||||
|
|
||||||
|
// The length field affects the size of the object. The allocation
|
||||||
|
// above allocates the correct size (see calculation of "size") but
|
||||||
|
// the size() method of the constant pool cache oop will not reflect
|
||||||
|
// that size until the correct length is set.
|
||||||
cache->set_length(length);
|
cache->set_length(length);
|
||||||
|
|
||||||
|
// The store of the length must be visible before is_conc_safe is
|
||||||
|
// set to a safe state.
|
||||||
|
// This should be done safely because _is_conc_safe has
|
||||||
|
// been declared volatile. If there are any problems, consider adding
|
||||||
|
// OrderAccess::storestore();
|
||||||
|
cache->set_is_conc_safe(methodOopDesc::IsSafeConc);
|
||||||
cache->set_constant_pool(NULL);
|
cache->set_constant_pool(NULL);
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
@ -114,7 +144,6 @@ int constantPoolCacheKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegio
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int constantPoolCacheKlass::oop_adjust_pointers(oop obj) {
|
int constantPoolCacheKlass::oop_adjust_pointers(oop obj) {
|
||||||
assert(obj->is_constantPoolCache(), "obj must be constant pool cache");
|
assert(obj->is_constantPoolCache(), "obj must be constant pool cache");
|
||||||
constantPoolCacheOop cache = (constantPoolCacheOop)obj;
|
constantPoolCacheOop cache = (constantPoolCacheOop)obj;
|
||||||
@ -131,6 +160,11 @@ int constantPoolCacheKlass::oop_adjust_pointers(oop obj) {
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool constantPoolCacheKlass::oop_is_conc_safe(oop obj) const {
|
||||||
|
assert(obj->is_constantPoolCache(), "should be constant pool");
|
||||||
|
return constantPoolCacheOop(obj)->is_conc_safe();
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef SERIALGC
|
#ifndef SERIALGC
|
||||||
void constantPoolCacheKlass::oop_copy_contents(PSPromotionManager* pm,
|
void constantPoolCacheKlass::oop_copy_contents(PSPromotionManager* pm,
|
||||||
oop obj) {
|
oop obj) {
|
||||||
|
@ -32,7 +32,7 @@ class constantPoolCacheKlass: public Klass {
|
|||||||
|
|
||||||
// Allocation
|
// Allocation
|
||||||
DEFINE_ALLOCATE_PERMANENT(constantPoolCacheKlass);
|
DEFINE_ALLOCATE_PERMANENT(constantPoolCacheKlass);
|
||||||
constantPoolCacheOop allocate(int length, TRAPS);
|
constantPoolCacheOop allocate(int length, bool is_conc_safe, TRAPS);
|
||||||
static klassOop create_klass(TRAPS);
|
static klassOop create_klass(TRAPS);
|
||||||
|
|
||||||
// Casting from klassOop
|
// Casting from klassOop
|
||||||
@ -48,6 +48,7 @@ class constantPoolCacheKlass: public Klass {
|
|||||||
// Garbage collection
|
// Garbage collection
|
||||||
void oop_follow_contents(oop obj);
|
void oop_follow_contents(oop obj);
|
||||||
int oop_adjust_pointers(oop obj);
|
int oop_adjust_pointers(oop obj);
|
||||||
|
virtual bool oop_is_conc_safe(oop obj) const;
|
||||||
|
|
||||||
// Parallel Scavenge and Parallel Old
|
// Parallel Scavenge and Parallel Old
|
||||||
PARALLEL_GC_DECLS
|
PARALLEL_GC_DECLS
|
||||||
|
@ -291,6 +291,9 @@ class constantPoolCacheOopDesc: public oopDesc {
|
|||||||
private:
|
private:
|
||||||
int _length;
|
int _length;
|
||||||
constantPoolOop _constant_pool; // the corresponding constant pool
|
constantPoolOop _constant_pool; // the corresponding constant pool
|
||||||
|
// If true, safe for concurrent GC processing,
|
||||||
|
// Set unconditionally in constantPoolCacheKlass::allocate()
|
||||||
|
volatile bool _is_conc_safe;
|
||||||
|
|
||||||
// Sizing
|
// Sizing
|
||||||
debug_only(friend class ClassVerifier;)
|
debug_only(friend class ClassVerifier;)
|
||||||
@ -316,6 +319,12 @@ class constantPoolCacheOopDesc: public oopDesc {
|
|||||||
constantPoolOop constant_pool() const { return _constant_pool; }
|
constantPoolOop constant_pool() const { return _constant_pool; }
|
||||||
ConstantPoolCacheEntry* entry_at(int i) const { assert(0 <= i && i < length(), "index out of bounds"); return base() + i; }
|
ConstantPoolCacheEntry* entry_at(int i) const { assert(0 <= i && i < length(), "index out of bounds"); return base() + i; }
|
||||||
|
|
||||||
|
// GC support
|
||||||
|
// If the _length field has not been set, the size of the
|
||||||
|
// constantPoolCache cannot be correctly calculated.
|
||||||
|
bool is_conc_safe() { return _is_conc_safe; }
|
||||||
|
void set_is_conc_safe(bool v) { _is_conc_safe = v; }
|
||||||
|
|
||||||
// Code generation
|
// Code generation
|
||||||
static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); }
|
static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); }
|
||||||
|
|
||||||
|
@ -880,6 +880,7 @@ void PhaseCFG::dump_headers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PhaseCFG::verify( ) const {
|
void PhaseCFG::verify( ) const {
|
||||||
|
#ifdef ASSERT
|
||||||
// Verify sane CFG
|
// Verify sane CFG
|
||||||
for( uint i = 0; i < _num_blocks; i++ ) {
|
for( uint i = 0; i < _num_blocks; i++ ) {
|
||||||
Block *b = _blocks[i];
|
Block *b = _blocks[i];
|
||||||
@ -894,10 +895,20 @@ void PhaseCFG::verify( ) const {
|
|||||||
"CreateEx must be first instruction in block" );
|
"CreateEx must be first instruction in block" );
|
||||||
}
|
}
|
||||||
for( uint k = 0; k < n->req(); k++ ) {
|
for( uint k = 0; k < n->req(); k++ ) {
|
||||||
Node *use = n->in(k);
|
Node *def = n->in(k);
|
||||||
if( use && use != n ) {
|
if( def && def != n ) {
|
||||||
assert( _bbs[use->_idx] || use->is_Con(),
|
assert( _bbs[def->_idx] || def->is_Con(),
|
||||||
"must have block; constants for debug info ok" );
|
"must have block; constants for debug info ok" );
|
||||||
|
// Verify that instructions in the block is in correct order.
|
||||||
|
// Uses must follow their definition if they are at the same block.
|
||||||
|
// Mostly done to check that MachSpillCopy nodes are placed correctly
|
||||||
|
// when CreateEx node is moved in build_ifg_physical().
|
||||||
|
if( _bbs[def->_idx] == b &&
|
||||||
|
!(b->head()->is_Loop() && n->is_Phi()) &&
|
||||||
|
// See (+++) comment in reg_split.cpp
|
||||||
|
!(n->jvms() != NULL && n->jvms()->is_monitor_use(k)) ) {
|
||||||
|
assert( b->find_node(def) < j, "uses must follow definitions" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -914,6 +925,7 @@ void PhaseCFG::verify( ) const {
|
|||||||
assert( b->_num_succs == 2, "Conditional branch must have two targets");
|
assert( b->_num_succs == 2, "Conditional branch must have two targets");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -191,6 +191,9 @@
|
|||||||
notproduct(bool, VerifyHashTableKeys, true, \
|
notproduct(bool, VerifyHashTableKeys, true, \
|
||||||
"Verify the immutability of keys in the VN hash tables") \
|
"Verify the immutability of keys in the VN hash tables") \
|
||||||
\
|
\
|
||||||
|
notproduct(bool, VerifyRegisterAllocator , false, \
|
||||||
|
"Verify Register Allocator") \
|
||||||
|
\
|
||||||
develop_pd(intx, FLOATPRESSURE, \
|
develop_pd(intx, FLOATPRESSURE, \
|
||||||
"Number of float LRG's that constitute high register pressure") \
|
"Number of float LRG's that constitute high register pressure") \
|
||||||
\
|
\
|
||||||
|
@ -858,12 +858,18 @@ const Type *PhiNode::Value( PhaseTransform *phase ) const {
|
|||||||
// convert the one to the other.
|
// convert the one to the other.
|
||||||
const TypePtr* ttp = _type->make_ptr();
|
const TypePtr* ttp = _type->make_ptr();
|
||||||
const TypeInstPtr* ttip = (ttp != NULL) ? ttp->isa_instptr() : NULL;
|
const TypeInstPtr* ttip = (ttp != NULL) ? ttp->isa_instptr() : NULL;
|
||||||
|
const TypeKlassPtr* ttkp = (ttp != NULL) ? ttp->isa_klassptr() : NULL;
|
||||||
bool is_intf = false;
|
bool is_intf = false;
|
||||||
if (ttip != NULL) {
|
if (ttip != NULL) {
|
||||||
ciKlass* k = ttip->klass();
|
ciKlass* k = ttip->klass();
|
||||||
if (k->is_loaded() && k->is_interface())
|
if (k->is_loaded() && k->is_interface())
|
||||||
is_intf = true;
|
is_intf = true;
|
||||||
}
|
}
|
||||||
|
if (ttkp != NULL) {
|
||||||
|
ciKlass* k = ttkp->klass();
|
||||||
|
if (k->is_loaded() && k->is_interface())
|
||||||
|
is_intf = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Default case: merge all inputs
|
// Default case: merge all inputs
|
||||||
const Type *t = Type::TOP; // Merged type starting value
|
const Type *t = Type::TOP; // Merged type starting value
|
||||||
@ -921,6 +927,8 @@ const Type *PhiNode::Value( PhaseTransform *phase ) const {
|
|||||||
// uplift the type.
|
// uplift the type.
|
||||||
if( !t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface() )
|
if( !t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface() )
|
||||||
{ assert(ft == _type, ""); } // Uplift to interface
|
{ assert(ft == _type, ""); } // Uplift to interface
|
||||||
|
else if( !t->empty() && ttkp && ttkp->is_loaded() && ttkp->klass()->is_interface() )
|
||||||
|
{ assert(ft == _type, ""); } // Uplift to interface
|
||||||
// Otherwise it's something stupid like non-overlapping int ranges
|
// Otherwise it's something stupid like non-overlapping int ranges
|
||||||
// found on dying counted loops.
|
// found on dying counted loops.
|
||||||
else
|
else
|
||||||
@ -936,6 +944,7 @@ const Type *PhiNode::Value( PhaseTransform *phase ) const {
|
|||||||
// because the type system doesn't interact well with interfaces.
|
// because the type system doesn't interact well with interfaces.
|
||||||
const TypePtr *jtp = jt->make_ptr();
|
const TypePtr *jtp = jt->make_ptr();
|
||||||
const TypeInstPtr *jtip = (jtp != NULL) ? jtp->isa_instptr() : NULL;
|
const TypeInstPtr *jtip = (jtp != NULL) ? jtp->isa_instptr() : NULL;
|
||||||
|
const TypeKlassPtr *jtkp = (jtp != NULL) ? jtp->isa_klassptr() : NULL;
|
||||||
if( jtip && ttip ) {
|
if( jtip && ttip ) {
|
||||||
if( jtip->is_loaded() && jtip->klass()->is_interface() &&
|
if( jtip->is_loaded() && jtip->klass()->is_interface() &&
|
||||||
ttip->is_loaded() && !ttip->klass()->is_interface() ) {
|
ttip->is_loaded() && !ttip->klass()->is_interface() ) {
|
||||||
@ -945,6 +954,14 @@ const Type *PhiNode::Value( PhaseTransform *phase ) const {
|
|||||||
jt = ft;
|
jt = ft;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( jtkp && ttkp ) {
|
||||||
|
if( jtkp->is_loaded() && jtkp->klass()->is_interface() &&
|
||||||
|
ttkp->is_loaded() && !ttkp->klass()->is_interface() ) {
|
||||||
|
assert(ft == ttkp->cast_to_ptr_type(jtkp->ptr()) ||
|
||||||
|
ft->isa_narrowoop() && ft->make_ptr() == ttkp->cast_to_ptr_type(jtkp->ptr()), "");
|
||||||
|
jt = ft;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (jt != ft && jt->base() == ft->base()) {
|
if (jt != ft && jt->base() == ft->base()) {
|
||||||
if (jt->isa_int() &&
|
if (jt->isa_int() &&
|
||||||
jt->is_int()->_lo == ft->is_int()->_lo &&
|
jt->is_int()->_lo == ft->is_int()->_lo &&
|
||||||
|
@ -228,6 +228,11 @@ void PhaseChaitin::Register_Allocate() {
|
|||||||
// them for real.
|
// them for real.
|
||||||
de_ssa();
|
de_ssa();
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
// Veify the graph before RA.
|
||||||
|
verify(&live_arena);
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
NOT_PRODUCT( Compile::TracePhase t3("computeLive", &_t_computeLive, TimeCompiler); )
|
NOT_PRODUCT( Compile::TracePhase t3("computeLive", &_t_computeLive, TimeCompiler); )
|
||||||
_live = NULL; // Mark live as being not available
|
_live = NULL; // Mark live as being not available
|
||||||
@ -306,12 +311,6 @@ void PhaseChaitin::Register_Allocate() {
|
|||||||
C->check_node_count(2*NodeLimitFudgeFactor, "out of nodes after physical split");
|
C->check_node_count(2*NodeLimitFudgeFactor, "out of nodes after physical split");
|
||||||
if (C->failing()) return;
|
if (C->failing()) return;
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
if( VerifyOpto ) {
|
|
||||||
_cfg.verify();
|
|
||||||
verify_base_ptrs(&live_arena);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
NOT_PRODUCT( C->verify_graph_edges(); )
|
NOT_PRODUCT( C->verify_graph_edges(); )
|
||||||
|
|
||||||
compact(); // Compact LRGs; return new lower max lrg
|
compact(); // Compact LRGs; return new lower max lrg
|
||||||
@ -340,7 +339,7 @@ void PhaseChaitin::Register_Allocate() {
|
|||||||
compress_uf_map_for_nodes();
|
compress_uf_map_for_nodes();
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if( VerifyOpto ) _ifg->verify(this);
|
verify(&live_arena, true);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
ifg.SquareUp();
|
ifg.SquareUp();
|
||||||
@ -376,12 +375,6 @@ void PhaseChaitin::Register_Allocate() {
|
|||||||
// Bail out if unique gets too large (ie - unique > MaxNodeLimit - 2*NodeLimitFudgeFactor)
|
// Bail out if unique gets too large (ie - unique > MaxNodeLimit - 2*NodeLimitFudgeFactor)
|
||||||
C->check_node_count(2*NodeLimitFudgeFactor, "out of nodes after split");
|
C->check_node_count(2*NodeLimitFudgeFactor, "out of nodes after split");
|
||||||
if (C->failing()) return;
|
if (C->failing()) return;
|
||||||
#ifdef ASSERT
|
|
||||||
if( VerifyOpto ) {
|
|
||||||
_cfg.verify();
|
|
||||||
verify_base_ptrs(&live_arena);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
compact(); // Compact LRGs; return new lower max lrg
|
compact(); // Compact LRGs; return new lower max lrg
|
||||||
|
|
||||||
@ -412,7 +405,7 @@ void PhaseChaitin::Register_Allocate() {
|
|||||||
}
|
}
|
||||||
compress_uf_map_for_nodes();
|
compress_uf_map_for_nodes();
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if( VerifyOpto ) _ifg->verify(this);
|
verify(&live_arena, true);
|
||||||
#endif
|
#endif
|
||||||
cache_lrg_info(); // Count degree of LRGs
|
cache_lrg_info(); // Count degree of LRGs
|
||||||
|
|
||||||
@ -432,6 +425,11 @@ void PhaseChaitin::Register_Allocate() {
|
|||||||
// Peephole remove copies
|
// Peephole remove copies
|
||||||
post_allocate_copy_removal();
|
post_allocate_copy_removal();
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
// Veify the graph after RA.
|
||||||
|
verify(&live_arena);
|
||||||
|
#endif
|
||||||
|
|
||||||
// max_reg is past the largest *register* used.
|
// max_reg is past the largest *register* used.
|
||||||
// Convert that to a frame_slot number.
|
// Convert that to a frame_slot number.
|
||||||
if( _max_reg <= _matcher._new_SP )
|
if( _max_reg <= _matcher._new_SP )
|
||||||
@ -956,7 +954,7 @@ void PhaseChaitin::Simplify( ) {
|
|||||||
while ((neighbor = elements.next()) != 0) {
|
while ((neighbor = elements.next()) != 0) {
|
||||||
LRG *n = &lrgs(neighbor);
|
LRG *n = &lrgs(neighbor);
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if( VerifyOpto ) {
|
if( VerifyOpto || VerifyRegisterAllocator ) {
|
||||||
assert( _ifg->effective_degree(neighbor) == n->degree(), "" );
|
assert( _ifg->effective_degree(neighbor) == n->degree(), "" );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -491,6 +491,8 @@ private:
|
|||||||
// Verify that base pointers and derived pointers are still sane
|
// Verify that base pointers and derived pointers are still sane
|
||||||
void verify_base_ptrs( ResourceArea *a ) const;
|
void verify_base_ptrs( ResourceArea *a ) const;
|
||||||
|
|
||||||
|
void verify( ResourceArea *a, bool verify_ifg = false ) const;
|
||||||
|
|
||||||
void dump_for_spill_split_recycle() const;
|
void dump_for_spill_split_recycle() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -129,7 +129,7 @@ macro(JumpProj)
|
|||||||
macro(LShiftI)
|
macro(LShiftI)
|
||||||
macro(LShiftL)
|
macro(LShiftL)
|
||||||
macro(LoadB)
|
macro(LoadB)
|
||||||
macro(LoadC)
|
macro(LoadUS)
|
||||||
macro(LoadD)
|
macro(LoadD)
|
||||||
macro(LoadD_unaligned)
|
macro(LoadD_unaligned)
|
||||||
macro(LoadF)
|
macro(LoadF)
|
||||||
|
@ -2005,7 +2005,7 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &fpu ) {
|
|||||||
case Op_StoreP:
|
case Op_StoreP:
|
||||||
case Op_StoreN:
|
case Op_StoreN:
|
||||||
case Op_LoadB:
|
case Op_LoadB:
|
||||||
case Op_LoadC:
|
case Op_LoadUS:
|
||||||
case Op_LoadI:
|
case Op_LoadI:
|
||||||
case Op_LoadKlass:
|
case Op_LoadKlass:
|
||||||
case Op_LoadNKlass:
|
case Op_LoadNKlass:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||||
@ -244,42 +244,73 @@ static bool magic_long_divide_constants(jlong d, jlong &M, jint &s) {
|
|||||||
|
|
||||||
//---------------------long_by_long_mulhi--------------------------------------
|
//---------------------long_by_long_mulhi--------------------------------------
|
||||||
// Generate ideal node graph for upper half of a 64 bit x 64 bit multiplication
|
// Generate ideal node graph for upper half of a 64 bit x 64 bit multiplication
|
||||||
static Node *long_by_long_mulhi( PhaseGVN *phase, Node *dividend, jlong magic_const) {
|
static Node* long_by_long_mulhi(PhaseGVN* phase, Node* dividend, jlong magic_const) {
|
||||||
// If the architecture supports a 64x64 mulhi, there is
|
// If the architecture supports a 64x64 mulhi, there is
|
||||||
// no need to synthesize it in ideal nodes.
|
// no need to synthesize it in ideal nodes.
|
||||||
if (Matcher::has_match_rule(Op_MulHiL)) {
|
if (Matcher::has_match_rule(Op_MulHiL)) {
|
||||||
Node *v = phase->longcon(magic_const);
|
Node* v = phase->longcon(magic_const);
|
||||||
return new (phase->C, 3) MulHiLNode(dividend, v);
|
return new (phase->C, 3) MulHiLNode(dividend, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Taken from Hacker's Delight, Fig. 8-2. Multiply high signed.
|
||||||
|
// (http://www.hackersdelight.org/HDcode/mulhs.c)
|
||||||
|
//
|
||||||
|
// int mulhs(int u, int v) {
|
||||||
|
// unsigned u0, v0, w0;
|
||||||
|
// int u1, v1, w1, w2, t;
|
||||||
|
//
|
||||||
|
// u0 = u & 0xFFFF; u1 = u >> 16;
|
||||||
|
// v0 = v & 0xFFFF; v1 = v >> 16;
|
||||||
|
// w0 = u0*v0;
|
||||||
|
// t = u1*v0 + (w0 >> 16);
|
||||||
|
// w1 = t & 0xFFFF;
|
||||||
|
// w2 = t >> 16;
|
||||||
|
// w1 = u0*v1 + w1;
|
||||||
|
// return u1*v1 + w2 + (w1 >> 16);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Note: The version above is for 32x32 multiplications, while the
|
||||||
|
// following inline comments are adapted to 64x64.
|
||||||
|
|
||||||
const int N = 64;
|
const int N = 64;
|
||||||
|
|
||||||
Node *u_hi = phase->transform(new (phase->C, 3) RShiftLNode(dividend, phase->intcon(N / 2)));
|
// u0 = u & 0xFFFFFFFF; u1 = u >> 32;
|
||||||
Node *u_lo = phase->transform(new (phase->C, 3) AndLNode(dividend, phase->longcon(0xFFFFFFFF)));
|
Node* u0 = phase->transform(new (phase->C, 3) AndLNode(dividend, phase->longcon(0xFFFFFFFF)));
|
||||||
|
Node* u1 = phase->transform(new (phase->C, 3) RShiftLNode(dividend, phase->intcon(N / 2)));
|
||||||
|
|
||||||
Node *v_hi = phase->longcon(magic_const >> N/2);
|
// v0 = v & 0xFFFFFFFF; v1 = v >> 32;
|
||||||
Node *v_lo = phase->longcon(magic_const & 0XFFFFFFFF);
|
Node* v0 = phase->longcon(magic_const & 0xFFFFFFFF);
|
||||||
|
Node* v1 = phase->longcon(magic_const >> (N / 2));
|
||||||
|
|
||||||
Node *hihi_product = phase->transform(new (phase->C, 3) MulLNode(u_hi, v_hi));
|
// w0 = u0*v0;
|
||||||
Node *hilo_product = phase->transform(new (phase->C, 3) MulLNode(u_hi, v_lo));
|
Node* w0 = phase->transform(new (phase->C, 3) MulLNode(u0, v0));
|
||||||
Node *lohi_product = phase->transform(new (phase->C, 3) MulLNode(u_lo, v_hi));
|
|
||||||
Node *lolo_product = phase->transform(new (phase->C, 3) MulLNode(u_lo, v_lo));
|
|
||||||
|
|
||||||
Node *t1 = phase->transform(new (phase->C, 3) URShiftLNode(lolo_product, phase->intcon(N / 2)));
|
// t = u1*v0 + (w0 >> 32);
|
||||||
Node *t2 = phase->transform(new (phase->C, 3) AddLNode(hilo_product, t1));
|
Node* u1v0 = phase->transform(new (phase->C, 3) MulLNode(u1, v0));
|
||||||
|
Node* temp = phase->transform(new (phase->C, 3) URShiftLNode(w0, phase->intcon(N / 2)));
|
||||||
|
Node* t = phase->transform(new (phase->C, 3) AddLNode(u1v0, temp));
|
||||||
|
|
||||||
// Construct both t3 and t4 before transforming so t2 doesn't go dead
|
// w1 = t & 0xFFFFFFFF;
|
||||||
// prematurely.
|
Node* w1 = new (phase->C, 3) AndLNode(t, phase->longcon(0xFFFFFFFF));
|
||||||
Node *t3 = new (phase->C, 3) RShiftLNode(t2, phase->intcon(N / 2));
|
|
||||||
Node *t4 = new (phase->C, 3) AndLNode(t2, phase->longcon(0xFFFFFFFF));
|
|
||||||
t3 = phase->transform(t3);
|
|
||||||
t4 = phase->transform(t4);
|
|
||||||
|
|
||||||
Node *t5 = phase->transform(new (phase->C, 3) AddLNode(t4, lohi_product));
|
// w2 = t >> 32;
|
||||||
Node *t6 = phase->transform(new (phase->C, 3) RShiftLNode(t5, phase->intcon(N / 2)));
|
Node* w2 = new (phase->C, 3) RShiftLNode(t, phase->intcon(N / 2));
|
||||||
Node *t7 = phase->transform(new (phase->C, 3) AddLNode(t3, hihi_product));
|
|
||||||
|
|
||||||
return new (phase->C, 3) AddLNode(t7, t6);
|
// 6732154: Construct both w1 and w2 before transforming, so t
|
||||||
|
// doesn't go dead prematurely.
|
||||||
|
w1 = phase->transform(w1);
|
||||||
|
w2 = phase->transform(w2);
|
||||||
|
|
||||||
|
// w1 = u0*v1 + w1;
|
||||||
|
Node* u0v1 = phase->transform(new (phase->C, 3) MulLNode(u0, v1));
|
||||||
|
w1 = phase->transform(new (phase->C, 3) AddLNode(u0v1, w1));
|
||||||
|
|
||||||
|
// return u1*v1 + w2 + (w1 >> 32);
|
||||||
|
Node* u1v1 = phase->transform(new (phase->C, 3) MulLNode(u1, v1));
|
||||||
|
Node* temp1 = phase->transform(new (phase->C, 3) AddLNode(u1v1, w2));
|
||||||
|
Node* temp2 = phase->transform(new (phase->C, 3) RShiftLNode(w1, phase->intcon(N / 2)));
|
||||||
|
|
||||||
|
return new (phase->C, 3) AddLNode(temp1, temp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -976,7 +1007,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
|
|
||||||
// Expand mod
|
// Expand mod
|
||||||
if( con >= 0 && con < max_jlong && is_power_of_2_long(con+1) ) {
|
if( con >= 0 && con < max_jlong && is_power_of_2_long(con+1) ) {
|
||||||
uint k = log2_long(con); // Extract k
|
uint k = exact_log2_long(con+1); // Extract k
|
||||||
|
|
||||||
// Basic algorithm by David Detlefs. See fastmod_long.java for gory details.
|
// Basic algorithm by David Detlefs. See fastmod_long.java for gory details.
|
||||||
// Used to help a popular random number generator which does a long-mod
|
// Used to help a popular random number generator which does a long-mod
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
#include "incls/_precompiled.incl"
|
#include "incls/_precompiled.incl"
|
||||||
#include "incls/_gcm.cpp.incl"
|
#include "incls/_gcm.cpp.incl"
|
||||||
|
|
||||||
|
// To avoid float value underflow
|
||||||
|
#define MIN_BLOCK_FREQUENCY 1.e-35f
|
||||||
|
|
||||||
//----------------------------schedule_node_into_block-------------------------
|
//----------------------------schedule_node_into_block-------------------------
|
||||||
// Insert node n into block b. Look for projections of n and make sure they
|
// Insert node n into block b. Look for projections of n and make sure they
|
||||||
// are in b also.
|
// are in b also.
|
||||||
@ -1380,6 +1383,13 @@ void PhaseCFG::Estimate_Block_Frequency() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
for (uint i = 0; i < _num_blocks; i++ ) {
|
||||||
|
Block *b = _blocks[i];
|
||||||
|
assert(b->_freq >= MIN_BLOCK_FREQUENCY, "Register Allocator requiers meaningful block frequency");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (PrintCFGBlockFreq) {
|
if (PrintCFGBlockFreq) {
|
||||||
tty->print_cr("CFG Block Frequencies");
|
tty->print_cr("CFG Block Frequencies");
|
||||||
@ -1877,7 +1887,9 @@ void CFGLoop::scale_freq() {
|
|||||||
float loop_freq = _freq * trip_count();
|
float loop_freq = _freq * trip_count();
|
||||||
for (int i = 0; i < _members.length(); i++) {
|
for (int i = 0; i < _members.length(); i++) {
|
||||||
CFGElement* s = _members.at(i);
|
CFGElement* s = _members.at(i);
|
||||||
s->_freq *= loop_freq;
|
float block_freq = s->_freq * loop_freq;
|
||||||
|
if (block_freq < MIN_BLOCK_FREQUENCY) block_freq = MIN_BLOCK_FREQUENCY;
|
||||||
|
s->_freq = block_freq;
|
||||||
}
|
}
|
||||||
CFGLoop* ch = _child;
|
CFGLoop* ch = _child;
|
||||||
while (ch != NULL) {
|
while (ch != NULL) {
|
||||||
|
@ -1836,10 +1836,7 @@ void GraphKit::write_barrier_post(Node* oop_store, Node* obj, Node* adr,
|
|||||||
(CardTableModRefBS*)(Universe::heap()->barrier_set());
|
(CardTableModRefBS*)(Universe::heap()->barrier_set());
|
||||||
Node *b = _gvn.transform(new (C, 3) URShiftXNode( cast, _gvn.intcon(CardTableModRefBS::card_shift) ));
|
Node *b = _gvn.transform(new (C, 3) URShiftXNode( cast, _gvn.intcon(CardTableModRefBS::card_shift) ));
|
||||||
// We store into a byte array, so do not bother to left-shift by zero
|
// We store into a byte array, so do not bother to left-shift by zero
|
||||||
// Get base of card map
|
Node *c = byte_map_base_node();
|
||||||
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte),
|
|
||||||
"adjust this code");
|
|
||||||
Node *c = makecon(TypeRawPtr::make((address)ct->byte_map_base));
|
|
||||||
// Combine
|
// Combine
|
||||||
Node *sb_ctl = control();
|
Node *sb_ctl = control();
|
||||||
Node *sb_adr = _gvn.transform(new (C, 4) AddPNode( top()/*no base ptr*/, c, b ));
|
Node *sb_adr = _gvn.transform(new (C, 4) AddPNode( top()/*no base ptr*/, c, b ));
|
||||||
@ -2945,16 +2942,10 @@ Node* GraphKit::new_instance(Node* klass_node,
|
|||||||
|
|
||||||
// Now generate allocation code
|
// Now generate allocation code
|
||||||
|
|
||||||
// With escape analysis, the entire memory state is needed to be able to
|
// The entire memory state is needed for slow path of the allocation
|
||||||
// eliminate the allocation. If the allocations cannot be eliminated, this
|
// since GC and deoptimization can happened.
|
||||||
// will be optimized to the raw slice when the allocation is expanded.
|
Node *mem = reset_memory();
|
||||||
Node *mem;
|
set_all_memory(mem); // Create new memory state
|
||||||
if (C->do_escape_analysis()) {
|
|
||||||
mem = reset_memory();
|
|
||||||
set_all_memory(mem);
|
|
||||||
} else {
|
|
||||||
mem = memory(Compile::AliasIdxRaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AllocateNode* alloc
|
AllocateNode* alloc
|
||||||
= new (C, AllocateNode::ParmLimit)
|
= new (C, AllocateNode::ParmLimit)
|
||||||
@ -3091,16 +3082,10 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable)
|
|||||||
|
|
||||||
// Now generate allocation code
|
// Now generate allocation code
|
||||||
|
|
||||||
// With escape analysis, the entire memory state is needed to be able to
|
// The entire memory state is needed for slow path of the allocation
|
||||||
// eliminate the allocation. If the allocations cannot be eliminated, this
|
// since GC and deoptimization can happened.
|
||||||
// will be optimized to the raw slice when the allocation is expanded.
|
Node *mem = reset_memory();
|
||||||
Node *mem;
|
set_all_memory(mem); // Create new memory state
|
||||||
if (C->do_escape_analysis()) {
|
|
||||||
mem = reset_memory();
|
|
||||||
set_all_memory(mem);
|
|
||||||
} else {
|
|
||||||
mem = memory(Compile::AliasIdxRaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the AllocateArrayNode and its result projections
|
// Create the AllocateArrayNode and its result projections
|
||||||
AllocateArrayNode* alloc
|
AllocateArrayNode* alloc
|
||||||
@ -3233,12 +3218,11 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
|
|||||||
|
|
||||||
// Now some of the values
|
// Now some of the values
|
||||||
|
|
||||||
Node* marking = __ load(no_ctrl, marking_adr, TypeInt::INT, active_type, Compile::AliasIdxRaw);
|
Node* marking = __ load(__ ctrl(), marking_adr, TypeInt::INT, active_type, Compile::AliasIdxRaw);
|
||||||
Node* index = __ load(no_ctrl, index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
|
|
||||||
Node* buffer = __ load(no_ctrl, buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
|
|
||||||
|
|
||||||
// if (!marking)
|
// if (!marking)
|
||||||
__ if_then(marking, BoolTest::ne, zero); {
|
__ if_then(marking, BoolTest::ne, zero); {
|
||||||
|
Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
|
||||||
|
|
||||||
const Type* t1 = adr->bottom_type();
|
const Type* t1 = adr->bottom_type();
|
||||||
const Type* t2 = val->bottom_type();
|
const Type* t2 = val->bottom_type();
|
||||||
@ -3246,6 +3230,7 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
|
|||||||
Node* orig = __ load(no_ctrl, adr, val_type, bt, alias_idx);
|
Node* orig = __ load(no_ctrl, adr, val_type, bt, alias_idx);
|
||||||
// if (orig != NULL)
|
// if (orig != NULL)
|
||||||
__ if_then(orig, BoolTest::ne, null()); {
|
__ if_then(orig, BoolTest::ne, null()); {
|
||||||
|
Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
|
||||||
|
|
||||||
// load original value
|
// load original value
|
||||||
// alias_idx correct??
|
// alias_idx correct??
|
||||||
@ -3365,14 +3350,6 @@ void GraphKit::g1_write_barrier_post(Node* store,
|
|||||||
|
|
||||||
const TypeFunc *tf = OptoRuntime::g1_wb_post_Type();
|
const TypeFunc *tf = OptoRuntime::g1_wb_post_Type();
|
||||||
|
|
||||||
// Get the address of the card table
|
|
||||||
CardTableModRefBS* ct =
|
|
||||||
(CardTableModRefBS*)(Universe::heap()->barrier_set());
|
|
||||||
Node *card_table = __ makecon(TypeRawPtr::make((address)ct->byte_map_base));
|
|
||||||
// Get base of card map
|
|
||||||
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
|
|
||||||
|
|
||||||
|
|
||||||
// Offsets into the thread
|
// Offsets into the thread
|
||||||
const int index_offset = in_bytes(JavaThread::dirty_card_queue_offset() +
|
const int index_offset = in_bytes(JavaThread::dirty_card_queue_offset() +
|
||||||
PtrQueue::byte_offset_of_index());
|
PtrQueue::byte_offset_of_index());
|
||||||
@ -3402,7 +3379,7 @@ void GraphKit::g1_write_barrier_post(Node* store,
|
|||||||
Node* card_offset = __ URShiftX( cast, __ ConI(CardTableModRefBS::card_shift) );
|
Node* card_offset = __ URShiftX( cast, __ ConI(CardTableModRefBS::card_shift) );
|
||||||
|
|
||||||
// Combine card table base and card offset
|
// Combine card table base and card offset
|
||||||
Node *card_adr = __ AddP(no_base, card_table, card_offset );
|
Node *card_adr = __ AddP(no_base, byte_map_base_node(), card_offset );
|
||||||
|
|
||||||
// If we know the value being stored does it cross regions?
|
// If we know the value being stored does it cross regions?
|
||||||
|
|
||||||
|
@ -83,6 +83,18 @@ class GraphKit : public Phase {
|
|||||||
Node* zerocon(BasicType bt) const { return _gvn.zerocon(bt); }
|
Node* zerocon(BasicType bt) const { return _gvn.zerocon(bt); }
|
||||||
// (See also macro MakeConX in type.hpp, which uses intcon or longcon.)
|
// (See also macro MakeConX in type.hpp, which uses intcon or longcon.)
|
||||||
|
|
||||||
|
// Helper for byte_map_base
|
||||||
|
Node* byte_map_base_node() {
|
||||||
|
// Get base of card map
|
||||||
|
CardTableModRefBS* ct = (CardTableModRefBS*)(Universe::heap()->barrier_set());
|
||||||
|
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust users of this code");
|
||||||
|
if (ct->byte_map_base != NULL) {
|
||||||
|
return makecon(TypeRawPtr::make((address)ct->byte_map_base));
|
||||||
|
} else {
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jint find_int_con(Node* n, jint value_if_unknown) {
|
jint find_int_con(Node* n, jint value_if_unknown) {
|
||||||
return _gvn.find_int_con(n, value_if_unknown);
|
return _gvn.find_int_con(n, value_if_unknown);
|
||||||
}
|
}
|
||||||
|
@ -471,12 +471,28 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
|
|||||||
// for the "collect_gc_info" phase later.
|
// for the "collect_gc_info" phase later.
|
||||||
IndexSet liveout(_live->live(b));
|
IndexSet liveout(_live->live(b));
|
||||||
uint last_inst = b->end_idx();
|
uint last_inst = b->end_idx();
|
||||||
// Compute last phi index
|
// Compute first nonphi node index
|
||||||
uint last_phi;
|
uint first_inst;
|
||||||
for( last_phi = 1; last_phi < last_inst; last_phi++ )
|
for( first_inst = 1; first_inst < last_inst; first_inst++ )
|
||||||
if( !b->_nodes[last_phi]->is_Phi() )
|
if( !b->_nodes[first_inst]->is_Phi() )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Spills could be inserted before CreateEx node which should be
|
||||||
|
// first instruction in block after Phis. Move CreateEx up.
|
||||||
|
for( uint insidx = first_inst; insidx < last_inst; insidx++ ) {
|
||||||
|
Node *ex = b->_nodes[insidx];
|
||||||
|
if( ex->is_SpillCopy() ) continue;
|
||||||
|
if( insidx > first_inst && ex->is_Mach() &&
|
||||||
|
ex->as_Mach()->ideal_Opcode() == Op_CreateEx ) {
|
||||||
|
// If the CreateEx isn't above all the MachSpillCopies
|
||||||
|
// then move it to the top.
|
||||||
|
b->_nodes.remove(insidx);
|
||||||
|
b->_nodes.insert(first_inst, ex);
|
||||||
|
}
|
||||||
|
// Stop once a CreateEx or any other node is found
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset block's register pressure values for each ifg construction
|
// Reset block's register pressure values for each ifg construction
|
||||||
uint pressure[2], hrp_index[2];
|
uint pressure[2], hrp_index[2];
|
||||||
pressure[0] = pressure[1] = 0;
|
pressure[0] = pressure[1] = 0;
|
||||||
@ -485,7 +501,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
|
|||||||
// Liveout things are presumed live for the whole block. We accumulate
|
// Liveout things are presumed live for the whole block. We accumulate
|
||||||
// 'area' accordingly. If they get killed in the block, we'll subtract
|
// 'area' accordingly. If they get killed in the block, we'll subtract
|
||||||
// the unused part of the block from the area.
|
// the unused part of the block from the area.
|
||||||
int inst_count = last_inst - last_phi;
|
int inst_count = last_inst - first_inst;
|
||||||
double cost = (inst_count <= 0) ? 0.0 : b->_freq * double(inst_count);
|
double cost = (inst_count <= 0) ? 0.0 : b->_freq * double(inst_count);
|
||||||
assert(!(cost < 0.0), "negative spill cost" );
|
assert(!(cost < 0.0), "negative spill cost" );
|
||||||
IndexSetIterator elements(&liveout);
|
IndexSetIterator elements(&liveout);
|
||||||
|
@ -107,7 +107,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe
|
|||||||
was_store = false;
|
was_store = false;
|
||||||
switch( mach->ideal_Opcode() ) {
|
switch( mach->ideal_Opcode() ) {
|
||||||
case Op_LoadB:
|
case Op_LoadB:
|
||||||
case Op_LoadC:
|
case Op_LoadUS:
|
||||||
case Op_LoadD:
|
case Op_LoadD:
|
||||||
case Op_LoadF:
|
case Op_LoadF:
|
||||||
case Op_LoadI:
|
case Op_LoadI:
|
||||||
|
@ -271,9 +271,9 @@ void PhaseLive::dump( const Block *b ) const {
|
|||||||
|
|
||||||
//------------------------------verify_base_ptrs-------------------------------
|
//------------------------------verify_base_ptrs-------------------------------
|
||||||
// Verify that base pointers and derived pointers are still sane.
|
// Verify that base pointers and derived pointers are still sane.
|
||||||
// Basically, if a derived pointer is live at a safepoint, then its
|
|
||||||
// base pointer must be live also.
|
|
||||||
void PhaseChaitin::verify_base_ptrs( ResourceArea *a ) const {
|
void PhaseChaitin::verify_base_ptrs( ResourceArea *a ) const {
|
||||||
|
#ifdef ASSERT
|
||||||
|
Unique_Node_List worklist(a);
|
||||||
for( uint i = 0; i < _cfg._num_blocks; i++ ) {
|
for( uint i = 0; i < _cfg._num_blocks; i++ ) {
|
||||||
Block *b = _cfg._blocks[i];
|
Block *b = _cfg._blocks[i];
|
||||||
for( uint j = b->end_idx() + 1; j > 1; j-- ) {
|
for( uint j = b->end_idx() + 1; j > 1; j-- ) {
|
||||||
@ -287,28 +287,81 @@ void PhaseChaitin::verify_base_ptrs( ResourceArea *a ) const {
|
|||||||
// Now scan for a live derived pointer
|
// Now scan for a live derived pointer
|
||||||
if (jvms->oopoff() < sfpt->req()) {
|
if (jvms->oopoff() < sfpt->req()) {
|
||||||
// Check each derived/base pair
|
// Check each derived/base pair
|
||||||
for (uint idx = jvms->oopoff(); idx < sfpt->req(); idx += 2) {
|
for (uint idx = jvms->oopoff(); idx < sfpt->req(); idx++) {
|
||||||
Node *check = sfpt->in(idx);
|
Node *check = sfpt->in(idx);
|
||||||
uint j = 0;
|
bool is_derived = ((idx - jvms->oopoff()) & 1) == 0;
|
||||||
// search upwards through spills and spill phis for AddP
|
// search upwards through spills and spill phis for AddP
|
||||||
while(true) {
|
worklist.clear();
|
||||||
if( !check ) break;
|
worklist.push(check);
|
||||||
int idx = check->is_Copy();
|
uint k = 0;
|
||||||
if( idx ) {
|
while( k < worklist.size() ) {
|
||||||
check = check->in(idx);
|
check = worklist.at(k);
|
||||||
} else if( check->is_Phi() && check->_idx >= _oldphi ) {
|
assert(check,"Bad base or derived pointer");
|
||||||
check = check->in(1);
|
// See PhaseChaitin::find_base_for_derived() for all cases.
|
||||||
} else
|
int isc = check->is_Copy();
|
||||||
break;
|
if( isc ) {
|
||||||
j++;
|
worklist.push(check->in(isc));
|
||||||
assert(j < 100000,"Derived pointer checking in infinite loop");
|
} else if( check->is_Phi() ) {
|
||||||
|
for (uint m = 1; m < check->req(); m++)
|
||||||
|
worklist.push(check->in(m));
|
||||||
|
} else if( check->is_Con() ) {
|
||||||
|
if (is_derived) {
|
||||||
|
// Derived is NULL+offset
|
||||||
|
assert(!is_derived || check->bottom_type()->is_ptr()->ptr() == TypePtr::Null,"Bad derived pointer");
|
||||||
|
} else {
|
||||||
|
assert(check->bottom_type()->is_ptr()->_offset == 0,"Bad base pointer");
|
||||||
|
// Base either ConP(NULL) or loadConP
|
||||||
|
if (check->is_Mach()) {
|
||||||
|
assert(check->as_Mach()->ideal_Opcode() == Op_ConP,"Bad base pointer");
|
||||||
|
} else {
|
||||||
|
assert(check->Opcode() == Op_ConP &&
|
||||||
|
check->bottom_type()->is_ptr()->ptr() == TypePtr::Null,"Bad base pointer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if( check->bottom_type()->is_ptr()->_offset == 0 ) {
|
||||||
|
if(check->is_Proj() || check->is_Mach() &&
|
||||||
|
(check->as_Mach()->ideal_Opcode() == Op_CreateEx ||
|
||||||
|
check->as_Mach()->ideal_Opcode() == Op_ThreadLocal ||
|
||||||
|
check->as_Mach()->ideal_Opcode() == Op_CMoveP ||
|
||||||
|
check->as_Mach()->ideal_Opcode() == Op_CheckCastPP ||
|
||||||
|
#ifdef _LP64
|
||||||
|
UseCompressedOops && check->as_Mach()->ideal_Opcode() == Op_CastPP ||
|
||||||
|
UseCompressedOops && check->as_Mach()->ideal_Opcode() == Op_DecodeN ||
|
||||||
|
#endif
|
||||||
|
check->as_Mach()->ideal_Opcode() == Op_LoadP ||
|
||||||
|
check->as_Mach()->ideal_Opcode() == Op_LoadKlass)) {
|
||||||
|
// Valid nodes
|
||||||
|
} else {
|
||||||
|
check->dump();
|
||||||
|
assert(false,"Bad base or derived pointer");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(is_derived,"Bad base pointer");
|
||||||
|
assert(check->is_Mach() && check->as_Mach()->ideal_Opcode() == Op_AddP,"Bad derived pointer");
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
assert(k < 100000,"Derived pointer checking in infinite loop");
|
||||||
} // End while
|
} // End while
|
||||||
assert(check->is_Mach() && check->as_Mach()->ideal_Opcode() == Op_AddP,"Bad derived pointer")
|
|
||||||
}
|
}
|
||||||
} // End of check for derived pointers
|
} // End of check for derived pointers
|
||||||
} // End of Kcheck for debug info
|
} // End of Kcheck for debug info
|
||||||
} // End of if found a safepoint
|
} // End of if found a safepoint
|
||||||
} // End of forall instructions in block
|
} // End of forall instructions in block
|
||||||
} // End of forall blocks
|
} // End of forall blocks
|
||||||
}
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------verify-------------------------------------
|
||||||
|
// Verify that graphs and base pointers are still sane.
|
||||||
|
void PhaseChaitin::verify( ResourceArea *a, bool verify_ifg ) const {
|
||||||
|
#ifdef ASSERT
|
||||||
|
if( VerifyOpto || VerifyRegisterAllocator ) {
|
||||||
|
_cfg.verify();
|
||||||
|
verify_base_ptrs(a);
|
||||||
|
if(verify_ifg)
|
||||||
|
_ifg->verify(this);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2654,7 +2654,7 @@ void PhaseIdealLoop::build_loop_late_post( Node *n, const PhaseIdealLoop *verify
|
|||||||
case Op_ModF:
|
case Op_ModF:
|
||||||
case Op_ModD:
|
case Op_ModD:
|
||||||
case Op_LoadB: // Same with Loads; they can sink
|
case Op_LoadB: // Same with Loads; they can sink
|
||||||
case Op_LoadC: // during loop optimizations.
|
case Op_LoadUS: // during loop optimizations.
|
||||||
case Op_LoadD:
|
case Op_LoadD:
|
||||||
case Op_LoadF:
|
case Op_LoadF:
|
||||||
case Op_LoadI:
|
case Op_LoadI:
|
||||||
|
@ -952,13 +952,6 @@ void PhaseMacroExpand::expand_allocate_common(
|
|||||||
Node* klass_node = alloc->in(AllocateNode::KlassNode);
|
Node* klass_node = alloc->in(AllocateNode::KlassNode);
|
||||||
Node* initial_slow_test = alloc->in(AllocateNode::InitialTest);
|
Node* initial_slow_test = alloc->in(AllocateNode::InitialTest);
|
||||||
|
|
||||||
// With escape analysis, the entire memory state was needed to be able to
|
|
||||||
// eliminate the allocation. Since the allocations cannot be eliminated,
|
|
||||||
// optimize it to the raw slice.
|
|
||||||
if (mem->is_MergeMem()) {
|
|
||||||
mem = mem->as_MergeMem()->memory_at(Compile::AliasIdxRaw);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(ctrl != NULL, "must have control");
|
assert(ctrl != NULL, "must have control");
|
||||||
// We need a Region and corresponding Phi's to merge the slow-path and fast-path results.
|
// We need a Region and corresponding Phi's to merge the slow-path and fast-path results.
|
||||||
// they will not be used if "always_slow" is set
|
// they will not be used if "always_slow" is set
|
||||||
@ -1016,6 +1009,11 @@ void PhaseMacroExpand::expand_allocate_common(
|
|||||||
Node *slow_mem = mem; // save the current memory state for slow path
|
Node *slow_mem = mem; // save the current memory state for slow path
|
||||||
// generate the fast allocation code unless we know that the initial test will always go slow
|
// generate the fast allocation code unless we know that the initial test will always go slow
|
||||||
if (!always_slow) {
|
if (!always_slow) {
|
||||||
|
// Fast path modifies only raw memory.
|
||||||
|
if (mem->is_MergeMem()) {
|
||||||
|
mem = mem->as_MergeMem()->memory_at(Compile::AliasIdxRaw);
|
||||||
|
}
|
||||||
|
|
||||||
Node* eden_top_adr;
|
Node* eden_top_adr;
|
||||||
Node* eden_end_adr;
|
Node* eden_end_adr;
|
||||||
|
|
||||||
@ -1239,8 +1237,6 @@ void PhaseMacroExpand::expand_allocate_common(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mem = result_phi_rawmem;
|
|
||||||
|
|
||||||
// An allocate node has separate i_o projections for the uses on the control and i_o paths
|
// An allocate node has separate i_o projections for the uses on the control and i_o paths
|
||||||
// Replace uses of the control i_o projection with result_phi_i_o (unless we are only generating a slow call)
|
// Replace uses of the control i_o projection with result_phi_i_o (unless we are only generating a slow call)
|
||||||
if (_ioproj_fallthrough == NULL) {
|
if (_ioproj_fallthrough == NULL) {
|
||||||
|
@ -1824,7 +1824,7 @@ void Matcher::find_shared( Node *n ) {
|
|||||||
mem_op = true;
|
mem_op = true;
|
||||||
break;
|
break;
|
||||||
case Op_LoadB:
|
case Op_LoadB:
|
||||||
case Op_LoadC:
|
case Op_LoadUS:
|
||||||
case Op_LoadD:
|
case Op_LoadD:
|
||||||
case Op_LoadF:
|
case Op_LoadF:
|
||||||
case Op_LoadI:
|
case Op_LoadI:
|
||||||
|
@ -779,14 +779,14 @@ Node *LoadNode::make( PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const Type
|
|||||||
"use LoadRangeNode instead");
|
"use LoadRangeNode instead");
|
||||||
switch (bt) {
|
switch (bt) {
|
||||||
case T_BOOLEAN:
|
case T_BOOLEAN:
|
||||||
case T_BYTE: return new (C, 3) LoadBNode(ctl, mem, adr, adr_type, rt->is_int() );
|
case T_BYTE: return new (C, 3) LoadBNode (ctl, mem, adr, adr_type, rt->is_int() );
|
||||||
case T_INT: return new (C, 3) LoadINode(ctl, mem, adr, adr_type, rt->is_int() );
|
case T_INT: return new (C, 3) LoadINode (ctl, mem, adr, adr_type, rt->is_int() );
|
||||||
case T_CHAR: return new (C, 3) LoadCNode(ctl, mem, adr, adr_type, rt->is_int() );
|
case T_CHAR: return new (C, 3) LoadUSNode(ctl, mem, adr, adr_type, rt->is_int() );
|
||||||
case T_SHORT: return new (C, 3) LoadSNode(ctl, mem, adr, adr_type, rt->is_int() );
|
case T_SHORT: return new (C, 3) LoadSNode (ctl, mem, adr, adr_type, rt->is_int() );
|
||||||
case T_LONG: return new (C, 3) LoadLNode(ctl, mem, adr, adr_type, rt->is_long() );
|
case T_LONG: return new (C, 3) LoadLNode (ctl, mem, adr, adr_type, rt->is_long() );
|
||||||
case T_FLOAT: return new (C, 3) LoadFNode(ctl, mem, adr, adr_type, rt );
|
case T_FLOAT: return new (C, 3) LoadFNode (ctl, mem, adr, adr_type, rt );
|
||||||
case T_DOUBLE: return new (C, 3) LoadDNode(ctl, mem, adr, adr_type, rt );
|
case T_DOUBLE: return new (C, 3) LoadDNode (ctl, mem, adr, adr_type, rt );
|
||||||
case T_ADDRESS: return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_ptr() );
|
case T_ADDRESS: return new (C, 3) LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr() );
|
||||||
case T_OBJECT:
|
case T_OBJECT:
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
|
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
|
||||||
@ -1076,13 +1076,14 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
|
|||||||
// of the original value.
|
// of the original value.
|
||||||
Node* mem_phi = in(Memory);
|
Node* mem_phi = in(Memory);
|
||||||
Node* offset = in(Address)->in(AddPNode::Offset);
|
Node* offset = in(Address)->in(AddPNode::Offset);
|
||||||
|
Node* region = base->in(0);
|
||||||
|
|
||||||
Node* in1 = clone();
|
Node* in1 = clone();
|
||||||
Node* in1_addr = in1->in(Address)->clone();
|
Node* in1_addr = in1->in(Address)->clone();
|
||||||
in1_addr->set_req(AddPNode::Base, base->in(allocation_index));
|
in1_addr->set_req(AddPNode::Base, base->in(allocation_index));
|
||||||
in1_addr->set_req(AddPNode::Address, base->in(allocation_index));
|
in1_addr->set_req(AddPNode::Address, base->in(allocation_index));
|
||||||
in1_addr->set_req(AddPNode::Offset, offset);
|
in1_addr->set_req(AddPNode::Offset, offset);
|
||||||
in1->set_req(0, base->in(allocation_index));
|
in1->set_req(0, region->in(allocation_index));
|
||||||
in1->set_req(Address, in1_addr);
|
in1->set_req(Address, in1_addr);
|
||||||
in1->set_req(Memory, mem_phi->in(allocation_index));
|
in1->set_req(Memory, mem_phi->in(allocation_index));
|
||||||
|
|
||||||
@ -1091,7 +1092,7 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
|
|||||||
in2_addr->set_req(AddPNode::Base, base->in(load_index));
|
in2_addr->set_req(AddPNode::Base, base->in(load_index));
|
||||||
in2_addr->set_req(AddPNode::Address, base->in(load_index));
|
in2_addr->set_req(AddPNode::Address, base->in(load_index));
|
||||||
in2_addr->set_req(AddPNode::Offset, offset);
|
in2_addr->set_req(AddPNode::Offset, offset);
|
||||||
in2->set_req(0, base->in(load_index));
|
in2->set_req(0, region->in(load_index));
|
||||||
in2->set_req(Address, in2_addr);
|
in2->set_req(Address, in2_addr);
|
||||||
in2->set_req(Memory, mem_phi->in(load_index));
|
in2->set_req(Memory, mem_phi->in(load_index));
|
||||||
|
|
||||||
@ -1100,7 +1101,7 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
|
|||||||
in2_addr = phase->transform(in2_addr);
|
in2_addr = phase->transform(in2_addr);
|
||||||
in2 = phase->transform(in2);
|
in2 = phase->transform(in2);
|
||||||
|
|
||||||
PhiNode* result = PhiNode::make_blank(base->in(0), this);
|
PhiNode* result = PhiNode::make_blank(region, this);
|
||||||
result->set_req(allocation_index, in1);
|
result->set_req(allocation_index, in1);
|
||||||
result->set_req(load_index, in2);
|
result->set_req(load_index, in2);
|
||||||
return result;
|
return result;
|
||||||
@ -1303,6 +1304,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore);
|
Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore);
|
||||||
if (base != NULL
|
if (base != NULL
|
||||||
&& phase->type(base)->higher_equal(TypePtr::NOTNULL)
|
&& phase->type(base)->higher_equal(TypePtr::NOTNULL)
|
||||||
|
&& phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw
|
||||||
&& all_controls_dominate(base, phase->C->start())) {
|
&& all_controls_dominate(base, phase->C->start())) {
|
||||||
// A method-invariant, non-null address (constant or 'this' argument).
|
// A method-invariant, non-null address (constant or 'this' argument).
|
||||||
set_req(MemNode::Control, NULL);
|
set_req(MemNode::Control, NULL);
|
||||||
@ -1356,7 +1358,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
// Steps (a), (b): Walk past independent stores to find an exact match.
|
// Steps (a), (b): Walk past independent stores to find an exact match.
|
||||||
if (prev_mem != NULL && prev_mem != in(MemNode::Memory)) {
|
if (prev_mem != NULL && prev_mem != in(MemNode::Memory)) {
|
||||||
// (c) See if we can fold up on the spot, but don't fold up here.
|
// (c) See if we can fold up on the spot, but don't fold up here.
|
||||||
// Fold-up might require truncation (for LoadB/LoadS/LoadC) or
|
// Fold-up might require truncation (for LoadB/LoadS/LoadUS) or
|
||||||
// just return a prior value, which is done by Identity calls.
|
// just return a prior value, which is done by Identity calls.
|
||||||
if (can_see_stored_value(prev_mem, phase)) {
|
if (can_see_stored_value(prev_mem, phase)) {
|
||||||
// Make ready for step (d):
|
// Make ready for step (d):
|
||||||
@ -1605,14 +1607,14 @@ Node *LoadBNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
return LoadNode::Ideal(phase, can_reshape);
|
return LoadNode::Ideal(phase, can_reshape);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------LoadCNode::Ideal--------------------------------------
|
//--------------------------LoadUSNode::Ideal-------------------------------------
|
||||||
//
|
//
|
||||||
// If the previous store is to the same address as this load,
|
// If the previous store is to the same address as this load,
|
||||||
// and the value stored was larger than a char, replace this load
|
// and the value stored was larger than a char, replace this load
|
||||||
// with the value stored truncated to a char. If no truncation is
|
// with the value stored truncated to a char. If no truncation is
|
||||||
// needed, the replacement is done in LoadNode::Identity().
|
// needed, the replacement is done in LoadNode::Identity().
|
||||||
//
|
//
|
||||||
Node *LoadCNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
Node *LoadUSNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
Node* mem = in(MemNode::Memory);
|
Node* mem = in(MemNode::Memory);
|
||||||
Node* value = can_see_stored_value(mem,phase);
|
Node* value = can_see_stored_value(mem,phase);
|
||||||
if( value && !phase->type(value)->higher_equal( _type ) )
|
if( value && !phase->type(value)->higher_equal( _type ) )
|
||||||
|
@ -207,11 +207,11 @@ public:
|
|||||||
virtual BasicType memory_type() const { return T_BYTE; }
|
virtual BasicType memory_type() const { return T_BYTE; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------LoadCNode--------------------------------------
|
//------------------------------LoadUSNode-------------------------------------
|
||||||
// Load a char (16bits unsigned) from memory
|
// Load an unsigned short/char (16bits unsigned) from memory
|
||||||
class LoadCNode : public LoadNode {
|
class LoadUSNode : public LoadNode {
|
||||||
public:
|
public:
|
||||||
LoadCNode( Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti = TypeInt::CHAR )
|
LoadUSNode( Node *c, Node *mem, Node *adr, const TypePtr* at, const TypeInt *ti = TypeInt::CHAR )
|
||||||
: LoadNode(c,mem,adr,at,ti) {}
|
: LoadNode(c,mem,adr,at,ti) {}
|
||||||
virtual int Opcode() const;
|
virtual int Opcode() const;
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||||
@ -442,16 +442,17 @@ Node *AndINode::Identity( PhaseTransform *phase ) {
|
|||||||
return load;
|
return load;
|
||||||
}
|
}
|
||||||
uint lop = load->Opcode();
|
uint lop = load->Opcode();
|
||||||
if( lop == Op_LoadC &&
|
if( lop == Op_LoadUS &&
|
||||||
con == 0x0000FFFF ) // Already zero-extended
|
con == 0x0000FFFF ) // Already zero-extended
|
||||||
return load;
|
return load;
|
||||||
// Masking off the high bits of a unsigned-shift-right is not
|
// Masking off the high bits of a unsigned-shift-right is not
|
||||||
// needed either.
|
// needed either.
|
||||||
if( lop == Op_URShiftI ) {
|
if( lop == Op_URShiftI ) {
|
||||||
const TypeInt *t12 = phase->type( load->in(2) )->isa_int();
|
const TypeInt *t12 = phase->type( load->in(2) )->isa_int();
|
||||||
if( t12 && t12->is_con() ) {
|
if( t12 && t12->is_con() ) { // Shift is by a constant
|
||||||
int shift_con = t12->get_con();
|
int shift = t12->get_con();
|
||||||
int mask = max_juint >> shift_con;
|
shift &= BitsPerJavaInteger - 1; // semantics of Java shifts
|
||||||
|
int mask = max_juint >> shift;
|
||||||
if( (mask&con) == mask ) // If AND is useless, skip it
|
if( (mask&con) == mask ) // If AND is useless, skip it
|
||||||
return load;
|
return load;
|
||||||
}
|
}
|
||||||
@ -470,19 +471,19 @@ Node *AndINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
uint lop = load->Opcode();
|
uint lop = load->Opcode();
|
||||||
|
|
||||||
// Masking bits off of a Character? Hi bits are already zero.
|
// Masking bits off of a Character? Hi bits are already zero.
|
||||||
if( lop == Op_LoadC &&
|
if( lop == Op_LoadUS &&
|
||||||
(mask & 0xFFFF0000) ) // Can we make a smaller mask?
|
(mask & 0xFFFF0000) ) // Can we make a smaller mask?
|
||||||
return new (phase->C, 3) AndINode(load,phase->intcon(mask&0xFFFF));
|
return new (phase->C, 3) AndINode(load,phase->intcon(mask&0xFFFF));
|
||||||
|
|
||||||
// Masking bits off of a Short? Loading a Character does some masking
|
// Masking bits off of a Short? Loading a Character does some masking
|
||||||
if( lop == Op_LoadS &&
|
if( lop == Op_LoadS &&
|
||||||
(mask & 0xFFFF0000) == 0 ) {
|
(mask & 0xFFFF0000) == 0 ) {
|
||||||
Node *ldc = new (phase->C, 3) LoadCNode(load->in(MemNode::Control),
|
Node *ldus = new (phase->C, 3) LoadUSNode(load->in(MemNode::Control),
|
||||||
load->in(MemNode::Memory),
|
load->in(MemNode::Memory),
|
||||||
load->in(MemNode::Address),
|
load->in(MemNode::Address),
|
||||||
load->adr_type());
|
load->adr_type());
|
||||||
ldc = phase->transform(ldc);
|
ldus = phase->transform(ldus);
|
||||||
return new (phase->C, 3) AndINode(ldc,phase->intcon(mask&0xFFFF));
|
return new (phase->C, 3) AndINode(ldus, phase->intcon(mask&0xFFFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Masking sign bits off of a Byte? Let the matcher use an unsigned load
|
// Masking sign bits off of a Byte? Let the matcher use an unsigned load
|
||||||
@ -579,9 +580,10 @@ Node *AndLNode::Identity( PhaseTransform *phase ) {
|
|||||||
// needed either.
|
// needed either.
|
||||||
if( lop == Op_URShiftL ) {
|
if( lop == Op_URShiftL ) {
|
||||||
const TypeInt *t12 = phase->type( usr->in(2) )->isa_int();
|
const TypeInt *t12 = phase->type( usr->in(2) )->isa_int();
|
||||||
if( t12 && t12->is_con() ) {
|
if( t12 && t12->is_con() ) { // Shift is by a constant
|
||||||
int shift_con = t12->get_con();
|
int shift = t12->get_con();
|
||||||
jlong mask = max_julong >> shift_con;
|
shift &= BitsPerJavaLong - 1; // semantics of Java shifts
|
||||||
|
jlong mask = max_julong >> shift;
|
||||||
if( (mask&con) == mask ) // If AND is useless, skip it
|
if( (mask&con) == mask ) // If AND is useless, skip it
|
||||||
return usr;
|
return usr;
|
||||||
}
|
}
|
||||||
@ -605,8 +607,8 @@ Node *AndLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
const TypeInt *t12 = phase->type(rsh->in(2))->isa_int();
|
const TypeInt *t12 = phase->type(rsh->in(2))->isa_int();
|
||||||
if( t12 && t12->is_con() ) { // Shift is by a constant
|
if( t12 && t12->is_con() ) { // Shift is by a constant
|
||||||
int shift = t12->get_con();
|
int shift = t12->get_con();
|
||||||
shift &= (BitsPerJavaInteger*2)-1; // semantics of Java shifts
|
shift &= BitsPerJavaLong - 1; // semantics of Java shifts
|
||||||
const jlong sign_bits_mask = ~(((jlong)CONST64(1) << (jlong)(BitsPerJavaInteger*2 - shift)) -1);
|
const jlong sign_bits_mask = ~(((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - shift)) -1);
|
||||||
// If the AND'ing of the 2 masks has no bits, then only original shifted
|
// If the AND'ing of the 2 masks has no bits, then only original shifted
|
||||||
// bits survive. NO sign-extension bits survive the maskings.
|
// bits survive. NO sign-extension bits survive the maskings.
|
||||||
if( (sign_bits_mask & mask) == 0 ) {
|
if( (sign_bits_mask & mask) == 0 ) {
|
||||||
@ -786,7 +788,7 @@ Node *LShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
|
|
||||||
// Check for ((x & ((CONST64(1)<<(64-c0))-1)) << c0) which ANDs off high bits
|
// Check for ((x & ((CONST64(1)<<(64-c0))-1)) << c0) which ANDs off high bits
|
||||||
// before shifting them away.
|
// before shifting them away.
|
||||||
const jlong bits_mask = ((jlong)CONST64(1) << (jlong)(BitsPerJavaInteger*2 - con)) - CONST64(1);
|
const jlong bits_mask = ((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - con)) - CONST64(1);
|
||||||
if( add1_op == Op_AndL &&
|
if( add1_op == Op_AndL &&
|
||||||
phase->type(add1->in(2)) == TypeLong::make( bits_mask ) )
|
phase->type(add1->in(2)) == TypeLong::make( bits_mask ) )
|
||||||
return new (phase->C, 3) LShiftLNode( add1->in(1), in(2) );
|
return new (phase->C, 3) LShiftLNode( add1->in(1), in(2) );
|
||||||
@ -820,7 +822,7 @@ const Type *LShiftLNode::Value( PhaseTransform *phase ) const {
|
|||||||
return TypeLong::LONG;
|
return TypeLong::LONG;
|
||||||
|
|
||||||
uint shift = r2->get_con();
|
uint shift = r2->get_con();
|
||||||
shift &= (BitsPerJavaInteger*2)-1; // semantics of Java shifts
|
shift &= BitsPerJavaLong - 1; // semantics of Java shifts
|
||||||
// Shift by a multiple of 64 does nothing:
|
// Shift by a multiple of 64 does nothing:
|
||||||
if (shift == 0) return t1;
|
if (shift == 0) return t1;
|
||||||
|
|
||||||
@ -913,7 +915,7 @@ Node *RShiftINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
set_req(2, phase->intcon(0));
|
set_req(2, phase->intcon(0));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
else if( ld->Opcode() == Op_LoadC )
|
else if( ld->Opcode() == Op_LoadUS )
|
||||||
// Replace zero-extension-load with sign-extension-load
|
// Replace zero-extension-load with sign-extension-load
|
||||||
return new (phase->C, 3) LoadSNode( ld->in(MemNode::Control),
|
return new (phase->C, 3) LoadSNode( ld->in(MemNode::Control),
|
||||||
ld->in(MemNode::Memory),
|
ld->in(MemNode::Memory),
|
||||||
@ -1235,7 +1237,7 @@ Node *URShiftLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||||||
if ( con == 0 ) return NULL; // let Identity() handle a 0 shift count
|
if ( con == 0 ) return NULL; // let Identity() handle a 0 shift count
|
||||||
// note: mask computation below does not work for 0 shift count
|
// note: mask computation below does not work for 0 shift count
|
||||||
// We'll be wanting the right-shift amount as a mask of that many bits
|
// We'll be wanting the right-shift amount as a mask of that many bits
|
||||||
const jlong mask = (((jlong)CONST64(1) << (jlong)(BitsPerJavaInteger*2 - con)) -1);
|
const jlong mask = (((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - con)) -1);
|
||||||
|
|
||||||
// Check for ((x << z) + Y) >>> z. Replace with x + con>>>z
|
// Check for ((x << z) + Y) >>> z. Replace with x + con>>>z
|
||||||
// The idiom for rounding to a power of 2 is "(Q+(2^z-1)) >>> z".
|
// The idiom for rounding to a power of 2 is "(Q+(2^z-1)) >>> z".
|
||||||
@ -1302,7 +1304,7 @@ const Type *URShiftLNode::Value( PhaseTransform *phase ) const {
|
|||||||
|
|
||||||
if (r2->is_con()) {
|
if (r2->is_con()) {
|
||||||
uint shift = r2->get_con();
|
uint shift = r2->get_con();
|
||||||
shift &= (2*BitsPerJavaInteger)-1; // semantics of Java shifts
|
shift &= BitsPerJavaLong - 1; // semantics of Java shifts
|
||||||
// Shift by a multiple of 64 does nothing:
|
// Shift by a multiple of 64 does nothing:
|
||||||
if (shift == 0) return t1;
|
if (shift == 0) return t1;
|
||||||
// Calculate reasonably aggressive bounds for the result.
|
// Calculate reasonably aggressive bounds for the result.
|
||||||
@ -1325,7 +1327,7 @@ const Type *URShiftLNode::Value( PhaseTransform *phase ) const {
|
|||||||
const TypeLong* tl = TypeLong::make(lo, hi, MAX2(r1->_widen,r2->_widen));
|
const TypeLong* tl = TypeLong::make(lo, hi, MAX2(r1->_widen,r2->_widen));
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// Make sure we get the sign-capture idiom correct.
|
// Make sure we get the sign-capture idiom correct.
|
||||||
if (shift == (2*BitsPerJavaInteger)-1) {
|
if (shift == BitsPerJavaLong - 1) {
|
||||||
if (r1->_lo >= 0) assert(tl == TypeLong::ZERO, ">>>63 of + is 0");
|
if (r1->_lo >= 0) assert(tl == TypeLong::ZERO, ">>>63 of + is 0");
|
||||||
if (r1->_hi < 0) assert(tl == TypeLong::ONE, ">>>63 of - is +1");
|
if (r1->_hi < 0) assert(tl == TypeLong::ONE, ">>>63 of - is +1");
|
||||||
}
|
}
|
||||||
|
@ -1444,7 +1444,7 @@ const Type* SuperWord::container_type(const Type* t) {
|
|||||||
// (Start, end] half-open range defining which operands are vector
|
// (Start, end] half-open range defining which operands are vector
|
||||||
void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) {
|
void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) {
|
||||||
switch (n->Opcode()) {
|
switch (n->Opcode()) {
|
||||||
case Op_LoadB: case Op_LoadC:
|
case Op_LoadB: case Op_LoadUS:
|
||||||
case Op_LoadI: case Op_LoadL:
|
case Op_LoadI: case Op_LoadL:
|
||||||
case Op_LoadF: case Op_LoadD:
|
case Op_LoadF: case Op_LoadD:
|
||||||
case Op_LoadP:
|
case Op_LoadP:
|
||||||
|
@ -2471,6 +2471,8 @@ const Type *TypeOopPtr::filter( const Type *kills ) const {
|
|||||||
const Type* ft = join(kills);
|
const Type* ft = join(kills);
|
||||||
const TypeInstPtr* ftip = ft->isa_instptr();
|
const TypeInstPtr* ftip = ft->isa_instptr();
|
||||||
const TypeInstPtr* ktip = kills->isa_instptr();
|
const TypeInstPtr* ktip = kills->isa_instptr();
|
||||||
|
const TypeKlassPtr* ftkp = ft->isa_klassptr();
|
||||||
|
const TypeKlassPtr* ktkp = kills->isa_klassptr();
|
||||||
|
|
||||||
if (ft->empty()) {
|
if (ft->empty()) {
|
||||||
// Check for evil case of 'this' being a class and 'kills' expecting an
|
// Check for evil case of 'this' being a class and 'kills' expecting an
|
||||||
@ -2484,6 +2486,8 @@ const Type *TypeOopPtr::filter( const Type *kills ) const {
|
|||||||
// uplift the type.
|
// uplift the type.
|
||||||
if (!empty() && ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface())
|
if (!empty() && ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface())
|
||||||
return kills; // Uplift to interface
|
return kills; // Uplift to interface
|
||||||
|
if (!empty() && ktkp != NULL && ktkp->klass()->is_loaded() && ktkp->klass()->is_interface())
|
||||||
|
return kills; // Uplift to interface
|
||||||
|
|
||||||
return Type::TOP; // Canonical empty value
|
return Type::TOP; // Canonical empty value
|
||||||
}
|
}
|
||||||
@ -2499,6 +2503,12 @@ const Type *TypeOopPtr::filter( const Type *kills ) const {
|
|||||||
// Happens in a CTW of rt.jar, 320-341, no extra flags
|
// Happens in a CTW of rt.jar, 320-341, no extra flags
|
||||||
return ktip->cast_to_ptr_type(ftip->ptr());
|
return ktip->cast_to_ptr_type(ftip->ptr());
|
||||||
}
|
}
|
||||||
|
if (ftkp != NULL && ktkp != NULL &&
|
||||||
|
ftkp->is_loaded() && ftkp->klass()->is_interface() &&
|
||||||
|
ktkp->is_loaded() && !ktkp->klass()->is_interface()) {
|
||||||
|
// Happens in a CTW of rt.jar, 320-341, no extra flags
|
||||||
|
return ktkp->cast_to_ptr_type(ftkp->ptr());
|
||||||
|
}
|
||||||
|
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
@ -3657,7 +3667,7 @@ const TypePtr *TypeKlassPtr::add_offset( intptr_t offset ) const {
|
|||||||
|
|
||||||
//------------------------------cast_to_ptr_type-------------------------------
|
//------------------------------cast_to_ptr_type-------------------------------
|
||||||
const Type *TypeKlassPtr::cast_to_ptr_type(PTR ptr) const {
|
const Type *TypeKlassPtr::cast_to_ptr_type(PTR ptr) const {
|
||||||
assert(_base == OopPtr, "subclass must override cast_to_ptr_type");
|
assert(_base == KlassPtr, "subclass must override cast_to_ptr_type");
|
||||||
if( ptr == _ptr ) return this;
|
if( ptr == _ptr ) return this;
|
||||||
return make(ptr, _klass, _offset);
|
return make(ptr, _klass, _offset);
|
||||||
}
|
}
|
||||||
|
@ -882,6 +882,8 @@ class TypeKlassPtr : public TypeOopPtr {
|
|||||||
public:
|
public:
|
||||||
ciSymbol* name() const { return _klass->name(); }
|
ciSymbol* name() const { return _klass->name(); }
|
||||||
|
|
||||||
|
bool is_loaded() const { return _klass->is_loaded(); }
|
||||||
|
|
||||||
// ptr to klass 'k'
|
// ptr to klass 'k'
|
||||||
static const TypeKlassPtr *make( ciKlass* k ) { return make( TypePtr::Constant, k, 0); }
|
static const TypeKlassPtr *make( ciKlass* k ) { return make( TypePtr::Constant, k, 0); }
|
||||||
// ptr to klass 'k' with offset
|
// ptr to klass 'k' with offset
|
||||||
|
@ -239,7 +239,7 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
|
|||||||
return Op_XorV;
|
return Op_XorV;
|
||||||
|
|
||||||
case Op_LoadB:
|
case Op_LoadB:
|
||||||
case Op_LoadC:
|
case Op_LoadUS:
|
||||||
case Op_LoadS:
|
case Op_LoadS:
|
||||||
case Op_LoadI:
|
case Op_LoadI:
|
||||||
case Op_LoadL:
|
case Op_LoadL:
|
||||||
@ -269,7 +269,7 @@ int VectorLoadNode::opcode(int sopc, uint vlen) {
|
|||||||
case 16: return Op_Load16B;
|
case 16: return Op_Load16B;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Op_LoadC:
|
case Op_LoadUS:
|
||||||
switch (vlen) {
|
switch (vlen) {
|
||||||
case 2: return Op_Load2C;
|
case 2: return Op_Load2C;
|
||||||
case 4: return Op_Load4C;
|
case 4: return Op_Load4C;
|
||||||
|
@ -2489,7 +2489,7 @@ jint Arguments::parse_options_environment_variable(const char* name, SysClassPat
|
|||||||
vm_args.version = JNI_VERSION_1_2;
|
vm_args.version = JNI_VERSION_1_2;
|
||||||
vm_args.options = options;
|
vm_args.options = options;
|
||||||
vm_args.nOptions = i;
|
vm_args.nOptions = i;
|
||||||
vm_args.ignoreUnrecognized = false;
|
vm_args.ignoreUnrecognized = IgnoreUnrecognizedVMOptions;
|
||||||
|
|
||||||
if (PrintVMOptions) {
|
if (PrintVMOptions) {
|
||||||
const char* tail;
|
const char* tail;
|
||||||
@ -2536,13 +2536,12 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
|
|||||||
|
|
||||||
// If flag "-XX:Flags=flags-file" is used it will be the first option to be processed.
|
// If flag "-XX:Flags=flags-file" is used it will be the first option to be processed.
|
||||||
bool settings_file_specified = false;
|
bool settings_file_specified = false;
|
||||||
|
const char* flags_file;
|
||||||
int index;
|
int index;
|
||||||
for (index = 0; index < args->nOptions; index++) {
|
for (index = 0; index < args->nOptions; index++) {
|
||||||
const JavaVMOption *option = args->options + index;
|
const JavaVMOption *option = args->options + index;
|
||||||
if (match_option(option, "-XX:Flags=", &tail)) {
|
if (match_option(option, "-XX:Flags=", &tail)) {
|
||||||
if (!process_settings_file(tail, true, args->ignoreUnrecognized)) {
|
flags_file = tail;
|
||||||
return JNI_EINVAL;
|
|
||||||
}
|
|
||||||
settings_file_specified = true;
|
settings_file_specified = true;
|
||||||
}
|
}
|
||||||
if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
|
if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
|
||||||
@ -2551,6 +2550,24 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
|
|||||||
if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
|
if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
|
||||||
PrintVMOptions = false;
|
PrintVMOptions = false;
|
||||||
}
|
}
|
||||||
|
if (match_option(option, "-XX:+IgnoreUnrecognizedVMOptions", &tail)) {
|
||||||
|
IgnoreUnrecognizedVMOptions = true;
|
||||||
|
}
|
||||||
|
if (match_option(option, "-XX:-IgnoreUnrecognizedVMOptions", &tail)) {
|
||||||
|
IgnoreUnrecognizedVMOptions = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IgnoreUnrecognizedVMOptions) {
|
||||||
|
// uncast const to modify the flag args->ignoreUnrecognized
|
||||||
|
*(jboolean*)(&args->ignoreUnrecognized) = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse specified settings file
|
||||||
|
if (settings_file_specified) {
|
||||||
|
if (!process_settings_file(flags_file, true, args->ignoreUnrecognized)) {
|
||||||
|
return JNI_EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse default .hotspotrc settings file
|
// Parse default .hotspotrc settings file
|
||||||
|
@ -1426,10 +1426,10 @@ class CommandLineFlags {
|
|||||||
develop(bool, CMSOverflowEarlyRestoration, false, \
|
develop(bool, CMSOverflowEarlyRestoration, false, \
|
||||||
"Whether preserved marks should be restored early") \
|
"Whether preserved marks should be restored early") \
|
||||||
\
|
\
|
||||||
product(uintx, CMSMarkStackSize, 32*K, \
|
product(uintx, CMSMarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \
|
||||||
"Size of CMS marking stack") \
|
"Size of CMS marking stack") \
|
||||||
\
|
\
|
||||||
product(uintx, CMSMarkStackSizeMax, 4*M, \
|
product(uintx, CMSMarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \
|
||||||
"Max size of CMS marking stack") \
|
"Max size of CMS marking stack") \
|
||||||
\
|
\
|
||||||
notproduct(bool, CMSMarkStackOverflowALot, false, \
|
notproduct(bool, CMSMarkStackOverflowALot, false, \
|
||||||
@ -1655,6 +1655,13 @@ class CommandLineFlags {
|
|||||||
develop(uintx, WorkStealingYieldsBeforeSleep, 1000, \
|
develop(uintx, WorkStealingYieldsBeforeSleep, 1000, \
|
||||||
"Number of yields before a sleep is done during workstealing") \
|
"Number of yields before a sleep is done during workstealing") \
|
||||||
\
|
\
|
||||||
|
develop(uintx, WorkStealingHardSpins, 4096, \
|
||||||
|
"Number of iterations in a spin loop between checks on " \
|
||||||
|
"time out of hard spin") \
|
||||||
|
\
|
||||||
|
develop(uintx, WorkStealingSpinToYieldRatio, 10, \
|
||||||
|
"Ratio of hard spins to calls to yield") \
|
||||||
|
\
|
||||||
product(uintx, PreserveMarkStackSize, 1024, \
|
product(uintx, PreserveMarkStackSize, 1024, \
|
||||||
"Size for stack used in promotion failure handling") \
|
"Size for stack used in promotion failure handling") \
|
||||||
\
|
\
|
||||||
@ -2187,6 +2194,9 @@ class CommandLineFlags {
|
|||||||
product(bool, PrintVMOptions, trueInDebug, \
|
product(bool, PrintVMOptions, trueInDebug, \
|
||||||
"print VM flag settings") \
|
"print VM flag settings") \
|
||||||
\
|
\
|
||||||
|
product(bool, IgnoreUnrecognizedVMOptions, false, \
|
||||||
|
"Ignore unrecognized VM options") \
|
||||||
|
\
|
||||||
diagnostic(bool, SerializeVMOutput, true, \
|
diagnostic(bool, SerializeVMOutput, true, \
|
||||||
"Use a mutex to serialize output to tty and hotspot.log") \
|
"Use a mutex to serialize output to tty and hotspot.log") \
|
||||||
\
|
\
|
||||||
|
@ -74,13 +74,11 @@ char* os::iso8601_time(char* buffer, size_t buffer_length) {
|
|||||||
const int milliseconds_after_second =
|
const int milliseconds_after_second =
|
||||||
milliseconds_since_19700101 % milliseconds_per_microsecond;
|
milliseconds_since_19700101 % milliseconds_per_microsecond;
|
||||||
// Convert the time value to a tm and timezone variable
|
// Convert the time value to a tm and timezone variable
|
||||||
const struct tm *time_struct_temp = localtime(&seconds_since_19700101);
|
struct tm time_struct;
|
||||||
if (time_struct_temp == NULL) {
|
if (localtime_pd(&seconds_since_19700101, &time_struct) == NULL) {
|
||||||
assert(false, "Failed localtime");
|
assert(false, "Failed localtime_pd");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// Save the results of localtime
|
|
||||||
const struct tm time_struct = *time_struct_temp;
|
|
||||||
const time_t zone = timezone;
|
const time_t zone = timezone;
|
||||||
|
|
||||||
// If daylight savings time is in effect,
|
// If daylight savings time is in effect,
|
||||||
@ -93,10 +91,10 @@ char* os::iso8601_time(char* buffer, size_t buffer_length) {
|
|||||||
UTC_to_local = UTC_to_local - seconds_per_hour;
|
UTC_to_local = UTC_to_local - seconds_per_hour;
|
||||||
}
|
}
|
||||||
// Compute the time zone offset.
|
// Compute the time zone offset.
|
||||||
// localtime(3C) sets timezone to the difference (in seconds)
|
// localtime_pd() sets timezone to the difference (in seconds)
|
||||||
// between UTC and and local time.
|
// between UTC and and local time.
|
||||||
// ISO 8601 says we need the difference between local time and UTC,
|
// ISO 8601 says we need the difference between local time and UTC,
|
||||||
// we change the sign of the localtime(3C) result.
|
// we change the sign of the localtime_pd() result.
|
||||||
const time_t local_to_UTC = -(UTC_to_local);
|
const time_t local_to_UTC = -(UTC_to_local);
|
||||||
// Then we have to figure out if if we are ahead (+) or behind (-) UTC.
|
// Then we have to figure out if if we are ahead (+) or behind (-) UTC.
|
||||||
char sign_local_to_UTC = '+';
|
char sign_local_to_UTC = '+';
|
||||||
|
@ -120,7 +120,8 @@ class os: AllStatic {
|
|||||||
// Return current local time in a string (YYYY-MM-DD HH:MM:SS).
|
// Return current local time in a string (YYYY-MM-DD HH:MM:SS).
|
||||||
// It is MT safe, but not async-safe, as reading time zone
|
// It is MT safe, but not async-safe, as reading time zone
|
||||||
// information may require a lock on some platforms.
|
// information may require a lock on some platforms.
|
||||||
static char* local_time_string(char *buf, size_t buflen);
|
static char* local_time_string(char *buf, size_t buflen);
|
||||||
|
static struct tm* localtime_pd (const time_t* clock, struct tm* res);
|
||||||
// Fill in buffer with current local time as an ISO-8601 string.
|
// Fill in buffer with current local time as an ISO-8601 string.
|
||||||
// E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz.
|
// E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz.
|
||||||
// Returns buffer, or NULL if it failed.
|
// Returns buffer, or NULL if it failed.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
* Copyright 1997-2009 Sun Microsystems, Inc. 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
|
||||||
@ -74,6 +74,7 @@ extern int BytesPerHeapOop;
|
|||||||
extern int BitsPerHeapOop;
|
extern int BitsPerHeapOop;
|
||||||
|
|
||||||
const int BitsPerJavaInteger = 32;
|
const int BitsPerJavaInteger = 32;
|
||||||
|
const int BitsPerJavaLong = 64;
|
||||||
const int BitsPerSize_t = size_tSize * BitsPerByte;
|
const int BitsPerSize_t = size_tSize * BitsPerByte;
|
||||||
|
|
||||||
// Size of a char[] needed to represent a jint as a string in decimal.
|
// Size of a char[] needed to represent a jint as a string in decimal.
|
||||||
@ -906,6 +907,14 @@ inline int exact_log2(intptr_t x) {
|
|||||||
return log2_intptr(x);
|
return log2_intptr(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//* the argument must be exactly a power of 2
|
||||||
|
inline int exact_log2_long(jlong x) {
|
||||||
|
#ifdef ASSERT
|
||||||
|
if (!is_power_of_2_long(x)) basic_fatal("x must be a power of 2");
|
||||||
|
#endif
|
||||||
|
return log2_long(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// returns integer round-up to the nearest multiple of s (s must be a power of two)
|
// returns integer round-up to the nearest multiple of s (s must be a power of two)
|
||||||
inline intptr_t round_to(intptr_t x, uintx s) {
|
inline intptr_t round_to(intptr_t x, uintx s) {
|
||||||
|
@ -25,6 +25,12 @@
|
|||||||
# include "incls/_precompiled.incl"
|
# include "incls/_precompiled.incl"
|
||||||
# include "incls/_taskqueue.cpp.incl"
|
# include "incls/_taskqueue.cpp.incl"
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
uint ParallelTaskTerminator::_total_yields = 0;
|
||||||
|
uint ParallelTaskTerminator::_total_spins = 0;
|
||||||
|
uint ParallelTaskTerminator::_total_peeks = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool TaskQueueSuper::peek() {
|
bool TaskQueueSuper::peek() {
|
||||||
return _bottom != _age.top();
|
return _bottom != _age.top();
|
||||||
}
|
}
|
||||||
@ -69,15 +75,62 @@ bool
|
|||||||
ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
|
ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
|
||||||
Atomic::inc(&_offered_termination);
|
Atomic::inc(&_offered_termination);
|
||||||
|
|
||||||
juint yield_count = 0;
|
uint yield_count = 0;
|
||||||
|
// Number of hard spin loops done since last yield
|
||||||
|
uint hard_spin_count = 0;
|
||||||
|
// Number of iterations in the hard spin loop.
|
||||||
|
uint hard_spin_limit = WorkStealingHardSpins;
|
||||||
|
|
||||||
|
// If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
|
||||||
|
// If it is greater than 0, then start with a small number
|
||||||
|
// of spins and increase number with each turn at spinning until
|
||||||
|
// the count of hard spins exceeds WorkStealingSpinToYieldRatio.
|
||||||
|
// Then do a yield() call and start spinning afresh.
|
||||||
|
if (WorkStealingSpinToYieldRatio > 0) {
|
||||||
|
hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
|
||||||
|
hard_spin_limit = MAX2(hard_spin_limit, 1U);
|
||||||
|
}
|
||||||
|
// Remember the initial spin limit.
|
||||||
|
uint hard_spin_start = hard_spin_limit;
|
||||||
|
|
||||||
|
// Loop waiting for all threads to offer termination or
|
||||||
|
// more work.
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Are all threads offering termination?
|
||||||
if (_offered_termination == _n_threads) {
|
if (_offered_termination == _n_threads) {
|
||||||
//inner_termination_loop();
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
// Look for more work.
|
||||||
|
// Periodically sleep() instead of yield() to give threads
|
||||||
|
// waiting on the cores the chance to grab this code
|
||||||
if (yield_count <= WorkStealingYieldsBeforeSleep) {
|
if (yield_count <= WorkStealingYieldsBeforeSleep) {
|
||||||
|
// Do a yield or hardspin. For purposes of deciding whether
|
||||||
|
// to sleep, count this as a yield.
|
||||||
yield_count++;
|
yield_count++;
|
||||||
yield();
|
|
||||||
|
// Periodically call yield() instead spinning
|
||||||
|
// After WorkStealingSpinToYieldRatio spins, do a yield() call
|
||||||
|
// and reset the counts and starting limit.
|
||||||
|
if (hard_spin_count > WorkStealingSpinToYieldRatio) {
|
||||||
|
yield();
|
||||||
|
hard_spin_count = 0;
|
||||||
|
hard_spin_limit = hard_spin_start;
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
_total_yields++;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
// Hard spin this time
|
||||||
|
// Increase the hard spinning period but only up to a limit.
|
||||||
|
hard_spin_limit = MIN2(2*hard_spin_limit,
|
||||||
|
(uint) WorkStealingHardSpins);
|
||||||
|
for (uint j = 0; j < hard_spin_limit; j++) {
|
||||||
|
SpinPause();
|
||||||
|
}
|
||||||
|
hard_spin_count++;
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
_total_spins++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (PrintGCDetails && Verbose) {
|
if (PrintGCDetails && Verbose) {
|
||||||
gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
|
gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
|
||||||
@ -92,6 +145,9 @@ ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
|
|||||||
sleep(WorkStealingSleepMillis);
|
sleep(WorkStealingSleepMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
_total_peeks++;
|
||||||
|
#endif
|
||||||
if (peek_in_queue_set() ||
|
if (peek_in_queue_set() ||
|
||||||
(terminator != NULL && terminator->should_exit_termination())) {
|
(terminator != NULL && terminator->should_exit_termination())) {
|
||||||
Atomic::dec(&_offered_termination);
|
Atomic::dec(&_offered_termination);
|
||||||
@ -101,6 +157,16 @@ ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
void ParallelTaskTerminator::print_termination_counts() {
|
||||||
|
gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %lld "
|
||||||
|
"Total spins: %lld Total peeks: %lld",
|
||||||
|
total_yields(),
|
||||||
|
total_spins(),
|
||||||
|
total_peeks());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void ParallelTaskTerminator::reset_for_reuse() {
|
void ParallelTaskTerminator::reset_for_reuse() {
|
||||||
if (_offered_termination != 0) {
|
if (_offered_termination != 0) {
|
||||||
assert(_offered_termination == _n_threads,
|
assert(_offered_termination == _n_threads,
|
||||||
|
@ -22,67 +22,76 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef LP64
|
||||||
|
typedef juint TAG_TYPE;
|
||||||
|
// for a taskqueue size of 4M
|
||||||
|
#define LOG_TASKQ_SIZE 22
|
||||||
|
#else
|
||||||
|
typedef jushort TAG_TYPE;
|
||||||
|
// for a taskqueue size of 16K
|
||||||
|
#define LOG_TASKQ_SIZE 14
|
||||||
|
#endif
|
||||||
|
|
||||||
class TaskQueueSuper: public CHeapObj {
|
class TaskQueueSuper: public CHeapObj {
|
||||||
protected:
|
protected:
|
||||||
// The first free element after the last one pushed (mod _n).
|
// The first free element after the last one pushed (mod _n).
|
||||||
// (For now we'll assume only 32-bit CAS).
|
volatile uint _bottom;
|
||||||
volatile juint _bottom;
|
|
||||||
|
|
||||||
// log2 of the size of the queue.
|
// log2 of the size of the queue.
|
||||||
enum SomeProtectedConstants {
|
enum SomeProtectedConstants {
|
||||||
Log_n = 14
|
Log_n = LOG_TASKQ_SIZE
|
||||||
};
|
};
|
||||||
|
#undef LOG_TASKQ_SIZE
|
||||||
|
|
||||||
// Size of the queue.
|
// Size of the queue.
|
||||||
juint n() { return (1 << Log_n); }
|
uint n() { return (1 << Log_n); }
|
||||||
// For computing "x mod n" efficiently.
|
// For computing "x mod n" efficiently.
|
||||||
juint n_mod_mask() { return n() - 1; }
|
uint n_mod_mask() { return n() - 1; }
|
||||||
|
|
||||||
struct Age {
|
struct Age {
|
||||||
jushort _top;
|
TAG_TYPE _top;
|
||||||
jushort _tag;
|
TAG_TYPE _tag;
|
||||||
|
|
||||||
jushort tag() const { return _tag; }
|
TAG_TYPE tag() const { return _tag; }
|
||||||
jushort top() const { return _top; }
|
TAG_TYPE top() const { return _top; }
|
||||||
|
|
||||||
Age() { _tag = 0; _top = 0; }
|
Age() { _tag = 0; _top = 0; }
|
||||||
|
|
||||||
friend bool operator ==(const Age& a1, const Age& a2) {
|
friend bool operator ==(const Age& a1, const Age& a2) {
|
||||||
return a1.tag() == a2.tag() && a1.top() == a2.top();
|
return a1.tag() == a2.tag() && a1.top() == a2.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
Age _age;
|
Age _age;
|
||||||
// These make sure we do single atomic reads and writes.
|
// These make sure we do single atomic reads and writes.
|
||||||
Age get_age() {
|
Age get_age() {
|
||||||
jint res = *(volatile jint*)(&_age);
|
uint res = *(volatile uint*)(&_age);
|
||||||
return *(Age*)(&res);
|
return *(Age*)(&res);
|
||||||
}
|
}
|
||||||
void set_age(Age a) {
|
void set_age(Age a) {
|
||||||
*(volatile jint*)(&_age) = *(int*)(&a);
|
*(volatile uint*)(&_age) = *(uint*)(&a);
|
||||||
}
|
}
|
||||||
|
|
||||||
jushort get_top() {
|
TAG_TYPE get_top() {
|
||||||
return get_age().top();
|
return get_age().top();
|
||||||
}
|
}
|
||||||
|
|
||||||
// These both operate mod _n.
|
// These both operate mod _n.
|
||||||
juint increment_index(juint ind) {
|
uint increment_index(uint ind) {
|
||||||
return (ind + 1) & n_mod_mask();
|
return (ind + 1) & n_mod_mask();
|
||||||
}
|
}
|
||||||
juint decrement_index(juint ind) {
|
uint decrement_index(uint ind) {
|
||||||
return (ind - 1) & n_mod_mask();
|
return (ind - 1) & n_mod_mask();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a number in the range [0.._n). If the result is "n-1", it
|
// Returns a number in the range [0.._n). If the result is "n-1", it
|
||||||
// should be interpreted as 0.
|
// should be interpreted as 0.
|
||||||
juint dirty_size(juint bot, juint top) {
|
uint dirty_size(uint bot, uint top) {
|
||||||
return ((jint)bot - (jint)top) & n_mod_mask();
|
return ((int)bot - (int)top) & n_mod_mask();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the size corresponding to the given "bot" and "top".
|
// Returns the size corresponding to the given "bot" and "top".
|
||||||
juint size(juint bot, juint top) {
|
uint size(uint bot, uint top) {
|
||||||
juint sz = dirty_size(bot, top);
|
uint sz = dirty_size(bot, top);
|
||||||
// Has the queue "wrapped", so that bottom is less than top?
|
// Has the queue "wrapped", so that bottom is less than top?
|
||||||
// There's a complicated special case here. A pair of threads could
|
// There's a complicated special case here. A pair of threads could
|
||||||
// perform pop_local and pop_global operations concurrently, starting
|
// perform pop_local and pop_global operations concurrently, starting
|
||||||
@ -94,7 +103,7 @@ protected:
|
|||||||
// owner performs pop_local's, and several concurrent threads
|
// owner performs pop_local's, and several concurrent threads
|
||||||
// attempting to perform the pop_global will all perform the same CAS,
|
// attempting to perform the pop_global will all perform the same CAS,
|
||||||
// and only one can succeed. Any stealing thread that reads after
|
// and only one can succeed. Any stealing thread that reads after
|
||||||
// either the increment or decrement will seen an empty queue, and will
|
// either the increment or decrement will see an empty queue, and will
|
||||||
// not join the competitors. The "sz == -1 || sz == _n-1" state will
|
// not join the competitors. The "sz == -1 || sz == _n-1" state will
|
||||||
// not be modified by concurrent queues, so the owner thread can reset
|
// not be modified by concurrent queues, so the owner thread can reset
|
||||||
// the state to _bottom == top so subsequent pushes will be performed
|
// the state to _bottom == top so subsequent pushes will be performed
|
||||||
@ -112,11 +121,11 @@ public:
|
|||||||
// Return an estimate of the number of elements in the queue.
|
// Return an estimate of the number of elements in the queue.
|
||||||
// The "careful" version admits the possibility of pop_local/pop_global
|
// The "careful" version admits the possibility of pop_local/pop_global
|
||||||
// races.
|
// races.
|
||||||
juint size() {
|
uint size() {
|
||||||
return size(_bottom, get_top());
|
return size(_bottom, get_top());
|
||||||
}
|
}
|
||||||
|
|
||||||
juint dirty_size() {
|
uint dirty_size() {
|
||||||
return dirty_size(_bottom, get_top());
|
return dirty_size(_bottom, get_top());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,15 +136,15 @@ public:
|
|||||||
|
|
||||||
// Maximum number of elements allowed in the queue. This is two less
|
// Maximum number of elements allowed in the queue. This is two less
|
||||||
// than the actual queue size, for somewhat complicated reasons.
|
// than the actual queue size, for somewhat complicated reasons.
|
||||||
juint max_elems() { return n() - 2; }
|
uint max_elems() { return n() - 2; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class E> class GenericTaskQueue: public TaskQueueSuper {
|
template<class E> class GenericTaskQueue: public TaskQueueSuper {
|
||||||
private:
|
private:
|
||||||
// Slow paths for push, pop_local. (pop_global has no fast path.)
|
// Slow paths for push, pop_local. (pop_global has no fast path.)
|
||||||
bool push_slow(E t, juint dirty_n_elems);
|
bool push_slow(E t, uint dirty_n_elems);
|
||||||
bool pop_local_slow(juint localBot, Age oldAge);
|
bool pop_local_slow(uint localBot, Age oldAge);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initializes the queue to empty.
|
// Initializes the queue to empty.
|
||||||
@ -170,7 +179,7 @@ private:
|
|||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
GenericTaskQueue<E>::GenericTaskQueue():TaskQueueSuper() {
|
GenericTaskQueue<E>::GenericTaskQueue():TaskQueueSuper() {
|
||||||
assert(sizeof(Age) == sizeof(jint), "Depends on this.");
|
assert(sizeof(Age) == sizeof(int), "Depends on this.");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
@ -182,9 +191,9 @@ void GenericTaskQueue<E>::initialize() {
|
|||||||
template<class E>
|
template<class E>
|
||||||
void GenericTaskQueue<E>::oops_do(OopClosure* f) {
|
void GenericTaskQueue<E>::oops_do(OopClosure* f) {
|
||||||
// tty->print_cr("START OopTaskQueue::oops_do");
|
// tty->print_cr("START OopTaskQueue::oops_do");
|
||||||
int iters = size();
|
uint iters = size();
|
||||||
juint index = _bottom;
|
uint index = _bottom;
|
||||||
for (int i = 0; i < iters; ++i) {
|
for (uint i = 0; i < iters; ++i) {
|
||||||
index = decrement_index(index);
|
index = decrement_index(index);
|
||||||
// tty->print_cr(" doing entry %d," INTPTR_T " -> " INTPTR_T,
|
// tty->print_cr(" doing entry %d," INTPTR_T " -> " INTPTR_T,
|
||||||
// index, &_elems[index], _elems[index]);
|
// index, &_elems[index], _elems[index]);
|
||||||
@ -198,10 +207,10 @@ void GenericTaskQueue<E>::oops_do(OopClosure* f) {
|
|||||||
|
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueue<E>::push_slow(E t, juint dirty_n_elems) {
|
bool GenericTaskQueue<E>::push_slow(E t, uint dirty_n_elems) {
|
||||||
if (dirty_n_elems == n() - 1) {
|
if (dirty_n_elems == n() - 1) {
|
||||||
// Actually means 0, so do the push.
|
// Actually means 0, so do the push.
|
||||||
juint localBot = _bottom;
|
uint localBot = _bottom;
|
||||||
_elems[localBot] = t;
|
_elems[localBot] = t;
|
||||||
_bottom = increment_index(localBot);
|
_bottom = increment_index(localBot);
|
||||||
return true;
|
return true;
|
||||||
@ -211,7 +220,7 @@ bool GenericTaskQueue<E>::push_slow(E t, juint dirty_n_elems) {
|
|||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueue<E>::
|
bool GenericTaskQueue<E>::
|
||||||
pop_local_slow(juint localBot, Age oldAge) {
|
pop_local_slow(uint localBot, Age oldAge) {
|
||||||
// This queue was observed to contain exactly one element; either this
|
// This queue was observed to contain exactly one element; either this
|
||||||
// thread will claim it, or a competing "pop_global". In either case,
|
// thread will claim it, or a competing "pop_global". In either case,
|
||||||
// the queue will be logically empty afterwards. Create a new Age value
|
// the queue will be logically empty afterwards. Create a new Age value
|
||||||
@ -230,9 +239,8 @@ pop_local_slow(juint localBot, Age oldAge) {
|
|||||||
Age tempAge;
|
Age tempAge;
|
||||||
// No competing pop_global has yet incremented "top"; we'll try to
|
// No competing pop_global has yet incremented "top"; we'll try to
|
||||||
// install new_age, thus claiming the element.
|
// install new_age, thus claiming the element.
|
||||||
assert(sizeof(Age) == sizeof(jint) && sizeof(jint) == sizeof(juint),
|
assert(sizeof(Age) == sizeof(int), "Assumption about CAS unit.");
|
||||||
"Assumption about CAS unit.");
|
*(uint*)&tempAge = Atomic::cmpxchg(*(uint*)&newAge, (volatile uint*)&_age, *(uint*)&oldAge);
|
||||||
*(jint*)&tempAge = Atomic::cmpxchg(*(jint*)&newAge, (volatile jint*)&_age, *(jint*)&oldAge);
|
|
||||||
if (tempAge == oldAge) {
|
if (tempAge == oldAge) {
|
||||||
// We win.
|
// We win.
|
||||||
assert(dirty_size(localBot, get_top()) != n() - 1,
|
assert(dirty_size(localBot, get_top()) != n() - 1,
|
||||||
@ -253,8 +261,8 @@ template<class E>
|
|||||||
bool GenericTaskQueue<E>::pop_global(E& t) {
|
bool GenericTaskQueue<E>::pop_global(E& t) {
|
||||||
Age newAge;
|
Age newAge;
|
||||||
Age oldAge = get_age();
|
Age oldAge = get_age();
|
||||||
juint localBot = _bottom;
|
uint localBot = _bottom;
|
||||||
juint n_elems = size(localBot, oldAge.top());
|
uint n_elems = size(localBot, oldAge.top());
|
||||||
if (n_elems == 0) {
|
if (n_elems == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -263,7 +271,7 @@ bool GenericTaskQueue<E>::pop_global(E& t) {
|
|||||||
newAge._top = increment_index(newAge.top());
|
newAge._top = increment_index(newAge.top());
|
||||||
if ( newAge._top == 0 ) newAge._tag++;
|
if ( newAge._top == 0 ) newAge._tag++;
|
||||||
Age resAge;
|
Age resAge;
|
||||||
*(jint*)&resAge = Atomic::cmpxchg(*(jint*)&newAge, (volatile jint*)&_age, *(jint*)&oldAge);
|
*(uint*)&resAge = Atomic::cmpxchg(*(uint*)&newAge, (volatile uint*)&_age, *(uint*)&oldAge);
|
||||||
// Note that using "_bottom" here might fail, since a pop_local might
|
// Note that using "_bottom" here might fail, since a pop_local might
|
||||||
// have decremented it.
|
// have decremented it.
|
||||||
assert(dirty_size(localBot, newAge._top) != n() - 1,
|
assert(dirty_size(localBot, newAge._top) != n() - 1,
|
||||||
@ -287,7 +295,7 @@ public:
|
|||||||
|
|
||||||
template<class E> class GenericTaskQueueSet: public TaskQueueSetSuper {
|
template<class E> class GenericTaskQueueSet: public TaskQueueSetSuper {
|
||||||
private:
|
private:
|
||||||
int _n;
|
uint _n;
|
||||||
GenericTaskQueue<E>** _queues;
|
GenericTaskQueue<E>** _queues;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -300,51 +308,51 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool steal_1_random(int queue_num, int* seed, E& t);
|
bool steal_1_random(uint queue_num, int* seed, E& t);
|
||||||
bool steal_best_of_2(int queue_num, int* seed, E& t);
|
bool steal_best_of_2(uint queue_num, int* seed, E& t);
|
||||||
bool steal_best_of_all(int queue_num, int* seed, E& t);
|
bool steal_best_of_all(uint queue_num, int* seed, E& t);
|
||||||
|
|
||||||
void register_queue(int i, GenericTaskQueue<E>* q);
|
void register_queue(uint i, GenericTaskQueue<E>* q);
|
||||||
|
|
||||||
GenericTaskQueue<E>* queue(int n);
|
GenericTaskQueue<E>* queue(uint n);
|
||||||
|
|
||||||
// The thread with queue number "queue_num" (and whose random number seed
|
// The thread with queue number "queue_num" (and whose random number seed
|
||||||
// is at "seed") is trying to steal a task from some other queue. (It
|
// is at "seed") is trying to steal a task from some other queue. (It
|
||||||
// may try several queues, according to some configuration parameter.)
|
// may try several queues, according to some configuration parameter.)
|
||||||
// If some steal succeeds, returns "true" and sets "t" the stolen task,
|
// If some steal succeeds, returns "true" and sets "t" the stolen task,
|
||||||
// otherwise returns false.
|
// otherwise returns false.
|
||||||
bool steal(int queue_num, int* seed, E& t);
|
bool steal(uint queue_num, int* seed, E& t);
|
||||||
|
|
||||||
bool peek();
|
bool peek();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
void GenericTaskQueueSet<E>::register_queue(int i, GenericTaskQueue<E>* q) {
|
void GenericTaskQueueSet<E>::register_queue(uint i, GenericTaskQueue<E>* q) {
|
||||||
assert(0 <= i && i < _n, "index out of range.");
|
assert(i < _n, "index out of range.");
|
||||||
_queues[i] = q;
|
_queues[i] = q;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
GenericTaskQueue<E>* GenericTaskQueueSet<E>::queue(int i) {
|
GenericTaskQueue<E>* GenericTaskQueueSet<E>::queue(uint i) {
|
||||||
return _queues[i];
|
return _queues[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueueSet<E>::steal(int queue_num, int* seed, E& t) {
|
bool GenericTaskQueueSet<E>::steal(uint queue_num, int* seed, E& t) {
|
||||||
for (int i = 0; i < 2 * _n; i++)
|
for (uint i = 0; i < 2 * _n; i++)
|
||||||
if (steal_best_of_2(queue_num, seed, t))
|
if (steal_best_of_2(queue_num, seed, t))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueueSet<E>::steal_best_of_all(int queue_num, int* seed, E& t) {
|
bool GenericTaskQueueSet<E>::steal_best_of_all(uint queue_num, int* seed, E& t) {
|
||||||
if (_n > 2) {
|
if (_n > 2) {
|
||||||
int best_k;
|
int best_k;
|
||||||
jint best_sz = 0;
|
uint best_sz = 0;
|
||||||
for (int k = 0; k < _n; k++) {
|
for (uint k = 0; k < _n; k++) {
|
||||||
if (k == queue_num) continue;
|
if (k == queue_num) continue;
|
||||||
jint sz = _queues[k]->size();
|
uint sz = _queues[k]->size();
|
||||||
if (sz > best_sz) {
|
if (sz > best_sz) {
|
||||||
best_sz = sz;
|
best_sz = sz;
|
||||||
best_k = k;
|
best_k = k;
|
||||||
@ -362,9 +370,9 @@ bool GenericTaskQueueSet<E>::steal_best_of_all(int queue_num, int* seed, E& t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueueSet<E>::steal_1_random(int queue_num, int* seed, E& t) {
|
bool GenericTaskQueueSet<E>::steal_1_random(uint queue_num, int* seed, E& t) {
|
||||||
if (_n > 2) {
|
if (_n > 2) {
|
||||||
int k = queue_num;
|
uint k = queue_num;
|
||||||
while (k == queue_num) k = randomParkAndMiller(seed) % _n;
|
while (k == queue_num) k = randomParkAndMiller(seed) % _n;
|
||||||
return _queues[2]->pop_global(t);
|
return _queues[2]->pop_global(t);
|
||||||
} else if (_n == 2) {
|
} else if (_n == 2) {
|
||||||
@ -378,20 +386,20 @@ bool GenericTaskQueueSet<E>::steal_1_random(int queue_num, int* seed, E& t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueueSet<E>::steal_best_of_2(int queue_num, int* seed, E& t) {
|
bool GenericTaskQueueSet<E>::steal_best_of_2(uint queue_num, int* seed, E& t) {
|
||||||
if (_n > 2) {
|
if (_n > 2) {
|
||||||
int k1 = queue_num;
|
uint k1 = queue_num;
|
||||||
while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n;
|
while (k1 == queue_num) k1 = randomParkAndMiller(seed) % _n;
|
||||||
int k2 = queue_num;
|
uint k2 = queue_num;
|
||||||
while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n;
|
while (k2 == queue_num || k2 == k1) k2 = randomParkAndMiller(seed) % _n;
|
||||||
// Sample both and try the larger.
|
// Sample both and try the larger.
|
||||||
juint sz1 = _queues[k1]->size();
|
uint sz1 = _queues[k1]->size();
|
||||||
juint sz2 = _queues[k2]->size();
|
uint sz2 = _queues[k2]->size();
|
||||||
if (sz2 > sz1) return _queues[k2]->pop_global(t);
|
if (sz2 > sz1) return _queues[k2]->pop_global(t);
|
||||||
else return _queues[k1]->pop_global(t);
|
else return _queues[k1]->pop_global(t);
|
||||||
} else if (_n == 2) {
|
} else if (_n == 2) {
|
||||||
// Just try the other one.
|
// Just try the other one.
|
||||||
int k = (queue_num + 1) % 2;
|
uint k = (queue_num + 1) % 2;
|
||||||
return _queues[k]->pop_global(t);
|
return _queues[k]->pop_global(t);
|
||||||
} else {
|
} else {
|
||||||
assert(_n == 1, "can't be zero.");
|
assert(_n == 1, "can't be zero.");
|
||||||
@ -402,7 +410,7 @@ bool GenericTaskQueueSet<E>::steal_best_of_2(int queue_num, int* seed, E& t) {
|
|||||||
template<class E>
|
template<class E>
|
||||||
bool GenericTaskQueueSet<E>::peek() {
|
bool GenericTaskQueueSet<E>::peek() {
|
||||||
// Try all the queues.
|
// Try all the queues.
|
||||||
for (int j = 0; j < _n; j++) {
|
for (uint j = 0; j < _n; j++) {
|
||||||
if (_queues[j]->peek())
|
if (_queues[j]->peek())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -418,11 +426,19 @@ public:
|
|||||||
// A class to aid in the termination of a set of parallel tasks using
|
// A class to aid in the termination of a set of parallel tasks using
|
||||||
// TaskQueueSet's for work stealing.
|
// TaskQueueSet's for work stealing.
|
||||||
|
|
||||||
|
#undef TRACESPINNING
|
||||||
|
|
||||||
class ParallelTaskTerminator: public StackObj {
|
class ParallelTaskTerminator: public StackObj {
|
||||||
private:
|
private:
|
||||||
int _n_threads;
|
int _n_threads;
|
||||||
TaskQueueSetSuper* _queue_set;
|
TaskQueueSetSuper* _queue_set;
|
||||||
jint _offered_termination;
|
int _offered_termination;
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
static uint _total_yields;
|
||||||
|
static uint _total_spins;
|
||||||
|
static uint _total_peeks;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool peek_in_queue_set();
|
bool peek_in_queue_set();
|
||||||
protected:
|
protected:
|
||||||
@ -454,13 +470,19 @@ public:
|
|||||||
// the terminator is finished.
|
// the terminator is finished.
|
||||||
void reset_for_reuse();
|
void reset_for_reuse();
|
||||||
|
|
||||||
|
#ifdef TRACESPINNING
|
||||||
|
static uint total_yields() { return _total_yields; }
|
||||||
|
static uint total_spins() { return _total_spins; }
|
||||||
|
static uint total_peeks() { return _total_peeks; }
|
||||||
|
static void print_termination_counts();
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SIMPLE_STACK 0
|
#define SIMPLE_STACK 0
|
||||||
|
|
||||||
template<class E> inline bool GenericTaskQueue<E>::push(E t) {
|
template<class E> inline bool GenericTaskQueue<E>::push(E t) {
|
||||||
#if SIMPLE_STACK
|
#if SIMPLE_STACK
|
||||||
juint localBot = _bottom;
|
uint localBot = _bottom;
|
||||||
if (_bottom < max_elems()) {
|
if (_bottom < max_elems()) {
|
||||||
_elems[localBot] = t;
|
_elems[localBot] = t;
|
||||||
_bottom = localBot + 1;
|
_bottom = localBot + 1;
|
||||||
@ -469,10 +491,10 @@ template<class E> inline bool GenericTaskQueue<E>::push(E t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
juint localBot = _bottom;
|
uint localBot = _bottom;
|
||||||
assert((localBot >= 0) && (localBot < n()), "_bottom out of range.");
|
assert((localBot >= 0) && (localBot < n()), "_bottom out of range.");
|
||||||
jushort top = get_top();
|
TAG_TYPE top = get_top();
|
||||||
juint dirty_n_elems = dirty_size(localBot, top);
|
uint dirty_n_elems = dirty_size(localBot, top);
|
||||||
assert((dirty_n_elems >= 0) && (dirty_n_elems < n()),
|
assert((dirty_n_elems >= 0) && (dirty_n_elems < n()),
|
||||||
"n_elems out of range.");
|
"n_elems out of range.");
|
||||||
if (dirty_n_elems < max_elems()) {
|
if (dirty_n_elems < max_elems()) {
|
||||||
@ -487,19 +509,19 @@ template<class E> inline bool GenericTaskQueue<E>::push(E t) {
|
|||||||
|
|
||||||
template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) {
|
template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) {
|
||||||
#if SIMPLE_STACK
|
#if SIMPLE_STACK
|
||||||
juint localBot = _bottom;
|
uint localBot = _bottom;
|
||||||
assert(localBot > 0, "precondition.");
|
assert(localBot > 0, "precondition.");
|
||||||
localBot--;
|
localBot--;
|
||||||
t = _elems[localBot];
|
t = _elems[localBot];
|
||||||
_bottom = localBot;
|
_bottom = localBot;
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
juint localBot = _bottom;
|
uint localBot = _bottom;
|
||||||
// This value cannot be n-1. That can only occur as a result of
|
// This value cannot be n-1. That can only occur as a result of
|
||||||
// the assignment to bottom in this method. If it does, this method
|
// the assignment to bottom in this method. If it does, this method
|
||||||
// resets the size( to 0 before the next call (which is sequential,
|
// resets the size( to 0 before the next call (which is sequential,
|
||||||
// since this is pop_local.)
|
// since this is pop_local.)
|
||||||
juint dirty_n_elems = dirty_size(localBot, get_top());
|
uint dirty_n_elems = dirty_size(localBot, get_top());
|
||||||
assert(dirty_n_elems != n() - 1, "Shouldn't be possible...");
|
assert(dirty_n_elems != n() - 1, "Shouldn't be possible...");
|
||||||
if (dirty_n_elems == 0) return false;
|
if (dirty_n_elems == 0) return false;
|
||||||
localBot = decrement_index(localBot);
|
localBot = decrement_index(localBot);
|
||||||
@ -512,7 +534,7 @@ template<class E> inline bool GenericTaskQueue<E>::pop_local(E& t) {
|
|||||||
// If there's still at least one element in the queue, based on the
|
// If there's still at least one element in the queue, based on the
|
||||||
// "_bottom" and "age" we've read, then there can be no interference with
|
// "_bottom" and "age" we've read, then there can be no interference with
|
||||||
// a "pop_global" operation, and we're done.
|
// a "pop_global" operation, and we're done.
|
||||||
juint tp = get_top();
|
TAG_TYPE tp = get_top(); // XXX
|
||||||
if (size(localBot, tp) > 0) {
|
if (size(localBot, tp) > 0) {
|
||||||
assert(dirty_size(localBot, tp) != n() - 1,
|
assert(dirty_size(localBot, tp) != n() - 1,
|
||||||
"Shouldn't be possible...");
|
"Shouldn't be possible...");
|
||||||
@ -581,7 +603,7 @@ class RegionTaskQueueWithOverflow: public CHeapObj {
|
|||||||
bool is_empty();
|
bool is_empty();
|
||||||
bool stealable_is_empty();
|
bool stealable_is_empty();
|
||||||
bool overflow_is_empty();
|
bool overflow_is_empty();
|
||||||
juint stealable_size() { return _region_queue.size(); }
|
uint stealable_size() { return _region_queue.size(); }
|
||||||
RegionTaskQueue* task_queue() { return &_region_queue; }
|
RegionTaskQueue* task_queue() { return &_region_queue; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class WorkData;
|
|||||||
|
|
||||||
// An abstract task to be worked on by a gang.
|
// An abstract task to be worked on by a gang.
|
||||||
// You subclass this to supply your own work() method
|
// You subclass this to supply your own work() method
|
||||||
class AbstractGangTask: public CHeapObj {
|
class AbstractGangTask VALUE_OBJ_CLASS_SPEC {
|
||||||
public:
|
public:
|
||||||
// The abstract work method.
|
// The abstract work method.
|
||||||
// The argument tells you which member of the gang you are.
|
// The argument tells you which member of the gang you are.
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
|
|
||||||
# Get OS/ARCH specifics
|
# Get OS/ARCH specifics
|
||||||
OSNAME = $(shell uname -s)
|
OSNAME = $(shell uname -s)
|
||||||
SLASH_JAVA = /java
|
|
||||||
ifeq ($(OSNAME), SunOS)
|
ifeq ($(OSNAME), SunOS)
|
||||||
PLATFORM = solaris
|
PLATFORM = solaris
|
||||||
|
SLASH_JAVA = /java
|
||||||
ARCH = $(shell uname -p)
|
ARCH = $(shell uname -p)
|
||||||
ifeq ($(ARCH), i386)
|
ifeq ($(ARCH), i386)
|
||||||
ARCH=i586
|
ARCH=i586
|
||||||
@ -38,6 +38,7 @@ ifeq ($(OSNAME), SunOS)
|
|||||||
endif
|
endif
|
||||||
ifeq ($(OSNAME), Linux)
|
ifeq ($(OSNAME), Linux)
|
||||||
PLATFORM = linux
|
PLATFORM = linux
|
||||||
|
SLASH_JAVA = /java
|
||||||
ARCH = $(shell uname -m)
|
ARCH = $(shell uname -m)
|
||||||
ifeq ($(ARCH), i386)
|
ifeq ($(ARCH), i386)
|
||||||
ARCH = i586
|
ARCH = i586
|
||||||
@ -62,6 +63,10 @@ ifeq ($(OSNAME), Windows_NT)
|
|||||||
EXESUFFIX = .exe
|
EXESUFFIX = .exe
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef ALT_SLASH_JAVA
|
||||||
|
SLASH_JAVA = $(ALT_SLASH_JAVA)
|
||||||
|
endif
|
||||||
|
|
||||||
# Utilities used
|
# Utilities used
|
||||||
CD = cd
|
CD = cd
|
||||||
CP = cp
|
CP = cp
|
||||||
|
220
hotspot/test/compiler/6603011/Test.java
Normal file
220
hotspot/test/compiler/6603011/Test.java
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 6603011
|
||||||
|
* @summary long/int division by constant
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xcomp -Xbatch -XX:-Inline Test
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// -XX:-Inline is essential to this test so that verification functions
|
||||||
|
// divi, modi, divl and modl generate "plain" divides.
|
||||||
|
// -Xcomp -Xbatch are also useful to ensure the full range of
|
||||||
|
// dividend and divisor combinations are tested
|
||||||
|
//
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
|
class s {
|
||||||
|
static int divi(int dividend, int divisor) { return dividend / divisor; }
|
||||||
|
static int modi(int dividend, int divisor) { return dividend % divisor; }
|
||||||
|
static long divl(long dividend, long divisor) { return dividend / divisor; }
|
||||||
|
static long modl(long dividend, long divisor) { return dividend % divisor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test implements Runnable {
|
||||||
|
// Report verbose messages on failure; turn off to suppress
|
||||||
|
// too much output with gross numbers of failures.
|
||||||
|
static final boolean VERBOSE = true;
|
||||||
|
|
||||||
|
// Initailize DIVISOR so that it is final in this class.
|
||||||
|
static final int DIVISOR;
|
||||||
|
static {
|
||||||
|
int value = 0;
|
||||||
|
try {
|
||||||
|
value = Integer.decode(System.getProperty("divisor"));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
}
|
||||||
|
DIVISOR = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The methods of interest. We want the JIT to compile these
|
||||||
|
// and convert the divide into a multiply.
|
||||||
|
public int divbyI (int dividend) { return dividend / DIVISOR; }
|
||||||
|
public int modbyI (int dividend) { return dividend % DIVISOR; }
|
||||||
|
public long divbyL (long dividend) { return dividend / DIVISOR; }
|
||||||
|
public long modbyL (long dividend) { return dividend % DIVISOR; }
|
||||||
|
|
||||||
|
public int divisor() { return DIVISOR; }
|
||||||
|
|
||||||
|
public boolean checkI (int dividend) {
|
||||||
|
int quo = divbyI(dividend);
|
||||||
|
int rem = modbyI(dividend);
|
||||||
|
int quo0 = s.divi(dividend, divisor());
|
||||||
|
int rem0 = s.modi(dividend, divisor());
|
||||||
|
|
||||||
|
if (quo != quo0 || rem != rem0) {
|
||||||
|
if (VERBOSE) {
|
||||||
|
System.out.println("Computed: " + dividend + " / " + divisor() + " = " +
|
||||||
|
quo + ", " + dividend + " % " + divisor() + " = " + rem );
|
||||||
|
System.out.println("expected: " + dividend + " / " + divisor() + " = " +
|
||||||
|
quo0 + ", " + dividend + " % " + divisor() + " = " + rem0);
|
||||||
|
// Report sign of rem failure
|
||||||
|
if (rem != 0 && (rem ^ dividend) < 0) {
|
||||||
|
System.out.println(" rem & dividend have different signs");
|
||||||
|
}
|
||||||
|
// Report range of rem failure
|
||||||
|
if (java.lang.Math.abs(rem) >= java.lang.Math.abs(divisor())) {
|
||||||
|
System.out.println(" remainder out of range");
|
||||||
|
}
|
||||||
|
// Report quo/rem identity relationship failure
|
||||||
|
if ((quo * divisor()) + rem != dividend) {
|
||||||
|
System.out.println(" quotien/remainder invariant broken");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkL (long dividend) {
|
||||||
|
long quo = divbyL(dividend);
|
||||||
|
long rem = modbyL(dividend);
|
||||||
|
long quo0 = s.divl(dividend, divisor());
|
||||||
|
long rem0 = s.modl(dividend, divisor());
|
||||||
|
|
||||||
|
if (quo != quo0 || rem != rem0) {
|
||||||
|
if (VERBOSE) {
|
||||||
|
System.out.println(" " + dividend + " / " + divisor() + " = " +
|
||||||
|
quo + ", " + dividend + " % " + divisor() + " = " + rem);
|
||||||
|
// Report sign of rem failure
|
||||||
|
if (rem != 0 && (rem ^ dividend) < 0) {
|
||||||
|
System.out.println(" rem & dividend have different signs");
|
||||||
|
}
|
||||||
|
// Report range of rem failure
|
||||||
|
if (java.lang.Math.abs(rem) >= java.lang.Math.abs(divisor())) {
|
||||||
|
System.out.println(" remainder out of range");
|
||||||
|
}
|
||||||
|
// Report quo/rem identity relationship failure
|
||||||
|
if ((quo * divisor()) + rem != dividend) {
|
||||||
|
System.out.println(" (" + quo + " * " + divisor() + ") + " + rem + " != "
|
||||||
|
+ dividend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
// Don't try to divide by zero
|
||||||
|
if (divisor() == 0) return;
|
||||||
|
|
||||||
|
// Range of dividends to check. Try dividends from start to end
|
||||||
|
// inclusive, as well as variations on those values as shifted
|
||||||
|
// left.
|
||||||
|
int start = -1024;
|
||||||
|
int end = 1024;
|
||||||
|
|
||||||
|
// Test int division using a variety of dividends.
|
||||||
|
int wrong = 0;
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
outerloop:
|
||||||
|
for (int i = start; i <= end; i++) {
|
||||||
|
for (int s = 0; s < 32; s += 4) {
|
||||||
|
total++;
|
||||||
|
int dividend = i << s;
|
||||||
|
if (!checkI(dividend)) {
|
||||||
|
wrong++;
|
||||||
|
// Stop on the first failure
|
||||||
|
// break outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wrong > 0) {
|
||||||
|
System.out.println("divisor " + divisor() + ": " +
|
||||||
|
wrong + "/" + total + " wrong int divisions");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test long division using a variety of dividends.
|
||||||
|
wrong = 0;
|
||||||
|
total = 0;
|
||||||
|
|
||||||
|
outerloop:
|
||||||
|
for (int i = start; i <= end; i++) {
|
||||||
|
for (int s = 0; s < 64; s += 4) {
|
||||||
|
total++;
|
||||||
|
long dividend = i << s;
|
||||||
|
if (!checkL(dividend)) {
|
||||||
|
wrong++;
|
||||||
|
// Stop on the first failure
|
||||||
|
// break outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wrong > 0) {
|
||||||
|
System.out.println("divisor " + divisor() + ": " +
|
||||||
|
wrong + "/" + total + " wrong long divisions");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload this class with the "divisor" property set to the input parameter.
|
||||||
|
// This allows the JIT to see q.DIVISOR as a final constant, and change
|
||||||
|
// any divisions or mod operations into multiplies.
|
||||||
|
public static void test_divisor(int divisor,
|
||||||
|
URLClassLoader apploader) throws Exception {
|
||||||
|
System.setProperty("divisor", "" + divisor);
|
||||||
|
ClassLoader loader = new URLClassLoader(apploader.getURLs(),
|
||||||
|
apploader.getParent());
|
||||||
|
Class c = loader.loadClass("Test");
|
||||||
|
Runnable r = (Runnable)c.newInstance();
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Class cl = Class.forName("Test");
|
||||||
|
URLClassLoader apploader = (URLClassLoader)cl.getClassLoader();
|
||||||
|
|
||||||
|
|
||||||
|
// Test every divisor between -100 and 100.
|
||||||
|
for (int i = -100; i <= 100; i++) {
|
||||||
|
test_divisor(i, apploader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try a few divisors outside the typical range.
|
||||||
|
// The values below have been observed in rt.jar.
|
||||||
|
test_divisor(101, apploader);
|
||||||
|
test_divisor(400, apploader);
|
||||||
|
test_divisor(1000, apploader);
|
||||||
|
test_divisor(3600, apploader);
|
||||||
|
test_divisor(9973, apploader);
|
||||||
|
test_divisor(86400, apploader);
|
||||||
|
test_divisor(1000000, apploader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,7 +27,7 @@
|
|||||||
* @bug 6775880
|
* @bug 6775880
|
||||||
* @summary EA +DeoptimizeALot: assert(mon_info->owner()->is_locked(),"object must be locked now")
|
* @summary EA +DeoptimizeALot: assert(mon_info->owner()->is_locked(),"object must be locked now")
|
||||||
* @compile -source 1.4 -target 1.4 Test.java
|
* @compile -source 1.4 -target 1.4 Test.java
|
||||||
* @run main/othervm -server -Xbatch -XX:+DoEscapeAnalysis -XX:+DeoptimizeALot -XX:CompileCommand=exclude,java.lang.AbstractStringBuilder::append Test
|
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:+DoEscapeAnalysis -XX:+DeoptimizeALot -XX:CompileCommand=exclude,java.lang.AbstractStringBuilder::append Test
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class Test {
|
public class Test {
|
||||||
|
60
hotspot/test/compiler/6795161/Test.java
Normal file
60
hotspot/test/compiler/6795161/Test.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6795161
|
||||||
|
* @summary Escape analysis leads to data corruption
|
||||||
|
* @run main/othervm -server -Xcomp -XX:CompileOnly=Test -XX:+DoEscapeAnalysis Test
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Test_Class_1 {
|
||||||
|
static String var_1;
|
||||||
|
|
||||||
|
static void badFunc(int size)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 1; (new byte[size-i])[0] = 0, i++) {}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// don't comment it out, it will lead to correct results ;)
|
||||||
|
//System.out.println("Got exception: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
static String var_1_copy = Test_Class_1.var_1;
|
||||||
|
|
||||||
|
static byte var_check;
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
var_check = 1;
|
||||||
|
|
||||||
|
Test_Class_1.badFunc(-1);
|
||||||
|
|
||||||
|
System.out.println("EATester.var_check = " + Test.var_check + " (expected 1)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
48
hotspot/test/compiler/6795362/Test6795362.java
Normal file
48
hotspot/test/compiler/6795362/Test6795362.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 6795362
|
||||||
|
* @summary 32bit server compiler leads to wrong results on solaris-x86
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xcomp -XX:CompileOnly=Test6795362.sub Test6795362
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Test6795362 {
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
sub();
|
||||||
|
|
||||||
|
if (var_bad != 0)
|
||||||
|
throw new InternalError(var_bad + " != 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
static long var_bad = -1L;
|
||||||
|
|
||||||
|
static void sub()
|
||||||
|
{
|
||||||
|
var_bad >>= 65;
|
||||||
|
var_bad /= 65;
|
||||||
|
}
|
||||||
|
}
|
47
hotspot/test/compiler/6799693/Test.java
Normal file
47
hotspot/test/compiler/6799693/Test.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6799693
|
||||||
|
* @summary Server compiler leads to data corruption when expression throws an Exception
|
||||||
|
* @run main/othervm -Xcomp -XX:CompileOnly=Test Test
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
static int var_bad = 1;
|
||||||
|
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
var_bad++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 10; i++) (new byte[((byte)-1 << i)])[0] = 0;
|
||||||
|
}
|
||||||
|
catch (Exception e) { System.out.println("Got " + e); }
|
||||||
|
|
||||||
|
System.out.println("Test.var_bad = " + var_bad + " (expected 2)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
109
hotspot/test/compiler/6800154/Test6800154.java
Normal file
109
hotspot/test/compiler/6800154/Test6800154.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 6800154
|
||||||
|
* @summary Add comments to long_by_long_mulhi() for better understandability
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xcomp -XX:CompileOnly=Test6800154.divcomp Test6800154
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
public class Test6800154 implements Runnable {
|
||||||
|
static final long[] DIVIDENDS = {
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
1423487,
|
||||||
|
4444441,
|
||||||
|
4918923241323L,
|
||||||
|
-1,
|
||||||
|
-24351,
|
||||||
|
0x3333,
|
||||||
|
0x0000000080000000L,
|
||||||
|
0x7fffffffffffffffL,
|
||||||
|
0x8000000000000000L
|
||||||
|
};
|
||||||
|
|
||||||
|
static final long[] DIVISORS = {
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
17,
|
||||||
|
12342,
|
||||||
|
24123,
|
||||||
|
143444,
|
||||||
|
123444442344L,
|
||||||
|
-1,
|
||||||
|
-2,
|
||||||
|
-4423423234231423L,
|
||||||
|
0x0000000080000000L,
|
||||||
|
0x7fffffffffffffffL,
|
||||||
|
0x8000000000000000L
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize DIVISOR so that it is final in this class.
|
||||||
|
static final long DIVISOR;
|
||||||
|
|
||||||
|
static {
|
||||||
|
long value = 0;
|
||||||
|
try {
|
||||||
|
value = Long.decode(System.getProperty("divisor"));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
}
|
||||||
|
DIVISOR = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception
|
||||||
|
{
|
||||||
|
Class cl = Class.forName("Test6800154");
|
||||||
|
URLClassLoader apploader = (URLClassLoader) cl.getClassLoader();
|
||||||
|
|
||||||
|
// Iterate over all divisors.
|
||||||
|
for (int i = 0; i < DIVISORS.length; i++) {
|
||||||
|
System.setProperty("divisor", "" + DIVISORS[i]);
|
||||||
|
ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent());
|
||||||
|
Class c = loader.loadClass("Test6800154");
|
||||||
|
Runnable r = (Runnable) c.newInstance();
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
// Iterate over all dividends.
|
||||||
|
for (int i = 0; i < DIVIDENDS.length; i++) {
|
||||||
|
long dividend = DIVIDENDS[i];
|
||||||
|
|
||||||
|
long expected = divint(dividend);
|
||||||
|
long result = divcomp(dividend);
|
||||||
|
|
||||||
|
if (result != expected)
|
||||||
|
throw new InternalError(dividend + " / " + DIVISOR + " failed: " + result + " != " + expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long divint(long a) { return a / DIVISOR; }
|
||||||
|
static long divcomp(long a) { return a / DIVISOR; }
|
||||||
|
}
|
80
hotspot/test/compiler/6805724/Test6805724.java
Normal file
80
hotspot/test/compiler/6805724/Test6805724.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 6805724
|
||||||
|
* @summary ModLNode::Ideal() generates functionally incorrect graph when divisor is any (2^k-1) constant.
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xcomp -XX:CompileOnly=Test6805724.fcomp Test6805724
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
public class Test6805724 implements Runnable {
|
||||||
|
// Initialize DIVISOR so that it is final in this class.
|
||||||
|
static final long DIVISOR; // 2^k-1 constant
|
||||||
|
|
||||||
|
static {
|
||||||
|
long value = 0;
|
||||||
|
try {
|
||||||
|
value = Long.decode(System.getProperty("divisor"));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// This one is required for the Class.forName() in main.
|
||||||
|
}
|
||||||
|
DIVISOR = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long fint(long x) {
|
||||||
|
return x % DIVISOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long fcomp(long x) {
|
||||||
|
return x % DIVISOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
long a = 0x617981E1L;
|
||||||
|
|
||||||
|
long expected = fint(a);
|
||||||
|
long result = fcomp(a);
|
||||||
|
|
||||||
|
if (result != expected)
|
||||||
|
throw new InternalError(result + " != " + expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
Class cl = Class.forName("Test6805724");
|
||||||
|
URLClassLoader apploader = (URLClassLoader) cl.getClassLoader();
|
||||||
|
|
||||||
|
// Iterate over all 2^k-1 divisors.
|
||||||
|
for (int k = 1; k < Long.SIZE; k++) {
|
||||||
|
long divisor = (1L << k) - 1;
|
||||||
|
System.setProperty("divisor", "" + divisor);
|
||||||
|
ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent());
|
||||||
|
Class c = loader.loadClass("Test6805724");
|
||||||
|
Runnable r = (Runnable) c.newInstance();
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,3 +22,4 @@ d8eb2738db6b148911177d9bcfe888109b7f2f71 jdk7-b44
|
|||||||
527b426497a259d0605d069e3930e838948531a6 jdk7-b45
|
527b426497a259d0605d069e3930e838948531a6 jdk7-b45
|
||||||
4b03e27a44090d1f646af28dc58f9ead827e24c7 jdk7-b46
|
4b03e27a44090d1f646af28dc58f9ead827e24c7 jdk7-b46
|
||||||
b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47
|
b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47
|
||||||
|
5fbd9ea7def17186693b6f7099b5d0dc73903eee jdk7-b48
|
||||||
|
Loading…
x
Reference in New Issue
Block a user