This commit is contained in:
Vladimir Kozlov 2011-12-08 10:27:33 -08:00
commit 98ac731a94
62 changed files with 1233 additions and 562 deletions

View File

@ -248,7 +248,7 @@ jprt.build.targets=${jprt.build.targets.${jprt.tools.default.release}}
jprt.my.solaris.sparc.test.targets= \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \
${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \
${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \
${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \
@ -267,7 +267,7 @@ jprt.my.solaris.sparc.test.targets= \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_G1, \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParOldGC, \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_default, \
${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \
${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \
@ -276,7 +276,7 @@ jprt.my.solaris.sparc.test.targets= \
jprt.my.solaris.sparcv9.test.targets= \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \
${jprt.my.solaris.sparcv9}-product-c2-runThese, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default, \
@ -294,7 +294,7 @@ jprt.my.solaris.sparcv9.test.targets= \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_G1, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParOldGC, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \
${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \
@ -303,7 +303,7 @@ jprt.my.solaris.sparcv9.test.targets= \
jprt.my.solaris.x64.test.targets= \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-scimark, \
${jprt.my.solaris.x64}-product-c2-runThese, \
${jprt.my.solaris.x64}-product-c2-runThese_Xcomp, \
@ -322,7 +322,7 @@ jprt.my.solaris.x64.test.targets= \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \
${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \
@ -331,7 +331,7 @@ jprt.my.solaris.x64.test.targets= \
jprt.my.solaris.i586.test.targets= \
${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \
${jprt.my.solaris.i586}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.solaris.i586}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \
${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \
${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp, \
@ -358,7 +358,7 @@ jprt.my.solaris.i586.test.targets= \
${jprt.my.solaris.i586}-product-c1-GCOld_G1, \
${jprt.my.solaris.i586}-product-c1-GCOld_ParOldGC, \
${jprt.my.solaris.i586}-fastdebug-c2-jbb_default, \
${jprt.my.solaris.i586}-fastdebug-c2-jbb_default_tiered, \
${jprt.my.solaris.i586}-fastdebug-c2-jbb_default_nontiered, \
${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \
${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \
${jprt.my.solaris.i586}-fastdebug-c2-jbb_G1, \
@ -366,7 +366,7 @@ jprt.my.solaris.i586.test.targets= \
jprt.my.linux.i586.test.targets = \
${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \
${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \
${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \
${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \
@ -386,7 +386,7 @@ jprt.my.linux.i586.test.targets = \
${jprt.my.linux.i586}-product-{c1|c2}-GCOld_G1, \
${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParOldGC, \
${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_default, \
${jprt.my.linux.i586}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.linux.i586}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \
${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \
${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_G1, \
@ -394,7 +394,7 @@ jprt.my.linux.i586.test.targets = \
jprt.my.linux.x64.test.targets = \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_default, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \
@ -411,14 +411,14 @@ jprt.my.linux.x64.test.targets = \
${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_G1, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_G1, \
${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParOldGC
jprt.my.windows.i586.test.targets = \
${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \
${jprt.my.windows.i586}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.windows.i586}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-scimark, \
${jprt.my.windows.i586}-product-{c1|c2}-runThese, \
${jprt.my.windows.i586}-product-{c1|c2}-runThese_Xcomp, \
@ -438,7 +438,7 @@ jprt.my.windows.i586.test.targets = \
${jprt.my.windows.i586}-product-{c1|c2}-GCOld_G1, \
${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParOldGC, \
${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \
${jprt.my.windows.i586}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.windows.i586}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \
${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \
${jprt.my.windows.i586}-product-{c1|c2}-jbb_G1, \
@ -446,7 +446,7 @@ jprt.my.windows.i586.test.targets = \
jprt.my.windows.x64.test.targets = \
${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98_tiered, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98_nontiered, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark, \
${jprt.my.windows.x64}-product-c2-runThese, \
${jprt.my.windows.x64}-product-c2-runThese_Xcomp, \
@ -465,7 +465,7 @@ jprt.my.windows.x64.test.targets = \
${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_G1, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default_tiered, \
${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \
${jprt.my.windows.x64}-product-c2-jbb_CMS, \
${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \
${jprt.my.windows.x64}-product-c2-jbb_G1, \
@ -473,9 +473,9 @@ jprt.my.windows.x64.test.targets = \
# Some basic "smoke" tests for OpenJDK builds
jprt.test.targets.open = \
${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98_tiered, \
${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98_tiered, \
${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98_tiered
${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98, \
${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98, \
${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98
# Testing for actual embedded builds is different to standard
jprt.my.linux.i586.test.targets.embedded = \

View File

@ -855,12 +855,6 @@ class Assembler : public AbstractAssembler {
Lookaside = 1 << 4
};
// test if x is within signed immediate range for nbits
static bool is_simm(intptr_t x, int nbits) { return -( intptr_t(1) << nbits-1 ) <= x && x < ( intptr_t(1) << nbits-1 ); }
// test if -4096 <= x <= 4095
static bool is_simm13(intptr_t x) { return is_simm(x, 13); }
static bool is_in_wdisp_range(address a, address b, int nbits) {
intptr_t d = intptr_t(b) - intptr_t(a);
return is_simm(d, nbits + 2);
@ -1203,7 +1197,7 @@ public:
if (!UseCBCond || cbcond_before()) return false;
intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc());
assert( (x & 3) == 0, "not word aligned");
return is_simm(x, 12);
return is_simm12(x);
}
// Tells assembler you know that next instruction is delayed

View File

@ -765,7 +765,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
add_debug_info_for_null_check_here(op->info());
__ load_klass(O0, G3_scratch);
if (__ is_simm13(op->vtable_offset())) {
if (Assembler::is_simm13(op->vtable_offset())) {
__ ld_ptr(G3_scratch, op->vtable_offset(), G5_method);
} else {
// This will generate 2 instructions

View File

@ -42,7 +42,7 @@ define_pd_global(bool, ProfileInterpreter, false);
#else
define_pd_global(bool, ProfileInterpreter, true);
#endif // CC_INTERP
define_pd_global(bool, TieredCompilation, false);
define_pd_global(bool, TieredCompilation, true);
define_pd_global(intx, CompileThreshold, 10000);
define_pd_global(intx, BackEdgeThreshold, 140000);

View File

@ -315,7 +315,7 @@ void MethodHandles::RicochetFrame::verify_clean(MacroAssembler* _masm) {
__ cmp_and_br_short(O7_temp, T_VOID, Assembler::equal, Assembler::pt, L_ok_4);
extract_conversion_vminfo(_masm, L5_conversion, O5_temp);
__ ld_ptr(L4_saved_args_base, __ argument_offset(O5_temp, O5_temp), O7_temp);
assert(__ is_simm13(RETURN_VALUE_PLACEHOLDER), "must be simm13");
assert(Assembler::is_simm13(RETURN_VALUE_PLACEHOLDER), "must be simm13");
__ cmp_and_brx_short(O7_temp, (int32_t) RETURN_VALUE_PLACEHOLDER, Assembler::equal, Assembler::pt, L_ok_4);
__ stop("damaged ricochet frame: RETURN_VALUE_PLACEHOLDER not found");
__ BIND(L_ok_4);

View File

@ -767,7 +767,7 @@ void AdapterGenerator::gen_c2i_adapter(
// In the 64bit build because of wider slots and STACKBIAS we can run
// out of bits in the displacement to do loads and stores. Use g3 as
// temporary displacement.
if (! __ is_simm13(extraspace)) {
if (!Assembler::is_simm13(extraspace)) {
__ set(extraspace, G3_scratch);
__ sub(SP, G3_scratch, SP);
} else {

View File

@ -566,7 +566,7 @@ int MachCallDynamicJavaNode::ret_addr_offset() {
} else {
klass_load_size = 1*BytesPerInstWord;
}
if( Assembler::is_simm13(v_off) ) {
if (Assembler::is_simm13(v_off)) {
return klass_load_size +
(2*BytesPerInstWord + // ld_ptr, ld_ptr
NativeCall::instruction_size); // call; delay slot
@ -1019,8 +1019,21 @@ void emit_hi(CodeBuffer &cbuf, int val) { }
//=============================================================================
const bool Matcher::constant_table_absolute_addressing = false;
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask;
const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask();
int Compile::ConstantTable::calculate_table_base_offset() const {
if (UseRDPCForConstantTableBase) {
// The table base offset might be less but then it fits into
// simm13 anyway and we are good (cf. MachConstantBaseNode::emit).
return Assembler::min_simm13();
} else {
int offset = -(size() / 2);
if (!Assembler::is_simm13(offset)) {
offset = Assembler::min_simm13();
}
return offset;
}
}
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
Compile* C = ra_->C;
@ -1028,8 +1041,9 @@ void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
MacroAssembler _masm(&cbuf);
Register r = as_Register(ra_->get_encode(this));
CodeSection* cs = __ code()->consts();
int consts_size = cs->align_at_start(cs->size());
CodeSection* consts_section = __ code()->consts();
int consts_size = consts_section->align_at_start(consts_section->size());
assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size));
if (UseRDPCForConstantTableBase) {
// For the following RDPC logic to work correctly the consts
@ -1037,30 +1051,37 @@ void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
// assert checks for that. The layout and the SECT_* constants
// are defined in src/share/vm/asm/codeBuffer.hpp.
assert(CodeBuffer::SECT_CONSTS + 1 == CodeBuffer::SECT_INSTS, "must be");
int offset = __ offset();
int insts_offset = __ offset();
// Layout:
//
// |----------- consts section ------------|----------- insts section -----------...
// |------ constant table -----|- padding -|------------------x----
// \ current PC (RDPC instruction)
// |<------------- consts_size ----------->|<- insts_offset ->|
// \ table base
// The table base offset is later added to the load displacement
// so it has to be negative.
int table_base_offset = -(consts_size + insts_offset);
int disp;
// If the displacement from the current PC to the constant table
// base fits into simm13 we set the constant table base to the
// current PC.
if (__ is_simm13(-(consts_size + offset))) {
constant_table.set_table_base_offset(-(consts_size + offset));
if (Assembler::is_simm13(table_base_offset)) {
constant_table.set_table_base_offset(table_base_offset);
disp = 0;
} else {
// If the offset of the top constant (last entry in the table)
// fits into simm13 we set the constant table base to the actual
// table base.
if (__ is_simm13(constant_table.top_offset())) {
constant_table.set_table_base_offset(0);
disp = consts_size + offset;
} else {
// Otherwise we set the constant table base in the middle of the
// constant table.
int half_consts_size = consts_size / 2;
assert(half_consts_size * 2 == consts_size, "sanity");
constant_table.set_table_base_offset(-half_consts_size); // table base offset gets added to the load displacement.
disp = half_consts_size + offset;
}
// Otherwise we set the constant table base offset to the
// maximum negative displacement of load instructions to keep
// the disp as small as possible:
//
// |<------------- consts_size ----------->|<- insts_offset ->|
// |<--------- min_simm13 --------->|<-------- disp --------->|
// \ table base
table_base_offset = Assembler::min_simm13();
constant_table.set_table_base_offset(table_base_offset);
disp = (consts_size + insts_offset) + table_base_offset;
}
__ rdpc(r);
@ -1072,8 +1093,7 @@ void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
}
else {
// Materialize the constant table base.
assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size));
address baseaddr = cs->start() + -(constant_table.table_base_offset());
address baseaddr = consts_section->start() + -(constant_table.table_base_offset());
RelocationHolder rspec = internal_word_Relocation::spec(baseaddr);
AddressLiteral base(baseaddr, rspec);
__ set(base, r);
@ -1169,6 +1189,13 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
__ save(SP, G3, SP);
}
C->set_frame_complete( __ offset() );
if (!UseRDPCForConstantTableBase && C->has_mach_constant_base_node()) {
// NOTE: We set the table base offset here because users might be
// emitted before MachConstantBaseNode.
Compile::ConstantTable& constant_table = C->constant_table();
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
}
}
uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
@ -1843,7 +1870,7 @@ const bool Matcher::convL2FSupported(void) {
bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) {
// The passed offset is relative to address of the branch.
// Don't need to adjust the offset.
return UseCBCond && Assembler::is_simm(offset, 12);
return UseCBCond && Assembler::is_simm12(offset);
}
const bool Matcher::isSimpleConstant64(jlong value) {
@ -1997,7 +2024,7 @@ RegMask Matcher::modL_proj_mask() {
}
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return L7_REGP_mask;
return L7_REGP_mask();
}
%}
@ -2072,8 +2099,8 @@ encode %{
%}
enc_class form3_mem_reg_long_unaligned_marshal( memory mem, iRegL reg ) %{
assert( Assembler::is_simm13($mem$$disp ), "need disp and disp+4" );
assert( Assembler::is_simm13($mem$$disp+4), "need disp and disp+4" );
assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4");
assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4");
guarantee($mem$$index == R_G0_enc, "double index?");
emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, R_O7_enc );
emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg );
@ -2082,8 +2109,8 @@ encode %{
%}
enc_class form3_mem_reg_double_unaligned( memory mem, RegD_low reg ) %{
assert( Assembler::is_simm13($mem$$disp ), "need disp and disp+4" );
assert( Assembler::is_simm13($mem$$disp+4), "need disp and disp+4" );
assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4");
assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4");
guarantee($mem$$index == R_G0_enc, "double index?");
// Load long with 2 instructions
emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg+0 );
@ -2563,7 +2590,7 @@ encode %{
}
int entry_offset = instanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes();
if( __ is_simm13(v_off) ) {
if (Assembler::is_simm13(v_off)) {
__ ld_ptr(G3, v_off, G5_method);
} else {
// Generate 2 instructions
@ -3336,7 +3363,7 @@ operand immI() %{
// Integer Immediate: 8-bit
operand immI8() %{
predicate(Assembler::is_simm(n->get_int(), 8));
predicate(Assembler::is_simm8(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
@ -3365,7 +3392,7 @@ operand immI13m7() %{
// Integer Immediate: 16-bit
operand immI16() %{
predicate(Assembler::is_simm(n->get_int(), 16));
predicate(Assembler::is_simm16(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
@ -3393,7 +3420,7 @@ operand immU6() %{
// Integer Immediate: 11-bit
operand immI11() %{
predicate(Assembler::is_simm(n->get_int(),11));
predicate(Assembler::is_simm11(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
@ -3402,7 +3429,7 @@ operand immI11() %{
// Integer Immediate: 5-bit
operand immI5() %{
predicate(Assembler::is_simm(n->get_int(), 5));
predicate(Assembler::is_simm5(n->get_int()));
match(ConI);
op_cost(0);
format %{ %}
@ -3634,7 +3661,7 @@ operand immL0() %{
// Integer Immediate: 5-bit
operand immL5() %{
predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm((int)n->get_long(), 5));
predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm5((int)n->get_long()));
match(ConL);
op_cost(0);
format %{ %}
@ -9251,13 +9278,16 @@ instruct jumpXtnd(iRegX switch_val, o7RegI table) %{
format %{ "ADD $constanttablebase, $constantoffset, O7\n\t"
"LD [O7 + $switch_val], O7\n\t"
"JUMP O7"
%}
"JUMP O7" %}
ins_encode %{
// Calculate table address into a register.
Register table_reg;
Register label_reg = O7;
if (constant_offset() == 0) {
// If we are calculating the size of this instruction don't trust
// zero offsets because they might change when
// MachConstantBaseNode decides to optimize the constant table
// base.
if ((constant_offset() == 0) && !Compile::current()->in_scratch_emit_size()) {
table_reg = $constanttablebase;
} else {
table_reg = O7;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -83,7 +83,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
}
#endif
int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes();
if( __ is_simm13(v_off) ) {
if (Assembler::is_simm13(v_off)) {
__ ld_ptr(G3, v_off, G5_method);
} else {
__ set(v_off,G5);

View File

@ -3535,7 +3535,8 @@ bool Assembler::reachable(AddressLiteral adr) {
// addressing.
bool Assembler::is_polling_page_far() {
intptr_t addr = (intptr_t)os::get_polling_page();
return !is_simm32(addr - (intptr_t)CodeCache::low_bound()) ||
return ForceUnreachable ||
!is_simm32(addr - (intptr_t)CodeCache::low_bound()) ||
!is_simm32(addr - (intptr_t)CodeCache::high_bound());
}

View File

@ -693,17 +693,6 @@ private:
static address locate_next_instruction(address inst);
// Utilities
#ifdef _LP64
static bool is_simm(int64_t x, int nbits) { return -(CONST64(1) << (nbits-1)) <= x &&
x < (CONST64(1) << (nbits-1)); }
static bool is_simm32(int64_t x) { return x == (int64_t)(int32_t)x; }
#else
static bool is_simm(int32_t x, int nbits) { return -(1 << (nbits-1)) <= x &&
x < (1 << (nbits-1)); }
static bool is_simm32(int32_t x) { return true; }
#endif // _LP64
static bool is_polling_page_far() NOT_LP64({ return false;});
// Generic instructions

View File

@ -44,7 +44,7 @@ define_pd_global(bool, ProfileInterpreter, false);
#else
define_pd_global(bool, ProfileInterpreter, true);
#endif // CC_INTERP
define_pd_global(bool, TieredCompilation, false);
define_pd_global(bool, TieredCompilation, true);
define_pd_global(intx, CompileThreshold, 10000);
define_pd_global(intx, BackEdgeThreshold, 100000);

View File

@ -27,7 +27,7 @@
// Adapters
enum /* platform_dependent_constants */ {
adapter_code_size = NOT_LP64(16000 DEBUG_ONLY(+ 15000)) LP64_ONLY(32000 DEBUG_ONLY(+ 80000))
adapter_code_size = NOT_LP64(16000 DEBUG_ONLY(+ 15000)) LP64_ONLY(32000 DEBUG_ONLY(+ 120000))
};
public:

View File

@ -95,6 +95,7 @@ class StubGenerator: public StubCodeGenerator {
#define inc_counter_np(counter) (0)
#else
void inc_counter_np_(int& counter) {
// This can destroy rscratch1 if counter is far from the code cache
__ incrementl(ExternalAddress((address)&counter));
}
#define inc_counter_np(counter) \
@ -1268,7 +1269,7 @@ class StubGenerator: public StubCodeGenerator {
__ subptr(end, start); // number of bytes to copy
intptr_t disp = (intptr_t) ct->byte_map_base;
if (__ is_simm32(disp)) {
if (Assembler::is_simm32(disp)) {
Address cardtable(noreg, noreg, Address::no_scale, disp);
__ lea(scratch, cardtable);
} else {
@ -1466,8 +1467,8 @@ class StubGenerator: public StubCodeGenerator {
__ movb(Address(end_to, 8), rax);
__ BIND(L_exit);
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1555,8 +1556,8 @@ class StubGenerator: public StubCodeGenerator {
__ decrement(qword_count);
__ jcc(Assembler::notZero, L_copy_8_bytes);
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1564,8 +1565,8 @@ class StubGenerator: public StubCodeGenerator {
// Copy in 32-bytes chunks
copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1658,8 +1659,8 @@ class StubGenerator: public StubCodeGenerator {
__ movw(Address(end_to, 8), rax);
__ BIND(L_exit);
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1759,8 +1760,8 @@ class StubGenerator: public StubCodeGenerator {
__ decrement(qword_count);
__ jcc(Assembler::notZero, L_copy_8_bytes);
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1768,8 +1769,8 @@ class StubGenerator: public StubCodeGenerator {
// Copy in 32-bytes chunks
copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1859,8 +1860,8 @@ class StubGenerator: public StubCodeGenerator {
__ leaq(end_to, Address(saved_to, dword_count, Address::times_4, -4));
gen_write_ref_array_post_barrier(saved_to, end_to, rax);
}
inc_counter_np(SharedRuntime::_jint_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1940,11 +1941,11 @@ class StubGenerator: public StubCodeGenerator {
__ decrement(qword_count);
__ jcc(Assembler::notZero, L_copy_8_bytes);
inc_counter_np(SharedRuntime::_jint_array_copy_ctr);
if (is_oop) {
__ jmp(L_exit);
}
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -1952,7 +1953,6 @@ class StubGenerator: public StubCodeGenerator {
// Copy in 32-bytes chunks
copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
inc_counter_np(SharedRuntime::_jint_array_copy_ctr);
__ bind(L_exit);
if (is_oop) {
Register end_to = rdx;
@ -1960,6 +1960,7 @@ class StubGenerator: public StubCodeGenerator {
gen_write_ref_array_post_barrier(to, end_to, rax);
}
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -2032,8 +2033,8 @@ class StubGenerator: public StubCodeGenerator {
if (is_oop) {
__ jmp(L_exit);
} else {
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -2045,11 +2046,13 @@ class StubGenerator: public StubCodeGenerator {
if (is_oop) {
__ BIND(L_exit);
gen_write_ref_array_post_barrier(saved_to, end_to, rax);
inc_counter_np(SharedRuntime::_oop_array_copy_ctr);
} else {
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr);
}
restore_arg_regs();
if (is_oop) {
inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
} else {
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free
}
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -2113,8 +2116,8 @@ class StubGenerator: public StubCodeGenerator {
if (is_oop) {
__ jmp(L_exit);
} else {
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -2127,11 +2130,13 @@ class StubGenerator: public StubCodeGenerator {
__ BIND(L_exit);
__ lea(rcx, Address(to, saved_count, Address::times_8, -8));
gen_write_ref_array_post_barrier(to, rcx, rax);
inc_counter_np(SharedRuntime::_oop_array_copy_ctr);
} else {
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr);
}
restore_arg_regs();
if (is_oop) {
inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
} else {
inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free
}
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
@ -2331,8 +2336,8 @@ class StubGenerator: public StubCodeGenerator {
__ BIND(L_done);
__ movptr(r13, Address(rsp, saved_r13_offset * wordSize));
__ movptr(r14, Address(rsp, saved_r14_offset * wordSize));
inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr);
restore_arg_regs();
inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); // Update counter after rscratch1 is free
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);

View File

@ -507,9 +507,12 @@ void encode_CopyXD( CodeBuffer &cbuf, int dst_encoding, int src_encoding ) {
//=============================================================================
const bool Matcher::constant_table_absolute_addressing = true;
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
int Compile::ConstantTable::calculate_table_base_offset() const {
return 0; // absolute addressing, no offset
}
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
// Empty encoding
}
@ -639,6 +642,12 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
}
#endif
if (C->has_mach_constant_base_node()) {
// NOTE: We set the table base offset here because users might be
// emitted before MachConstantBaseNode.
Compile::ConstantTable& constant_table = C->constant_table();
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
}
}
uint MachPrologNode::size(PhaseRegAlloc *ra_) const {
@ -1515,12 +1524,12 @@ bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
// Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() {
return EAX_REG_mask;
return EAX_REG_mask();
}
// Register for MODI projection of divmodI
RegMask Matcher::modI_proj_mask() {
return EDX_REG_mask;
return EDX_REG_mask();
}
// Register for DIVL projection of divmodL
@ -1536,7 +1545,7 @@ RegMask Matcher::modL_proj_mask() {
}
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return EBP_REG_mask;
return EBP_REG_mask();
}
// Returns true if the high 32 bits of the value is known to be zero.

View File

@ -843,9 +843,12 @@ void emit_cmpfp_fixup(MacroAssembler& _masm) {
//=============================================================================
const bool Matcher::constant_table_absolute_addressing = true;
const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty;
int Compile::ConstantTable::calculate_table_base_offset() const {
return 0; // absolute addressing, no offset
}
void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const {
// Empty encoding
}
@ -977,6 +980,13 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const
masm.bind(L);
}
#endif
if (C->has_mach_constant_base_node()) {
// NOTE: We set the table base offset here because users might be
// emitted before MachConstantBaseNode.
Compile::ConstantTable& constant_table = C->constant_table();
constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
}
}
uint MachPrologNode::size(PhaseRegAlloc* ra_) const
@ -2079,26 +2089,26 @@ bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) {
// Register for DIVI projection of divmodI
RegMask Matcher::divI_proj_mask() {
return INT_RAX_REG_mask;
return INT_RAX_REG_mask();
}
// Register for MODI projection of divmodI
RegMask Matcher::modI_proj_mask() {
return INT_RDX_REG_mask;
return INT_RDX_REG_mask();
}
// Register for DIVL projection of divmodL
RegMask Matcher::divL_proj_mask() {
return LONG_RAX_REG_mask;
return LONG_RAX_REG_mask();
}
// Register for MODL projection of divmodL
RegMask Matcher::modL_proj_mask() {
return LONG_RDX_REG_mask;
return LONG_RDX_REG_mask();
}
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return PTR_RBP_REG_mask;
return PTR_RBP_REG_mask();
}
static Address build_address(int b, int i, int s, int d) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -982,27 +982,9 @@ void ADLParser::frame_parse(void) {
}
if (strcmp(token,"interpreter_frame_pointer")==0) {
interpreter_frame_pointer_parse(frame, false);
// Add reg_class interpreter_frame_pointer_reg
if( _AD._register != NULL ) {
RegClass *reg_class = _AD._register->addRegClass("interpreter_frame_pointer_reg");
char *interpreter_frame_pointer_reg = frame->_interpreter_frame_pointer_reg;
if( interpreter_frame_pointer_reg != NULL ) {
RegDef *regDef = _AD._register->getRegDef(interpreter_frame_pointer_reg);
reg_class->addReg(regDef); // add regDef to regClass
}
}
}
if (strcmp(token,"inline_cache_reg")==0) {
inline_cache_parse(frame, false);
// Add reg_class inline_cache_reg
if( _AD._register != NULL ) {
RegClass *reg_class = _AD._register->addRegClass("inline_cache_reg");
char *inline_cache_reg = frame->_inline_cache_reg;
if( inline_cache_reg != NULL ) {
RegDef *regDef = _AD._register->getRegDef(inline_cache_reg);
reg_class->addReg(regDef); // add regDef to regClass
}
}
}
if (strcmp(token,"compiler_method_oop_reg")==0) {
parse_err(WARN, "Using obsolete Token, compiler_method_oop_reg");
@ -1010,15 +992,6 @@ void ADLParser::frame_parse(void) {
}
if (strcmp(token,"interpreter_method_oop_reg")==0) {
interpreter_method_oop_parse(frame, false);
// Add reg_class interpreter_method_oop_reg
if( _AD._register != NULL ) {
RegClass *reg_class = _AD._register->addRegClass("interpreter_method_oop_reg");
char *method_oop_reg = frame->_interpreter_method_oop_reg;
if( method_oop_reg != NULL ) {
RegDef *regDef = _AD._register->getRegDef(method_oop_reg);
reg_class->addReg(regDef); // add regDef to regClass
}
}
}
if (strcmp(token,"cisc_spilling_operand_name")==0) {
cisc_spilling_operand_name_parse(frame, false);
@ -2363,6 +2336,14 @@ void ADLParser::reg_class_parse(void) {
}
}
next_char(); // Skip closing ')'
} else if (_curchar == '%') {
char *code = find_cpp_block("reg class");
if (code == NULL) {
parse_err(SYNERR, "missing code declaration for reg class.\n");
return;
}
reg_class->_user_defined = code;
return;
}
// Check for terminating ';'
@ -3115,7 +3096,7 @@ void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
encoding->add_code(" _constant = C->constant_table().add");
// Parse everything in ( ) expression.
encoding->add_code("(");
encoding->add_code("(this, ");
next_char(); // Skip '('
int parens_depth = 1;
@ -3130,7 +3111,8 @@ void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
}
else if (_curchar == ')') {
parens_depth--;
encoding->add_code(")");
if (parens_depth > 0)
encoding->add_code(")");
next_char();
}
else {
@ -3157,7 +3139,7 @@ void ADLParser::constant_parse_expression(EncClass* encoding, char* ec_name) {
}
// Finish code line.
encoding->add_code(";");
encoding->add_code(");");
if (_AD._adlocation_debug) {
encoding->add_code(end_line_marker());
@ -3817,7 +3799,7 @@ void ADLParser::effect_parse(InstructForm *instr) {
return;
}
// Get list of effect-operand pairs and insert into dictionary
else get_effectlist(instr->_effects, instr->_localNames);
else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call);
// Debug Stuff
if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc);
@ -4595,7 +4577,7 @@ void ADLParser::get_oplist(NameList &parameters, FormDict &operands) {
// effect, and the second must be the name of an operand defined in the
// operand list of this instruction. Stores the names with a pointer to the
// effect form in a local effects table.
void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) {
void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) {
OperandForm *opForm;
Effect *eForm;
char *ident;
@ -4628,26 +4610,31 @@ void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) {
// Debugging Stuff
if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident);
skipws();
// Get name of operand and check that it is in the local name table
if( (ident = get_unique_ident(effects, "effect")) == NULL) {
parse_err(SYNERR, "missing operand identifier in effect list\n");
return;
}
const Form *form = operands[ident];
opForm = form ? form->is_operand() : NULL;
if( opForm == NULL ) {
if( form && form->is_opclass() ) {
const char* cname = form->is_opclass()->_ident;
parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);
} else {
parse_err(SYNERR, "undefined operand %s in effect list\n", ident);
if (eForm->is(Component::CALL)) {
if (_AD._adl_debug > 1) fprintf(stderr, "\n");
has_call = true;
} else {
// Get name of operand and check that it is in the local name table
if( (ident = get_unique_ident(effects, "effect")) == NULL) {
parse_err(SYNERR, "missing operand identifier in effect list\n");
return;
}
return;
const Form *form = operands[ident];
opForm = form ? form->is_operand() : NULL;
if( opForm == NULL ) {
if( form && form->is_opclass() ) {
const char* cname = form->is_opclass()->_ident;
parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident);
} else {
parse_err(SYNERR, "undefined operand %s in effect list\n", ident);
}
return;
}
// Add the pair to the effects table
effects.Insert(ident, eForm);
// Debugging Stuff
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
}
// Add the pair to the effects table
effects.Insert(ident, eForm);
// Debugging Stuff
if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident);
skipws();
} while(_curchar == ',');

View File

@ -232,7 +232,7 @@ protected:
char *get_relation_dup(void);
void get_oplist(NameList &parameters, FormDict &operands);// Parse type-operand pairs
void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs
void get_effectlist(FormDict &effects, FormDict &operands, bool& has_call); // Parse effect-operand pairs
// Return the contents of a parenthesized expression.
// Requires initial '(' and consumes final ')', which is replaced by '\0'.
char *get_paren_expr(const char *description, bool include_location = false);

View File

@ -823,9 +823,9 @@ static const char *getRegMask(const char *reg_class_name) {
} else {
char *rc_name = toUpper(reg_class_name);
const char *mask = "_mask";
int length = (int)strlen(rc_name) + (int)strlen(mask) + 3;
int length = (int)strlen(rc_name) + (int)strlen(mask) + 5;
char *regMask = new char[length];
sprintf(regMask,"%s%s", rc_name, mask);
sprintf(regMask,"%s%s()", rc_name, mask);
return regMask;
}
}
@ -1018,6 +1018,9 @@ void ArchDesc::initBaseOpTypes() {
ident = "TEMP";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
ident = "CALL";
eForm = new Effect(ident);
_globalNames.Insert(ident, eForm);
}
//

View File

@ -219,7 +219,9 @@ void RegDef::output(FILE *fp) { // Write info to output files
//------------------------------RegClass---------------------------------------
// Construct a register class into which registers will be inserted
RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena) {
RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena),
_user_defined(NULL)
{
}
// record a register in this class

View File

@ -161,6 +161,7 @@ public:
NameList _regDefs; // List of registers in class
Dict _regDef; // Dictionary of registers in class
bool _stack_or_reg; // Allowed on any stack slot
char* _user_defined;
// Public Methods
RegClass(const char *classid);// Constructor

View File

@ -31,7 +31,8 @@ InstructForm::InstructForm(const char *id, bool ideal_only)
: _ident(id), _ideal_only(ideal_only),
_localNames(cmpstr, hashstr, Form::arena),
_effects(cmpstr, hashstr, Form::arena),
_is_mach_constant(false)
_is_mach_constant(false),
_has_call(false)
{
_ftype = Form::INS;
@ -62,7 +63,8 @@ InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule)
: _ident(id), _ideal_only(false),
_localNames(instr->_localNames),
_effects(instr->_effects),
_is_mach_constant(false)
_is_mach_constant(false),
_has_call(false)
{
_ftype = Form::INS;
@ -1754,6 +1756,7 @@ static int effect_lookup(const char *name) {
if(!strcmp(name, "USE_KILL")) return Component::USE_KILL;
if(!strcmp(name, "TEMP")) return Component::TEMP;
if(!strcmp(name, "INVALID")) return Component::INVALID;
if(!strcmp(name, "CALL")) return Component::CALL;
assert( false,"Invalid effect name specified\n");
return Component::INVALID;
}

View File

@ -111,6 +111,8 @@ public:
ComponentList _components; // List of Components matches MachNode's
// operand structure
bool _has_call; // contain a call and caller save registers should be saved?
// Public Methods
InstructForm(const char *id, bool ideal_only = false);
InstructForm(const char *id, InstructForm *instr, MatchRule *rule);
@ -895,7 +897,8 @@ public:
DEF = 0x2, USE_DEF = 0x3,
KILL = 0x4, USE_KILL = 0x5,
SYNTHETIC = 0x8,
TEMP = USE | SYNTHETIC
TEMP = USE | SYNTHETIC,
CALL = 0x10
};
};

View File

@ -162,11 +162,17 @@ void ArchDesc::declare_register_masks(FILE *fp_hpp) {
RegClass *reg_class = _register->getRegClass(rc_name);
assert( reg_class, "Using an undefined register class");
int len = RegisterForm::RegMask_Size();
fprintf(fp_hpp, "extern const RegMask %s%s_mask;\n", prefix, toUpper( rc_name ) );
if (reg_class->_user_defined == NULL) {
fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, toUpper( rc_name ) );
fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, toUpper( rc_name ), prefix, toUpper( rc_name ));
} else {
fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, toUpper( rc_name ), reg_class->_user_defined);
}
if( reg_class->_stack_or_reg ) {
fprintf(fp_hpp, "extern const RegMask %sSTACK_OR_%s_mask;\n", prefix, toUpper( rc_name ) );
assert(reg_class->_user_defined == NULL, "no user defined reg class here");
fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, toUpper( rc_name ) );
fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, toUpper( rc_name ), prefix, toUpper( rc_name ) );
}
}
}
@ -188,8 +194,10 @@ void ArchDesc::build_register_masks(FILE *fp_cpp) {
RegClass *reg_class = _register->getRegClass(rc_name);
assert( reg_class, "Using an undefined register class");
if (reg_class->_user_defined != NULL) continue;
int len = RegisterForm::RegMask_Size();
fprintf(fp_cpp, "const RegMask %s%s_mask(", prefix, toUpper( rc_name ) );
fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, toUpper( rc_name ) );
{ int i;
for( i = 0; i < len-1; i++ )
fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i,false));
@ -198,7 +206,7 @@ void ArchDesc::build_register_masks(FILE *fp_cpp) {
if( reg_class->_stack_or_reg ) {
int i;
fprintf(fp_cpp, "const RegMask %sSTACK_OR_%s_mask(", prefix, toUpper( rc_name ) );
fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, toUpper( rc_name ) );
for( i = 0; i < len-1; i++ )
fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i,true));
fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i,true));
@ -2585,9 +2593,9 @@ void ArchDesc::defineEvalConstant(FILE* fp, InstructForm& inst) {
// Output instruction's emit prototype
fprintf(fp, "void %sNode::eval_constant(Compile* C) {\n", inst._ident);
// For ideal jump nodes, allocate a jump table.
// For ideal jump nodes, add a jump-table entry.
if (inst.is_ideal_jump()) {
fprintf(fp, " _constant = C->constant_table().allocate_jump_table(this);\n");
fprintf(fp, " _constant = C->constant_table().add_jump_table(this);\n");
}
// If user did not define an encode section,
@ -2690,7 +2698,7 @@ static void defineIn_RegMask(FILE *fp, FormDict &globals, OperandForm &oper) {
if (strcmp(first_reg_class, "stack_slots") == 0) {
fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n");
} else {
fprintf(fp," return &%s_mask;\n", toUpper(first_reg_class));
fprintf(fp," return &%s_mask();\n", toUpper(first_reg_class));
}
} else {
// Build a switch statement to return the desired mask.
@ -2702,7 +2710,7 @@ static void defineIn_RegMask(FILE *fp, FormDict &globals, OperandForm &oper) {
if( !strcmp(reg_class, "stack_slots") ) {
fprintf(fp, " case %d: return &(Compile::current()->FIRST_STACK_mask());\n", index);
} else {
fprintf(fp, " case %d: return &%s_mask;\n", index, toUpper(reg_class));
fprintf(fp, " case %d: return &%s_mask();\n", index, toUpper(reg_class));
}
}
fprintf(fp," }\n");
@ -4080,8 +4088,6 @@ void ArchDesc::buildFrameMethods(FILE *fp_cpp) {
fprintf(fp_cpp,"OptoReg::Name Matcher::inline_cache_reg() {");
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_inline_cache_reg);
fprintf(fp_cpp,"const RegMask &Matcher::inline_cache_reg_mask() {");
fprintf(fp_cpp," return INLINE_CACHE_REG_mask; }\n\n");
fprintf(fp_cpp,"int Matcher::inline_cache_reg_encode() {");
fprintf(fp_cpp," return _regEncode[inline_cache_reg()]; }\n\n");
@ -4089,8 +4095,6 @@ void ArchDesc::buildFrameMethods(FILE *fp_cpp) {
fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_method_oop_reg() {");
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_interpreter_method_oop_reg);
fprintf(fp_cpp,"const RegMask &Matcher::interpreter_method_oop_reg_mask() {");
fprintf(fp_cpp," return INTERPRETER_METHOD_OOP_REG_mask; }\n\n");
fprintf(fp_cpp,"int Matcher::interpreter_method_oop_reg_encode() {");
fprintf(fp_cpp," return _regEncode[interpreter_method_oop_reg()]; }\n\n");
@ -4101,11 +4105,6 @@ void ArchDesc::buildFrameMethods(FILE *fp_cpp) {
else
fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n",
_frame->_interpreter_frame_pointer_reg);
fprintf(fp_cpp,"const RegMask &Matcher::interpreter_frame_pointer_reg_mask() {");
if (_frame->_interpreter_frame_pointer_reg == NULL)
fprintf(fp_cpp," static RegMask dummy; return dummy; }\n\n");
else
fprintf(fp_cpp," return INTERPRETER_FRAME_POINTER_REG_mask; }\n\n");
// Frame Pointer definition
/* CNC - I can not contemplate having a different frame pointer between

View File

@ -1720,6 +1720,16 @@ void ArchDesc::declareClasses(FILE *fp) {
}
}
// flag: if this instruction is implemented with a call
if ( instr->_has_call ) {
if ( node_flags_set ) {
fprintf(fp," | Flag_has_call");
} else {
fprintf(fp,"init_flags(Flag_has_call");
node_flags_set = true;
}
}
if ( node_flags_set ) {
fprintf(fp,"); ");
}

View File

@ -257,6 +257,29 @@ class AbstractAssembler : public ResourceObj {
// ensure buf contains all code (call this before using/copying the code)
void flush();
// min and max values for signed immediate ranges
static int min_simm(int nbits) { return -(intptr_t(1) << (nbits - 1)) ; }
static int max_simm(int nbits) { return (intptr_t(1) << (nbits - 1)) - 1; }
// Define some:
static int min_simm10() { return min_simm(10); }
static int min_simm13() { return min_simm(13); }
static int min_simm16() { return min_simm(16); }
// Test if x is within signed immediate range for nbits
static bool is_simm(intptr_t x, int nbits) { return min_simm(nbits) <= x && x <= max_simm(nbits); }
// Define some:
static bool is_simm5( intptr_t x) { return is_simm(x, 5 ); }
static bool is_simm8( intptr_t x) { return is_simm(x, 8 ); }
static bool is_simm10(intptr_t x) { return is_simm(x, 10); }
static bool is_simm11(intptr_t x) { return is_simm(x, 11); }
static bool is_simm12(intptr_t x) { return is_simm(x, 12); }
static bool is_simm13(intptr_t x) { return is_simm(x, 13); }
static bool is_simm16(intptr_t x) { return is_simm(x, 16); }
static bool is_simm26(intptr_t x) { return is_simm(x, 26); }
static bool is_simm32(intptr_t x) { return is_simm(x, 32); }
// Accessors
CodeBuffer* code() const; // _code_section->outer()
CodeSection* code_section() const { return _code_section; }

View File

@ -3495,9 +3495,6 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, BlockBeg
if (profile_calls()) {
profile_call(recv, holder_known ? callee->holder() : NULL);
}
if (profile_inlined_calls()) {
profile_invocation(callee, copy_state_before());
}
}
// Introduce a new callee continuation point - if the callee has
@ -3571,6 +3568,10 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, BlockBeg
append(new RuntimeCall(voidType, "dtrace_method_entry", CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), args));
}
if (profile_inlined_calls()) {
profile_invocation(callee, copy_state_before_with_bci(SynchronizationEntryBCI));
}
BlockBegin* callee_start_block = block_at(0);
if (callee_start_block != NULL) {
assert(callee_start_block->is_set(BlockBegin::parser_loop_header_flag), "must be loop header");

View File

@ -501,6 +501,7 @@ class Instruction: public CompilationResourceObj {
virtual RoundFP* as_RoundFP() { return NULL; }
virtual ExceptionObject* as_ExceptionObject() { return NULL; }
virtual UnsafeOp* as_UnsafeOp() { return NULL; }
virtual ProfileInvoke* as_ProfileInvoke() { return NULL; }
virtual void visit(InstructionVisitor* v) = 0;

View File

@ -429,7 +429,7 @@ CodeEmitInfo* LIRGenerator::state_for(Instruction* x, ValueStack* state, bool ig
// all locals are dead on exit from the synthetic unlocker
liveness.clear();
} else {
assert(x->as_MonitorEnter(), "only other case is MonitorEnter");
assert(x->as_MonitorEnter() || x->as_ProfileInvoke(), "only other cases are MonitorEnter and ProfileInvoke");
}
}
if (!liveness.is_valid()) {

View File

@ -150,11 +150,23 @@ void BCEscapeAnalyzer::set_method_escape(ArgumentMap vars) {
clear_bits(vars, _arg_local);
}
void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars) {
void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars, bool merge) {
clear_bits(vars, _arg_local);
clear_bits(vars, _arg_stack);
if (vars.contains_allocated())
_allocated_escapes = true;
if (merge && !vars.is_empty()) {
// Merge new state into already processed block.
// New state is not taken into account and
// it may invalidate set_returned() result.
if (vars.contains_unknown() || vars.contains_allocated()) {
_return_local = false;
}
if (vars.contains_unknown() || vars.contains_vars()) {
_return_allocated = false;
}
}
}
void BCEscapeAnalyzer::set_dirty(ArgumentMap vars) {
@ -999,7 +1011,7 @@ void BCEscapeAnalyzer::merge_block_states(StateInfo *blockstates, ciBlock *dest,
t.set_difference(d_state->_stack[i]);
extra_vars.set_union(t);
}
set_global_escape(extra_vars);
set_global_escape(extra_vars, true);
}
}

View File

@ -81,7 +81,7 @@ class BCEscapeAnalyzer : public ResourceObj {
bool is_arg_stack(ArgumentMap vars);
void clear_bits(ArgumentMap vars, VectorSet &bs);
void set_method_escape(ArgumentMap vars);
void set_global_escape(ArgumentMap vars);
void set_global_escape(ArgumentMap vars, bool merge = false);
void set_dirty(ArgumentMap vars);
void set_modified(ArgumentMap vars, int offs, int size);

View File

@ -295,12 +295,6 @@ class ciMethod : public ciObject {
// Print the name of this method in various incarnations.
void print_name(outputStream* st = tty);
void print_short_name(outputStream* st = tty);
methodOop get_method_handle_target() {
KlassHandle receiver_limit; int flags = 0;
methodHandle m = MethodHandles::decode_method(get_oop(), receiver_limit, flags);
return m();
}
};
#endif // SHARE_VM_CI_CIMETHOD_HPP

View File

@ -1748,7 +1748,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
tty->print("%4d ", compile_id); // print compilation number
tty->print("%s ", (is_osr ? "%" : " "));
int code_size = (task->code() == NULL) ? 0 : task->code()->total_size();
tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, time.milliseconds(), task->num_inlined_bytecodes());
tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, (int)time.milliseconds(), task->num_inlined_bytecodes());
}
if (compilable == ciEnv::MethodCompilable_never) {

View File

@ -898,45 +898,41 @@ void PhaseCFG::dump_headers() {
void PhaseCFG::verify( ) const {
#ifdef ASSERT
// Verify sane CFG
for( uint i = 0; i < _num_blocks; i++ ) {
for (uint i = 0; i < _num_blocks; i++) {
Block *b = _blocks[i];
uint cnt = b->_nodes.size();
uint j;
for( j = 0; j < cnt; j++ ) {
for (j = 0; j < cnt; j++) {
Node *n = b->_nodes[j];
assert( _bbs[n->_idx] == b, "" );
if( j >= 1 && n->is_Mach() &&
n->as_Mach()->ideal_Opcode() == Op_CreateEx ) {
assert( j == 1 || b->_nodes[j-1]->is_Phi(),
"CreateEx must be first instruction in block" );
if (j >= 1 && n->is_Mach() &&
n->as_Mach()->ideal_Opcode() == Op_CreateEx) {
assert(j == 1 || b->_nodes[j-1]->is_Phi(),
"CreateEx must be first instruction in block");
}
for( uint k = 0; k < n->req(); k++ ) {
for (uint k = 0; k < n->req(); k++) {
Node *def = n->in(k);
if( def && def != n ) {
assert( _bbs[def->_idx] || def->is_Con(),
"must have block; constants for debug info ok" );
if (def && def != n) {
assert(_bbs[def->_idx] || def->is_Con(),
"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 &&
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)) ) {
!(n->jvms() != NULL && n->jvms()->is_monitor_use(k))) {
bool is_loop = false;
if (n->is_Phi()) {
for( uint l = 1; l < def->req(); l++ ) {
for (uint l = 1; l < def->req(); l++) {
if (n == def->in(l)) {
is_loop = true;
break; // Some kind of loop
}
}
}
assert( is_loop || b->find_node(def) < j, "uses must follow definitions" );
}
if( def->is_SafePointScalarObject() ) {
assert(_bbs[def->_idx] == b, "SafePointScalarObject Node should be at the same block as its SafePoint node");
assert(_bbs[def->_idx] == _bbs[def->in(0)->_idx], "SafePointScalarObject Node should be at the same block as its control edge");
assert(is_loop || b->find_node(def) < j, "uses must follow definitions");
}
}
}
@ -946,12 +942,11 @@ void PhaseCFG::verify( ) const {
Node *bp = (Node*)b->_nodes[b->_nodes.size()-1]->is_block_proj();
assert( bp, "last instruction must be a block proj" );
assert( bp == b->_nodes[j], "wrong number of successors for this block" );
if( bp->is_Catch() ) {
while( b->_nodes[--j]->is_MachProj() ) ;
assert( b->_nodes[j]->is_MachCall(), "CatchProj must follow call" );
}
else if( bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If ) {
assert( b->_num_succs == 2, "Conditional branch must have two targets");
if (bp->is_Catch()) {
while (b->_nodes[--j]->is_MachProj()) ;
assert(b->_nodes[j]->is_MachCall(), "CatchProj must follow call");
} else if (bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If) {
assert(b->_num_succs == 2, "Conditional branch must have two targets");
}
}
#endif

View File

@ -281,6 +281,8 @@ class Block : public CFGElement {
// Find and remove n from block list
void find_remove( const Node *n );
// helper function that adds caller save registers to MachProjNode
void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe);
// Schedule a call next in the block
uint sched_call(Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call);

View File

@ -456,6 +456,12 @@
product(intx, EliminateAllocationArraySizeLimit, 64, \
"Array size (number of elements) limit for scalar replacement") \
\
product(bool, OptimizePtrCompare, true, \
"Use escape analysis to optimize pointers compare") \
\
notproduct(bool, PrintOptimizePtrCompare, false, \
"Print information about optimized pointers compare") \
\
product(bool, UseOptoBiasInlining, true, \
"Generate biased locking code in C2 ideal graph") \
\

View File

@ -318,17 +318,17 @@ CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj
return new DirectCallGenerator(m, separate_io_proj);
}
CallGenerator* CallGenerator::for_dynamic_call(ciMethod* m) {
assert(m->is_method_handle_invoke() || m->is_method_handle_adapter(), "for_dynamic_call mismatch");
return new DynamicCallGenerator(m);
}
CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) {
assert(!m->is_static(), "for_virtual_call mismatch");
assert(!m->is_method_handle_invoke(), "should be a direct call");
return new VirtualCallGenerator(m, vtable_index);
}
CallGenerator* CallGenerator::for_dynamic_call(ciMethod* m) {
assert(m->is_method_handle_invoke() || m->is_method_handle_adapter(), "for_dynamic_call mismatch");
return new DynamicCallGenerator(m);
}
// Allow inlining decisions to be delayed
class LateInlineCallGenerator : public DirectCallGenerator {
CallGenerator* _inline_cg;
@ -576,7 +576,9 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
kit.set_control(slow_ctl);
if (!kit.stopped()) {
slow_jvms = _if_missed->generate(kit.sync_jvms());
assert(slow_jvms != NULL, "miss path must not fail to generate");
if (kit.failing())
return NULL; // might happen because of NodeCountInliningCutoff
assert(slow_jvms != NULL, "must be");
kit.add_exception_states_from(slow_jvms);
kit.set_map(slow_jvms->map());
if (!kit.stopped())
@ -682,6 +684,15 @@ CallGenerator* CallGenerator::for_predicted_dynamic_call(ciMethodHandle* predict
}
CallGenerator* CallGenerator::for_method_handle_call(Node* method_handle, JVMState* jvms,
ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
assert(callee->is_method_handle_invoke() || callee->is_method_handle_adapter(), "for_method_handle_call mismatch");
CallGenerator* cg = CallGenerator::for_method_handle_inline(method_handle, jvms, caller, callee, profile);
if (cg != NULL)
return cg;
return CallGenerator::for_direct_call(callee);
}
CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMState* jvms,
ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
if (method_handle->Opcode() == Op_ConP) {
@ -721,8 +732,8 @@ CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMS
// Generate a guard so that each can be inlined. We might want to
// do more inputs at later point but this gets the most common
// case.
CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile.rescale(1.0 - prob));
CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile.rescale(prob));
CallGenerator* cg1 = for_method_handle_call(method_handle->in(1), jvms, caller, callee, profile.rescale(1.0 - prob));
CallGenerator* cg2 = for_method_handle_call(method_handle->in(2), jvms, caller, callee, profile.rescale(prob));
if (cg1 != NULL && cg2 != NULL) {
const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr();
ciObject* const_oop = oop_ptr->const_oop();
@ -733,6 +744,17 @@ CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMS
return NULL;
}
CallGenerator* CallGenerator::for_invokedynamic_call(JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
assert(callee->is_method_handle_invoke() || callee->is_method_handle_adapter(), "for_invokedynamic_call mismatch");
// Get the CallSite object.
ciBytecodeStream str(caller);
str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci.
ciCallSite* call_site = str.get_call_site();
CallGenerator* cg = CallGenerator::for_invokedynamic_inline(call_site, jvms, caller, callee, profile);
if (cg != NULL)
return cg;
return CallGenerator::for_dynamic_call(callee);
}
CallGenerator* CallGenerator::for_invokedynamic_inline(ciCallSite* call_site, JVMState* jvms,
ciMethod* caller, ciMethod* callee, ciCallProfile profile) {
@ -819,7 +841,9 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
kit.set_control(slow_ctl);
if (!kit.stopped()) {
slow_jvms = _if_missed->generate(kit.sync_jvms());
assert(slow_jvms != NULL, "miss path must not fail to generate");
if (kit.failing())
return NULL; // might happen because of NodeCountInliningCutoff
assert(slow_jvms != NULL, "must be");
kit.add_exception_states_from(slow_jvms);
kit.set_map(slow_jvms->map());
if (!kit.stopped())

View File

@ -108,8 +108,11 @@ class CallGenerator : public ResourceObj {
// How to generate vanilla out-of-line call sites:
static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special
static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic
static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface
static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic
static CallGenerator* for_method_handle_call(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);
static CallGenerator* for_invokedynamic_call( JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);
static CallGenerator* for_method_handle_inline(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);
static CallGenerator* for_invokedynamic_inline(ciCallSite* call_site, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile);

View File

@ -1071,8 +1071,11 @@ SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp,
init_class_id(Class_SafePointScalarObject);
}
bool SafePointScalarObjectNode::pinned() const { return true; }
bool SafePointScalarObjectNode::depends_only_on_test() const { return false; }
// Do not allow value-numbering for SafePointScalarObject node.
uint SafePointScalarObjectNode::hash() const { return NO_HASH; }
uint SafePointScalarObjectNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
uint SafePointScalarObjectNode::ideal_reg() const {
return 0; // No matching to machine instruction
@ -1096,7 +1099,6 @@ SafePointScalarObjectNode::clone(int jvms_adj, Dict* sosn_map) const {
if (cached != NULL) {
return (SafePointScalarObjectNode*)cached;
}
Compile* C = Compile::current();
SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone();
res->_first_index += jvms_adj;
sosn_map->Insert((void*)this, (void*)res);
@ -1142,6 +1144,8 @@ uint AllocateArrayNode::size_of() const { return sizeof(*this); }
Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
const Type* type = phase->type(Ideal_length());
if (type->isa_int() && type->is_int()->_hi < 0) {
@ -1522,13 +1526,16 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// perform any generic optimizations first (returns 'this' or NULL)
Node *result = SafePointNode::Ideal(phase, can_reshape);
if (result != NULL) return result;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
// Now see if we can optimize away this lock. We don't actually
// remove the locking here, we simply set the _eliminate flag which
// prevents macro expansion from expanding the lock. Since we don't
// modify the graph, the value returned from this function is the
// one computed above.
if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) {
if (can_reshape && EliminateLocks && (!is_eliminated() || is_coarsened())) {
//
// If we are locking an unescaped object, the lock/unlock is unnecessary
//
@ -1537,8 +1544,16 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (cgr != NULL)
es = cgr->escape_state(obj_node());
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters
this->set_eliminated();
if (!is_eliminated()) {
// Mark it eliminated to update any counters
this->set_eliminated();
} else {
assert(is_coarsened(), "sanity");
// The lock could be marked eliminated by lock coarsening
// code during first IGVN before EA. Clear coarsened flag
// to eliminate all associated locks/unlocks.
this->clear_coarsened();
}
return result;
}
@ -1546,7 +1561,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Try lock coarsening
//
PhaseIterGVN* iter = phase->is_IterGVN();
if (iter != NULL) {
if (iter != NULL && !is_eliminated()) {
GrowableArray<AbstractLockNode*> lock_ops;
@ -1602,7 +1617,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
lock->set_eliminated();
lock->set_coarsened();
}
} else if (result != NULL && ctrl->is_Region() &&
} else if (ctrl->is_Region() &&
iter->_worklist.member(ctrl)) {
// We weren't able to find any opportunities but the region this
// lock is control dependent on hasn't been processed yet so put
@ -1623,7 +1638,10 @@ uint UnlockNode::size_of() const { return sizeof(*this); }
Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// perform any generic optimizations first (returns 'this' or NULL)
Node * result = SafePointNode::Ideal(phase, can_reshape);
Node *result = SafePointNode::Ideal(phase, can_reshape);
if (result != NULL) return result;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
// Now see if we can optimize away this unlock. We don't actually
// remove the unlocking here, we simply set the _eliminate flag which
@ -1631,7 +1649,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// modify the graph, the value returned from this function is the
// one computed above.
// Escape state is defined after Parse phase.
if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) {
if (can_reshape && EliminateLocks && (!is_eliminated() || is_coarsened())) {
//
// If we are unlocking an unescaped object, the lock/unlock is unnecessary.
//
@ -1640,8 +1658,16 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (cgr != NULL)
es = cgr->escape_state(obj_node());
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters
this->set_eliminated();
if (!is_eliminated()) {
// Mark it eliminated to update any counters
this->set_eliminated();
} else {
assert(is_coarsened(), "sanity");
// The lock could be marked eliminated by lock coarsening
// code during first IGVN before EA. Clear coarsened flag
// to eliminate all associated locks/unlocks.
this->clear_coarsened();
}
}
}
return result;

View File

@ -440,6 +440,10 @@ class SafePointScalarObjectNode: public TypeNode {
// states of the scalarized object fields are collected.
uint _n_fields; // Number of non-static fields of the scalarized object.
DEBUG_ONLY(AllocateNode* _alloc;)
virtual uint hash() const ; // { return NO_HASH; }
virtual uint cmp( const Node &n ) const;
public:
SafePointScalarObjectNode(const TypeOopPtr* tp,
#ifdef ASSERT
@ -454,15 +458,10 @@ public:
uint first_index() const { return _first_index; }
uint n_fields() const { return _n_fields; }
DEBUG_ONLY(AllocateNode* alloc() const { return _alloc; })
// SafePointScalarObject should be always pinned to the control edge
// of the SafePoint node for which it was generated.
virtual bool pinned() const; // { return true; }
// SafePointScalarObject depends on the SafePoint node
// for which it was generated.
virtual bool depends_only_on_test() const; // { return false; }
#ifdef ASSERT
AllocateNode* alloc() const { return _alloc; }
#endif
virtual uint size_of() const { return sizeof(*this); }
@ -880,6 +879,7 @@ public:
bool is_coarsened() { return _coarsened; }
void set_coarsened() { _coarsened = true; }
void clear_coarsened() { _coarsened = false; }
// locking does not modify its arguments
virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;}

View File

@ -460,8 +460,11 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Is it dead loop?
// If it is LoopNopde it had 2 (+1 itself) inputs and
// one of them was cut. The loop is dead if it was EntryContol.
assert(!this->is_Loop() || cnt_orig == 3, "Loop node should have 3 inputs");
if (this->is_Loop() && del_it == LoopNode::EntryControl ||
// Loop node may have only one input because entry path
// is removed in PhaseIdealLoop::Dominators().
assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs");
if (this->is_Loop() && (del_it == LoopNode::EntryControl ||
del_it == 0 && is_unreachable_region(phase)) ||
!this->is_Loop() && has_phis && is_unreachable_region(phase)) {
// Yes, the region will be removed during the next step below.
// Cut the backedge input and remove phis since no data paths left.
@ -1585,14 +1588,17 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// Only one not-NULL unique input path is left.
// Determine if this input is backedge of a loop.
// (Skip new phis which have no uses and dead regions).
if( outcnt() > 0 && r->in(0) != NULL ) {
if (outcnt() > 0 && r->in(0) != NULL) {
// First, take the short cut when we know it is a loop and
// the EntryControl data path is dead.
assert(!r->is_Loop() || r->req() == 3, "Loop node should have 3 inputs");
// Loop node may have only one input because entry path
// is removed in PhaseIdealLoop::Dominators().
assert(!r->is_Loop() || r->req() <= 3, "Loop node should have 3 or less inputs");
bool is_loop = (r->is_Loop() && r->req() == 3);
// Then, check if there is a data loop when phi references itself directly
// or through other data nodes.
if( r->is_Loop() && !phase->eqv_uncast(uin, in(LoopNode::EntryControl)) ||
!r->is_Loop() && is_unsafe_data_reference(uin) ) {
if (is_loop && !phase->eqv_uncast(uin, in(LoopNode::EntryControl)) ||
!is_loop && is_unsafe_data_reference(uin)) {
// Break this data loop to avoid creation of a dead loop.
if (can_reshape) {
return top;

View File

@ -1711,11 +1711,22 @@ void Compile::Optimize() {
if (failing()) return;
// Optimize out fields loads from scalar replaceable allocations.
igvn.optimize();
print_method("Iter GVN after EA", 2);
if (failing()) return;
if (congraph() != NULL && macro_count() > 0) {
PhaseMacroExpand mexp(igvn);
mexp.eliminate_macro_nodes();
igvn.set_delay_transform(false);
igvn.optimize();
print_method("Iter GVN after eliminating allocations and locks", 2);
if (failing()) return;
}
}
// Loop transforms on the ideal graph. Range Check Elimination,
@ -3052,24 +3063,13 @@ bool Compile::Constant::operator==(const Constant& other) {
return false;
}
// Emit constants grouped in the following order:
static BasicType type_order[] = {
T_FLOAT, // 32-bit
T_OBJECT, // 32 or 64-bit
T_ADDRESS, // 32 or 64-bit
T_DOUBLE, // 64-bit
T_LONG, // 64-bit
T_VOID, // 32 or 64-bit (jump-tables are at the end of the constant table for code emission reasons)
T_ILLEGAL
};
static int type_to_size_in_bytes(BasicType t) {
switch (t) {
case T_LONG: return sizeof(jlong );
case T_FLOAT: return sizeof(jfloat );
case T_DOUBLE: return sizeof(jdouble);
// We use T_VOID as marker for jump-table entries (labels) which
// need an interal word relocation.
// need an internal word relocation.
case T_VOID:
case T_ADDRESS:
case T_OBJECT: return sizeof(jobject);
@ -3079,87 +3079,92 @@ static int type_to_size_in_bytes(BasicType t) {
return -1;
}
int Compile::ConstantTable::qsort_comparator(Constant* a, Constant* b) {
// sort descending
if (a->freq() > b->freq()) return -1;
if (a->freq() < b->freq()) return 1;
return 0;
}
void Compile::ConstantTable::calculate_offsets_and_size() {
int size = 0;
for (int t = 0; type_order[t] != T_ILLEGAL; t++) {
BasicType type = type_order[t];
// First, sort the array by frequencies.
_constants.sort(qsort_comparator);
for (int i = 0; i < _constants.length(); i++) {
Constant con = _constants.at(i);
if (con.type() != type) continue; // Skip other types.
#ifdef ASSERT
// Make sure all jump-table entries were sorted to the end of the
// array (they have a negative frequency).
bool found_void = false;
for (int i = 0; i < _constants.length(); i++) {
Constant con = _constants.at(i);
if (con.type() == T_VOID)
found_void = true; // jump-tables
else
assert(!found_void, "wrong sorting");
}
#endif
// Align size for type.
int typesize = type_to_size_in_bytes(con.type());
size = align_size_up(size, typesize);
int offset = 0;
for (int i = 0; i < _constants.length(); i++) {
Constant* con = _constants.adr_at(i);
// Set offset.
con.set_offset(size);
_constants.at_put(i, con);
// Align offset for type.
int typesize = type_to_size_in_bytes(con->type());
offset = align_size_up(offset, typesize);
con->set_offset(offset); // set constant's offset
// Add type size.
size = size + typesize;
if (con->type() == T_VOID) {
MachConstantNode* n = (MachConstantNode*) con->get_jobject();
offset = offset + typesize * n->outcnt(); // expand jump-table
} else {
offset = offset + typesize;
}
}
// Align size up to the next section start (which is insts; see
// CodeBuffer::align_at_start).
assert(_size == -1, "already set?");
_size = align_size_up(size, CodeEntryAlignment);
if (Matcher::constant_table_absolute_addressing) {
set_table_base_offset(0); // No table base offset required
} else {
if (UseRDPCForConstantTableBase) {
// table base offset is set in MachConstantBaseNode::emit
} else {
// When RDPC is not used, the table base is set into the middle of
// the constant table.
int half_size = _size / 2;
assert(half_size * 2 == _size, "sanity");
set_table_base_offset(-half_size);
}
}
_size = align_size_up(offset, CodeEntryAlignment);
}
void Compile::ConstantTable::emit(CodeBuffer& cb) {
MacroAssembler _masm(&cb);
for (int t = 0; type_order[t] != T_ILLEGAL; t++) {
BasicType type = type_order[t];
for (int i = 0; i < _constants.length(); i++) {
Constant con = _constants.at(i);
if (con.type() != type) continue; // Skip other types.
address constant_addr;
switch (con.type()) {
case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break;
case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break;
case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break;
case T_OBJECT: {
jobject obj = con.get_jobject();
int oop_index = _masm.oop_recorder()->find_index(obj);
constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index));
break;
}
case T_ADDRESS: {
address addr = (address) con.get_jobject();
constant_addr = _masm.address_constant(addr);
break;
}
// We use T_VOID as marker for jump-table entries (labels) which
// need an interal word relocation.
case T_VOID: {
// Write a dummy word. The real value is filled in later
// in fill_jump_table_in_constant_table.
address addr = (address) con.get_jobject();
constant_addr = _masm.address_constant(addr);
break;
}
default: ShouldNotReachHere();
}
assert(constant_addr != NULL, "consts section too small");
assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset()));
for (int i = 0; i < _constants.length(); i++) {
Constant con = _constants.at(i);
address constant_addr;
switch (con.type()) {
case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break;
case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break;
case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break;
case T_OBJECT: {
jobject obj = con.get_jobject();
int oop_index = _masm.oop_recorder()->find_index(obj);
constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index));
break;
}
case T_ADDRESS: {
address addr = (address) con.get_jobject();
constant_addr = _masm.address_constant(addr);
break;
}
// We use T_VOID as marker for jump-table entries (labels) which
// need an internal word relocation.
case T_VOID: {
MachConstantNode* n = (MachConstantNode*) con.get_jobject();
// Fill the jump-table with a dummy word. The real value is
// filled in later in fill_jump_table.
address dummy = (address) n;
constant_addr = _masm.address_constant(dummy);
// Expand jump-table
for (uint i = 1; i < n->outcnt(); i++) {
address temp_addr = _masm.address_constant(dummy + i);
assert(temp_addr, "consts section too small");
}
break;
}
default: ShouldNotReachHere();
}
assert(constant_addr, "consts section too small");
assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset()));
}
}
@ -3175,19 +3180,21 @@ void Compile::ConstantTable::add(Constant& con) {
if (con.can_be_reused()) {
int idx = _constants.find(con);
if (idx != -1 && _constants.at(idx).can_be_reused()) {
_constants.adr_at(idx)->inc_freq(con.freq()); // increase the frequency by the current value
return;
}
}
(void) _constants.append(con);
}
Compile::Constant Compile::ConstantTable::add(BasicType type, jvalue value) {
Constant con(type, value);
Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, BasicType type, jvalue value) {
Block* b = Compile::current()->cfg()->_bbs[n->_idx];
Constant con(type, value, b->_freq);
add(con);
return con;
}
Compile::Constant Compile::ConstantTable::add(MachOper* oper) {
Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, MachOper* oper) {
jvalue value;
BasicType type = oper->type()->basic_type();
switch (type) {
@ -3198,20 +3205,18 @@ Compile::Constant Compile::ConstantTable::add(MachOper* oper) {
case T_ADDRESS: value.l = (jobject) oper->constant(); break;
default: ShouldNotReachHere();
}
return add(type, value);
return add(n, type, value);
}
Compile::Constant Compile::ConstantTable::allocate_jump_table(MachConstantNode* n) {
Compile::Constant Compile::ConstantTable::add_jump_table(MachConstantNode* n) {
jvalue value;
// We can use the node pointer here to identify the right jump-table
// as this method is called from Compile::Fill_buffer right before
// the MachNodes are emitted and the jump-table is filled (means the
// MachNode pointers do not change anymore).
value.l = (jobject) n;
Constant con(T_VOID, value, false); // Labels of a jump-table cannot be reused.
for (uint i = 0; i < n->outcnt(); i++) {
add(con);
}
Constant con(T_VOID, value, next_jump_table_freq(), false); // Labels of a jump-table cannot be reused.
add(con);
return con;
}
@ -3230,9 +3235,9 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n
MacroAssembler _masm(&cb);
address* jump_table_base = (address*) (_masm.code()->consts()->start() + offset);
for (int i = 0; i < labels.length(); i++) {
for (uint i = 0; i < n->outcnt(); i++) {
address* constant_addr = &jump_table_base[i];
assert(*constant_addr == (address) n, "all jump-table entries must contain node pointer");
assert(*constant_addr == (((address) n) + i), err_msg("all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, *constant_addr, (((address) n) + i)));
*constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr);
cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type);
}

View File

@ -150,14 +150,16 @@ class Compile : public Phase {
BasicType _type;
jvalue _value;
int _offset; // offset of this constant (in bytes) relative to the constant table base.
float _freq;
bool _can_be_reused; // true (default) if the value can be shared with other users.
public:
Constant() : _type(T_ILLEGAL), _offset(-1), _can_be_reused(true) { _value.l = 0; }
Constant(BasicType type, jvalue value, bool can_be_reused = true) :
Constant() : _type(T_ILLEGAL), _offset(-1), _freq(0.0f), _can_be_reused(true) { _value.l = 0; }
Constant(BasicType type, jvalue value, float freq = 0.0f, bool can_be_reused = true) :
_type(type),
_value(value),
_offset(-1),
_freq(freq),
_can_be_reused(can_be_reused)
{}
@ -173,6 +175,9 @@ class Compile : public Phase {
int offset() const { return _offset; }
void set_offset(int offset) { _offset = offset; }
float freq() const { return _freq; }
void inc_freq(float freq) { _freq += freq; }
bool can_be_reused() const { return _can_be_reused; }
};
@ -182,41 +187,51 @@ class Compile : public Phase {
GrowableArray<Constant> _constants; // Constants of this table.
int _size; // Size in bytes the emitted constant table takes (including padding).
int _table_base_offset; // Offset of the table base that gets added to the constant offsets.
int _nof_jump_tables; // Number of jump-tables in this constant table.
static int qsort_comparator(Constant* a, Constant* b);
// We use negative frequencies to keep the order of the
// jump-tables in which they were added. Otherwise we get into
// trouble with relocation.
float next_jump_table_freq() { return -1.0f * (++_nof_jump_tables); }
public:
ConstantTable() :
_size(-1),
_table_base_offset(-1) // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit).
_table_base_offset(-1), // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit).
_nof_jump_tables(0)
{}
int size() const { assert(_size != -1, "size not yet calculated"); return _size; }
int size() const { assert(_size != -1, "not calculated yet"); return _size; }
void set_table_base_offset(int x) { assert(_table_base_offset == -1, "set only once"); _table_base_offset = x; }
int table_base_offset() const { assert(_table_base_offset != -1, "table base offset not yet set"); return _table_base_offset; }
int calculate_table_base_offset() const; // AD specific
void set_table_base_offset(int x) { assert(_table_base_offset == -1 || x == _table_base_offset, "can't change"); _table_base_offset = x; }
int table_base_offset() const { assert(_table_base_offset != -1, "not set yet"); return _table_base_offset; }
void emit(CodeBuffer& cb);
// Returns the offset of the last entry (the top) of the constant table.
int top_offset() const { assert(_constants.top().offset() != -1, "constant not yet bound"); return _constants.top().offset(); }
int top_offset() const { assert(_constants.top().offset() != -1, "not bound yet"); return _constants.top().offset(); }
void calculate_offsets_and_size();
int find_offset(Constant& con) const;
void add(Constant& con);
Constant add(BasicType type, jvalue value);
Constant add(MachOper* oper);
Constant add(jfloat f) {
Constant add(MachConstantNode* n, BasicType type, jvalue value);
Constant add(MachConstantNode* n, MachOper* oper);
Constant add(MachConstantNode* n, jfloat f) {
jvalue value; value.f = f;
return add(T_FLOAT, value);
return add(n, T_FLOAT, value);
}
Constant add(jdouble d) {
Constant add(MachConstantNode* n, jdouble d) {
jvalue value; value.d = d;
return add(T_DOUBLE, value);
return add(n, T_DOUBLE, value);
}
// Jump table
Constant allocate_jump_table(MachConstantNode* n);
void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const;
// Jump-table
Constant add_jump_table(MachConstantNode* n);
void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray<Label*> labels) const;
};
private:

View File

@ -62,7 +62,6 @@ void trace_type_profile(ciMethod *method, int depth, int bci, ciMethod *prof_met
CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual,
JVMState* jvms, bool allow_inline,
float prof_factor) {
CallGenerator* cg;
ciMethod* caller = jvms->method();
int bci = jvms->bci();
Bytecodes::Code bytecode = caller->java_code_at_bci(bci);
@ -110,7 +109,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
// We do this before the strict f.p. check below because the
// intrinsics handle strict f.p. correctly.
if (allow_inline) {
cg = find_intrinsic(call_method, call_is_virtual);
CallGenerator* cg = find_intrinsic(call_method, call_is_virtual);
if (cg != NULL) return cg;
}
@ -121,33 +120,16 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
if (call_method->is_method_handle_invoke()) {
if (bytecode != Bytecodes::_invokedynamic) {
GraphKit kit(jvms);
Node* n = kit.argument(0);
CallGenerator* cg = CallGenerator::for_method_handle_inline(n, jvms, caller, call_method, profile);
if (cg != NULL) {
return cg;
}
return CallGenerator::for_direct_call(call_method);
Node* method_handle = kit.argument(0);
return CallGenerator::for_method_handle_call(method_handle, jvms, caller, call_method, profile);
}
else {
// Get the CallSite object.
ciMethod* caller_method = jvms->method();
ciBytecodeStream str(caller_method);
str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci.
ciCallSite* call_site = str.get_call_site();
CallGenerator* cg = CallGenerator::for_invokedynamic_inline(call_site, jvms, caller, call_method, profile);
if (cg != NULL) {
return cg;
}
// If something failed, generate a normal dynamic call.
return CallGenerator::for_dynamic_call(call_method);
return CallGenerator::for_invokedynamic_call(jvms, caller, call_method, profile);
}
}
// Do not inline strict fp into non-strict code, or the reverse
bool caller_method_is_strict = jvms->method()->is_strict();
if( caller_method_is_strict ^ call_method->is_strict() ) {
if (caller->is_strict() ^ call_method->is_strict()) {
allow_inline = false;
}
@ -258,7 +240,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
}
if (miss_cg != NULL) {
NOT_PRODUCT(trace_type_profile(jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count));
cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0));
CallGenerator* cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0));
if (cg != NULL) return cg;
}
}

View File

@ -119,6 +119,8 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
} else {
_noop_null = _oop_null; // Should be initialized
}
_pcmp_neq = NULL; // Should be initialized
_pcmp_eq = NULL;
}
void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
@ -128,6 +130,13 @@ void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set");
assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge");
assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge");
if (to_i == _phantom_object) { // Quick test for most common object
if (f->has_unknown_ptr()) {
return;
} else {
f->set_has_unknown_ptr();
}
}
add_edge(f, to_i, PointsToNode::PointsToEdge);
}
@ -163,6 +172,9 @@ int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) {
}
void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) {
// Don't add fields to NULL pointer.
if (is_null_ptr(from_i))
return;
PointsToNode *f = ptnode_adr(from_i);
PointsToNode *t = ptnode_adr(to_i);
@ -177,7 +189,7 @@ void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) {
void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) {
// Don't change non-escaping state of NULL pointer.
if (ni == _noop_null || ni == _oop_null)
if (is_null_ptr(ni))
return;
PointsToNode *npt = ptnode_adr(ni);
PointsToNode::EscapeState old_es = npt->escape_state();
@ -309,6 +321,9 @@ void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edg
visited->set(ni);
PointsToNode *ptn = ptnode_adr(ni);
assert(ptn->node_type() == PointsToNode::LocalVar ||
ptn->node_type() == PointsToNode::Field, "sanity");
assert(ptn->edge_count() != 0, "should have at least phantom_object");
// Mark current edges as visited and move deferred edges to separate array.
for (uint i = 0; i < ptn->edge_count(); ) {
@ -329,6 +344,7 @@ void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edg
uint t = deferred_edges->at(next);
PointsToNode *ptt = ptnode_adr(t);
uint e_cnt = ptt->edge_count();
assert(e_cnt != 0, "should have at least phantom_object");
for (uint e = 0; e < e_cnt; e++) {
uint etgt = ptt->edge_target(e);
if (visited->test_set(etgt))
@ -337,10 +353,6 @@ void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edg
PointsToNode::EdgeType et = ptt->edge_type(e);
if (et == PointsToNode::PointsToEdge) {
add_pointsto_edge(ni, etgt);
if(etgt == _phantom_object) {
// Special case - field set outside (globally escaping).
set_escape_state(ni, PointsToNode::GlobalEscape);
}
} else if (et == PointsToNode::DeferredEdge) {
deferred_edges->append(etgt);
} else {
@ -348,6 +360,20 @@ void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edg
}
}
}
if (ptn->edge_count() == 0) {
// No pointsto edges found after deferred edges are removed.
// For example, in the next case where call is replaced
// with uncommon trap and as result array's load references
// itself through deferred edges:
//
// A a = b[i];
// if (c!=null) a = c.foo();
// b[i] = a;
//
// Assume the value was set outside this method and
// add edge to phantom object.
add_pointsto_edge(ni, _phantom_object);
}
}
@ -356,13 +382,25 @@ void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edg
// a pointsto edge is added if it is a JavaObject
void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) {
// No fields for NULL pointer.
if (is_null_ptr(adr_i)) {
return;
}
PointsToNode* an = ptnode_adr(adr_i);
PointsToNode* to = ptnode_adr(to_i);
bool deferred = (to->node_type() == PointsToNode::LocalVar);
bool escaped = (to_i == _phantom_object) && (offs == Type::OffsetTop);
if (escaped) {
// Values in fields escaped during call.
assert(an->escape_state() >= PointsToNode::ArgEscape, "sanity");
offs = Type::OffsetBot;
}
for (uint fe = 0; fe < an->edge_count(); fe++) {
assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge");
int fi = an->edge_target(fe);
if (escaped) {
set_escape_state(fi, PointsToNode::GlobalEscape);
}
PointsToNode* pf = ptnode_adr(fi);
int po = pf->offset();
if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) {
@ -377,6 +415,15 @@ void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) {
// Add a deferred edge from node given by "from_i" to any field of adr_i
// whose offset matches "offset".
void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) {
// No fields for NULL pointer.
if (is_null_ptr(adr_i)) {
return;
}
if (adr_i == _phantom_object) {
// Add only one edge for unknown object.
add_pointsto_edge(from_i, _phantom_object);
return;
}
PointsToNode* an = ptnode_adr(adr_i);
bool is_alloc = an->_node->is_Allocate();
for (uint fe = 0; fe < an->edge_count(); fe++) {
@ -392,6 +439,13 @@ void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int o
add_deferred_edge(from_i, fi);
}
}
// Some fields references (AddP) may still be missing
// until Connection Graph construction is complete.
// For example, loads from RAW pointers with offset 0
// which don't have AddP.
// A reference to phantom_object will be added if
// a field reference is still missing after completing
// Connection Graph (see remove_deferred()).
}
// Helper functions
@ -1540,8 +1594,8 @@ bool ConnectionGraph::compute_escape() {
GrowableArray<Node*> alloc_worklist;
GrowableArray<Node*> addp_worklist;
GrowableArray<Node*> ptr_cmp_worklist;
PhaseGVN* igvn = _igvn;
bool has_allocations = false;
// Push all useful nodes onto CG list and set their type.
for( uint next = 0; next < worklist_init.size(); ++next ) {
@ -1551,11 +1605,8 @@ bool ConnectionGraph::compute_escape() {
// for an escape status. See process_call_result() below.
if (n->is_Allocate() || n->is_CallStaticJava() &&
ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) {
has_allocations = true;
if (n->is_Allocate())
alloc_worklist.append(n);
}
if(n->is_AddP()) {
alloc_worklist.append(n);
} else if(n->is_AddP()) {
// Collect address nodes. Use them during stage 3 below
// to build initial connection graph field edges.
addp_worklist.append(n);
@ -1563,6 +1614,10 @@ bool ConnectionGraph::compute_escape() {
// Collect all MergeMem nodes to add memory slices for
// scalar replaceable objects in split_unique_types().
_mergemem_worklist.append(n->as_MergeMem());
} else if (OptimizePtrCompare && n->is_Cmp() &&
(n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) {
// Compare pointers nodes
ptr_cmp_worklist.append(n);
}
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node* m = n->fast_out(i); // Get user
@ -1570,7 +1625,7 @@ bool ConnectionGraph::compute_escape() {
}
}
if (!has_allocations) {
if (alloc_worklist.length() == 0) {
_collecting = false;
return false; // Nothing to do.
}
@ -1588,7 +1643,7 @@ bool ConnectionGraph::compute_escape() {
for( uint next = 0; next < addp_length; ++next ) {
Node* n = addp_worklist.at(next);
Node* base = get_addp_base(n);
if (base->is_Proj())
if (base->is_Proj() && base->in(0)->is_Call())
base = base->in(0);
PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type();
if (nt == PointsToNode::JavaObject) {
@ -1653,39 +1708,7 @@ bool ConnectionGraph::compute_escape() {
}
#undef CG_BUILD_ITER_LIMIT
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
// 5. Find fields initializing values for not escaped allocations
uint alloc_length = alloc_worklist.length();
for (uint next = 0; next < alloc_length; ++next) {
Node* n = alloc_worklist.at(next);
if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) {
find_init_values(n, &visited, igvn);
}
}
worklist.clear();
// 6. Remove deferred edges from the graph.
uint cg_length = cg_worklist.length();
for (uint next = 0; next < cg_length; ++next) {
int ni = cg_worklist.at(next);
PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
remove_deferred(ni, &worklist, &visited);
Node *n = ptn->_node;
}
}
// 7. Adjust escape state of nonescaping objects.
for (uint next = 0; next < addp_length; ++next) {
Node* n = addp_worklist.at(next);
adjust_escape_state(n);
}
// 8. Propagate escape states.
// 5. Propagate escaped states.
worklist.clear();
// mark all nodes reachable from GlobalEscape nodes
@ -1694,20 +1717,72 @@ bool ConnectionGraph::compute_escape() {
// mark all nodes reachable from ArgEscape nodes
bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape);
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
// 6. Find fields initializing values for not escaped allocations
uint alloc_length = alloc_worklist.length();
for (uint next = 0; next < alloc_length; ++next) {
Node* n = alloc_worklist.at(next);
if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) {
has_non_escaping_obj = true;
if (n->is_Allocate()) {
find_init_values(n, &visited, igvn);
}
}
}
uint cg_length = cg_worklist.length();
// Skip the rest of code if all objects escaped.
if (!has_non_escaping_obj) {
cg_length = 0;
addp_length = 0;
}
for (uint next = 0; next < cg_length; ++next) {
int ni = cg_worklist.at(next);
PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
if (ptn->edge_count() == 0) {
// No values were found. Assume the value was set
// outside this method - add edge to phantom object.
add_pointsto_edge(ni, _phantom_object);
}
}
}
// 7. Remove deferred edges from the graph.
for (uint next = 0; next < cg_length; ++next) {
int ni = cg_worklist.at(next);
PointsToNode* ptn = ptnode_adr(ni);
PointsToNode::NodeType nt = ptn->node_type();
if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) {
remove_deferred(ni, &worklist, &visited);
}
}
// 8. Adjust escape state of nonescaping objects.
for (uint next = 0; next < addp_length; ++next) {
Node* n = addp_worklist.at(next);
adjust_escape_state(n);
}
// push all NoEscape nodes on the worklist
worklist.clear();
for( uint next = 0; next < cg_length; ++next ) {
int nk = cg_worklist.at(next);
if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape)
if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape &&
!is_null_ptr(nk))
worklist.push(nk);
}
alloc_worklist.clear();
// mark all nodes reachable from NoEscape nodes
// Propagate scalar_replaceable value.
while(worklist.length() > 0) {
uint nk = worklist.pop();
PointsToNode* ptn = ptnode_adr(nk);
if (ptn->node_type() == PointsToNode::JavaObject &&
!(nk == _noop_null || nk == _oop_null))
has_non_escaping_obj = true; // Non Escape
Node* n = ptn->_node;
bool scalar_replaceable = ptn->scalar_replaceable();
if (n->is_Allocate() && scalar_replaceable) {
@ -1719,6 +1794,8 @@ bool ConnectionGraph::compute_escape() {
uint e_cnt = ptn->edge_count();
for (uint ei = 0; ei < e_cnt; ei++) {
uint npi = ptn->edge_target(ei);
if (is_null_ptr(npi))
continue;
PointsToNode *np = ptnode_adr(npi);
if (np->escape_state() < PointsToNode::NoEscape) {
set_escape_state(npi, PointsToNode::NoEscape);
@ -1727,7 +1804,6 @@ bool ConnectionGraph::compute_escape() {
}
worklist.push(npi);
} else if (np->scalar_replaceable() && !scalar_replaceable) {
// Propagate scalar_replaceable value.
np->set_scalar_replaceable(false);
worklist.push(npi);
}
@ -1737,9 +1813,11 @@ bool ConnectionGraph::compute_escape() {
_collecting = false;
assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build");
assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape, "sanity");
assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape &&
ptnode_adr(_oop_null)->edge_count() == 0, "sanity");
if (UseCompressedOops) {
assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity");
assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape &&
ptnode_adr(_noop_null)->edge_count() == 0, "sanity");
}
if (EliminateLocks && has_non_escaping_obj) {
@ -1749,18 +1827,53 @@ bool ConnectionGraph::compute_escape() {
Node *n = C->macro_node(i);
if (n->is_AbstractLock()) { // Lock and Unlock nodes
AbstractLockNode* alock = n->as_AbstractLock();
if (!alock->is_eliminated()) {
if (!alock->is_eliminated() || alock->is_coarsened()) {
PointsToNode::EscapeState es = escape_state(alock->obj_node());
assert(es != PointsToNode::UnknownEscape, "should know");
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated
alock->set_eliminated();
if (!alock->is_eliminated()) {
// Mark it eliminated to update any counters
alock->set_eliminated();
} else {
// The lock could be marked eliminated by lock coarsening
// code during first IGVN before EA. Clear coarsened flag
// to eliminate all associated locks/unlocks and relock
// during deoptimization.
alock->clear_coarsened();
}
}
}
}
}
}
if (OptimizePtrCompare && has_non_escaping_obj) {
// Add ConI(#CC_GT) and ConI(#CC_EQ).
_pcmp_neq = igvn->makecon(TypeInt::CC_GT);
_pcmp_eq = igvn->makecon(TypeInt::CC_EQ);
// Optimize objects compare.
while (ptr_cmp_worklist.length() != 0) {
Node *n = ptr_cmp_worklist.pop();
Node *res = optimize_ptr_compare(n);
if (res != NULL) {
#ifndef PRODUCT
if (PrintOptimizePtrCompare) {
tty->print_cr("++++ Replaced: %d %s(%d,%d) --> %s", n->_idx, (n->Opcode() == Op_CmpP ? "CmpP" : "CmpN"), n->in(1)->_idx, n->in(2)->_idx, (res == _pcmp_eq ? "EQ" : "NotEQ"));
if (Verbose) {
n->dump(1);
}
}
#endif
_igvn->replace_node(n, res);
}
}
// cleanup
if (_pcmp_neq->outcnt() == 0)
igvn->hash_delete(_pcmp_neq);
if (_pcmp_eq->outcnt() == 0)
igvn->hash_delete(_pcmp_eq);
}
#ifndef PRODUCT
if (PrintEscapeAnalysis) {
dump(); // Dump ConnectionGraph
@ -1821,15 +1934,30 @@ void ConnectionGraph::find_init_values(Node* alloc, VectorSet* visited, PhaseTra
// Connection Graph does not record a default initialization by NULL
// captured by Initialize node.
//
uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
uint ae_cnt = pta->edge_count();
bool visited_bottom_offset = false;
for (uint ei = 0; ei < ae_cnt; ei++) {
uint nidx = pta->edge_target(ei); // Field (AddP)
PointsToNode* ptn = ptnode_adr(nidx);
assert(ptn->_node->is_AddP(), "Should be AddP nodes only");
int offset = ptn->offset();
if (offset != Type::OffsetBot &&
offset != oopDesc::klass_offset_in_bytes() &&
!visited->test_set(offset)) {
if (offset == Type::OffsetBot) {
if (!visited_bottom_offset) {
visited_bottom_offset = true;
// Check only oop fields.
const Type* adr_type = ptn->_node->as_AddP()->bottom_type();
if (!adr_type->isa_aryptr() ||
(adr_type->isa_aryptr()->klass() == NULL) ||
adr_type->isa_aryptr()->klass()->is_obj_array_klass()) {
// OffsetBot is used to reference array's element,
// always add reference to NULL since we don't
// known which element is referenced.
add_edge_from_fields(alloc->_idx, null_idx, offset);
}
}
} else if (offset != oopDesc::klass_offset_in_bytes() &&
!visited->test_set(offset)) {
// Check only oop fields.
const Type* adr_type = ptn->_node->as_AddP()->bottom_type();
@ -1904,7 +2032,6 @@ void ConnectionGraph::find_init_values(Node* alloc, VectorSet* visited, PhaseTra
}
if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
// A field's initializing value was not recorded. Add NULL.
uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
add_edge_from_fields(alloc->_idx, null_idx, offset);
}
}
@ -1990,13 +2117,21 @@ bool ConnectionGraph::propagate_escape_state(GrowableArray<int>* cg_worklist,
}
// mark all reachable nodes
while (worklist->length() > 0) {
PointsToNode* ptn = ptnode_adr(worklist->pop());
if (ptn->node_type() == PointsToNode::JavaObject) {
int pt = worklist->pop();
PointsToNode* ptn = ptnode_adr(pt);
if (ptn->node_type() == PointsToNode::JavaObject &&
!is_null_ptr(pt)) {
has_java_obj = true;
if (esc_state > PointsToNode::NoEscape) {
// fields values are unknown if object escapes
add_edge_from_fields(pt, _phantom_object, Type::OffsetBot);
}
}
uint e_cnt = ptn->edge_count();
for (uint ei = 0; ei < e_cnt; ei++) {
uint npi = ptn->edge_target(ei);
if (is_null_ptr(npi))
continue;
PointsToNode *np = ptnode_adr(npi);
if (np->escape_state() < esc_state) {
set_escape_state(npi, esc_state);
@ -2008,8 +2143,100 @@ bool ConnectionGraph::propagate_escape_state(GrowableArray<int>* cg_worklist,
return has_java_obj && (esc_state < PointsToNode::GlobalEscape);
}
void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
// Optimize objects compare.
Node* ConnectionGraph::optimize_ptr_compare(Node* n) {
assert(OptimizePtrCompare, "sanity");
// Clone returned Set since PointsTo() returns pointer
// to the same structure ConnectionGraph.pt_ptset.
VectorSet ptset1 = *PointsTo(n->in(1));
VectorSet ptset2 = *PointsTo(n->in(2));
// Check simple cases first.
if (ptset1.Size() == 1) {
uint pt1 = ptset1.getelem();
PointsToNode* ptn1 = ptnode_adr(pt1);
if (ptn1->escape_state() == PointsToNode::NoEscape) {
if (ptset2.Size() == 1 && ptset2.getelem() == pt1) {
// Comparing the same not escaping object.
return _pcmp_eq;
}
Node* obj = ptn1->_node;
// Comparing not escaping allocation.
if ((obj->is_Allocate() || obj->is_CallStaticJava()) &&
!ptset2.test(pt1)) {
return _pcmp_neq; // This includes nullness check.
}
}
} else if (ptset2.Size() == 1) {
uint pt2 = ptset2.getelem();
PointsToNode* ptn2 = ptnode_adr(pt2);
if (ptn2->escape_state() == PointsToNode::NoEscape) {
Node* obj = ptn2->_node;
// Comparing not escaping allocation.
if ((obj->is_Allocate() || obj->is_CallStaticJava()) &&
!ptset1.test(pt2)) {
return _pcmp_neq; // This includes nullness check.
}
}
}
if (!ptset1.disjoint(ptset2)) {
return NULL; // Sets are not disjoint
}
// Sets are disjoint.
bool set1_has_unknown_ptr = ptset1.test(_phantom_object) != 0;
bool set2_has_unknown_ptr = ptset2.test(_phantom_object) != 0;
bool set1_has_null_ptr = (ptset1.test(_oop_null) | ptset1.test(_noop_null)) != 0;
bool set2_has_null_ptr = (ptset2.test(_oop_null) | ptset2.test(_noop_null)) != 0;
if (set1_has_unknown_ptr && set2_has_null_ptr ||
set2_has_unknown_ptr && set1_has_null_ptr) {
// Check nullness of unknown object.
return NULL;
}
// Disjointness by itself is not sufficient since
// alias analysis is not complete for escaped objects.
// Disjoint sets are definitely unrelated only when
// at least one set has only not escaping objects.
if (!set1_has_unknown_ptr && !set1_has_null_ptr) {
bool has_only_non_escaping_alloc = true;
for (VectorSetI i(&ptset1); i.test(); ++i) {
uint pt = i.elem;
PointsToNode* ptn = ptnode_adr(pt);
Node* obj = ptn->_node;
if (ptn->escape_state() != PointsToNode::NoEscape ||
!(obj->is_Allocate() || obj->is_CallStaticJava())) {
has_only_non_escaping_alloc = false;
break;
}
}
if (has_only_non_escaping_alloc) {
return _pcmp_neq;
}
}
if (!set2_has_unknown_ptr && !set2_has_null_ptr) {
bool has_only_non_escaping_alloc = true;
for (VectorSetI i(&ptset2); i.test(); ++i) {
uint pt = i.elem;
PointsToNode* ptn = ptnode_adr(pt);
Node* obj = ptn->_node;
if (ptn->escape_state() != PointsToNode::NoEscape ||
!(obj->is_Allocate() || obj->is_CallStaticJava())) {
has_only_non_escaping_alloc = false;
break;
}
}
if (has_only_non_escaping_alloc) {
return _pcmp_neq;
}
}
return NULL;
}
void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) {
bool is_arraycopy = false;
switch (call->Opcode()) {
#ifdef ASSERT
case Op_Allocate:
@ -2019,25 +2246,44 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
assert(false, "should be done already");
break;
#endif
case Op_CallLeaf:
case Op_CallLeafNoFP:
is_arraycopy = (call->as_CallLeaf()->_name != NULL &&
strstr(call->as_CallLeaf()->_name, "arraycopy") != 0);
// fall through
case Op_CallLeaf:
{
// Stub calls, objects do not escape but they are not scale replaceable.
// Adjust escape state for outgoing arguments.
const TypeTuple * d = call->tf()->domain();
bool src_has_oops = false;
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
Node *arg = call->in(i)->uncast();
const Type *aat = phase->type(arg);
PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state();
if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() &&
ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) {
(is_arraycopy || arg_esc < PointsToNode::ArgEscape)) {
assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||
aat->isa_ptr() != NULL, "expecting an Ptr");
bool arg_has_oops = aat->isa_oopptr() &&
(aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() ||
(aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass()));
if (i == TypeFunc::Parms) {
src_has_oops = arg_has_oops;
}
//
// src or dst could be j.l.Object when other is basic type array:
//
// arraycopy(char[],0,Object*,0,size);
// arraycopy(Object*,0,char[],0,size);
//
// Don't add edges from dst's fields in such cases.
//
bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy &&
arg_has_oops && (i > TypeFunc::Parms);
#ifdef ASSERT
if (!(call->Opcode() == Op_CallLeafNoFP &&
call->as_CallLeaf()->_name != NULL &&
(strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) ||
if (!(is_arraycopy ||
call->as_CallLeaf()->_name != NULL &&
(strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 ||
strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 ))
@ -2046,20 +2292,72 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
assert(false, "EA: unexpected CallLeaf");
}
#endif
// Always process arraycopy's destination object since
// we need to add all possible edges to references in
// source object.
if (arg_esc >= PointsToNode::ArgEscape &&
!arg_is_arraycopy_dest) {
continue;
}
set_escape_state(arg->_idx, PointsToNode::ArgEscape);
Node* arg_base = arg;
if (arg->is_AddP()) {
//
// The inline_native_clone() case when the arraycopy stub is called
// after the allocation before Initialize and CheckCastPP nodes.
// Or normal arraycopy for object arrays case.
//
// Set AddP's base (Allocate) as not scalar replaceable since
// pointer to the base (with offset) is passed as argument.
//
arg = get_addp_base(arg);
arg_base = get_addp_base(arg);
}
for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) {
uint pt = j.elem;
set_escape_state(pt, PointsToNode::ArgEscape);
VectorSet argset = *PointsTo(arg_base); // Clone set
for( VectorSetI j(&argset); j.test(); ++j ) {
uint pd = j.elem; // Destination object
set_escape_state(pd, PointsToNode::ArgEscape);
if (arg_is_arraycopy_dest) {
PointsToNode* ptd = ptnode_adr(pd);
// Conservatively reference an unknown object since
// not all source's fields/elements may be known.
add_edge_from_fields(pd, _phantom_object, Type::OffsetBot);
Node *src = call->in(TypeFunc::Parms)->uncast();
Node* src_base = src;
if (src->is_AddP()) {
src_base = get_addp_base(src);
}
// Create edges from destination's fields to
// everything known source's fields could point to.
for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) {
uint ps = s.elem;
bool has_bottom_offset = false;
for (uint fd = 0; fd < ptd->edge_count(); fd++) {
assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge");
int fdi = ptd->edge_target(fd);
PointsToNode* pfd = ptnode_adr(fdi);
int offset = pfd->offset();
if (offset == Type::OffsetBot)
has_bottom_offset = true;
assert(offset != -1, "offset should be set");
add_deferred_edge_to_fields(fdi, ps, offset);
}
// Destination object may not have access (no field edge)
// to fields which are accessed in source object.
// As result no edges will be created to those source's
// fields and escape state of destination object will
// not be propagated to those fields.
//
// Mark source object as global escape except in
// the case with Type::OffsetBot field (which is
// common case for array elements access) when
// edges are created to all source's fields.
if (!has_bottom_offset) {
set_escape_state(ps, PointsToNode::GlobalEscape);
}
}
}
}
}
}
@ -2102,14 +2400,16 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) {
uint pt = j.elem;
if (global_escapes) {
//The argument global escapes, mark everything it could point to
// The argument global escapes, mark everything it could point to
set_escape_state(pt, PointsToNode::GlobalEscape);
add_edge_from_fields(pt, _phantom_object, Type::OffsetBot);
} else {
if (fields_escapes) {
// The argument itself doesn't escape, but any fields might
add_edge_from_fields(pt, _phantom_object, Type::OffsetBot);
}
set_escape_state(pt, PointsToNode::ArgEscape);
if (fields_escapes) {
// The argument itself doesn't escape, but any fields might.
// Use OffsetTop to indicate such case.
add_edge_from_fields(pt, _phantom_object, Type::OffsetTop);
}
}
}
}
@ -2135,6 +2435,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) {
uint pt = j.elem;
set_escape_state(pt, PointsToNode::GlobalEscape);
add_edge_from_fields(pt, _phantom_object, Type::OffsetBot);
}
}
}
@ -2235,15 +2536,16 @@ void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *pha
// it's fields will be marked as NoEscape at least.
set_escape_state(call_idx, PointsToNode::NoEscape);
ptnode_adr(call_idx)->set_scalar_replaceable(false);
// Fields values are unknown
add_edge_from_fields(call_idx, _phantom_object, Type::OffsetBot);
add_pointsto_edge(resproj_idx, call_idx);
copy_dependencies = true;
} else if (call_analyzer->is_return_local()) {
} else {
// determine whether any arguments are returned
set_escape_state(call_idx, PointsToNode::ArgEscape);
bool ret_arg = false;
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
if (at->isa_oopptr() != NULL) {
Node *arg = call->in(i)->uncast();
@ -2259,17 +2561,14 @@ void ConnectionGraph::process_call_result(ProjNode *resproj, PhaseTransform *pha
}
}
}
if (done && !ret_arg) {
// Returns unknown object.
set_escape_state(call_idx, PointsToNode::GlobalEscape);
add_pointsto_edge(resproj_idx, _phantom_object);
}
if (done) {
copy_dependencies = true;
// is_return_local() is true when only arguments are returned.
if (!ret_arg || !call_analyzer->is_return_local()) {
// Returns unknown object.
add_pointsto_edge(resproj_idx, _phantom_object);
}
}
} else {
set_escape_state(call_idx, PointsToNode::GlobalEscape);
add_pointsto_edge(resproj_idx, _phantom_object);
}
if (copy_dependencies)
call_analyzer->copy_dependencies(_compile->dependencies());
@ -2431,6 +2730,11 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, false);
break;
}
case Op_PartialSubtypeCheck:
{ // Produces Null or notNull and is used in CmpP.
add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true);
break;
}
case Op_Phi:
{
const Type *t = n->as_Phi()->type();
@ -2589,10 +2893,11 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
case Op_AddP:
{
Node *base = get_addp_base(n);
int offset = address_offset(n, phase);
// Create a field edge to this node from everything base could point to.
for( VectorSetI i(PointsTo(base)); i.test(); ++i ) {
uint pt = i.elem;
add_field_edge(pt, n_idx, address_offset(n, phase));
add_field_edge(pt, n_idx, offset);
}
break;
}
@ -2659,6 +2964,10 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
int offset = address_offset(adr, phase);
for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) {
uint pt = i.elem;
if (adr->is_AddP()) {
// Add field edge if it is missing.
add_field_edge(pt, adr->_idx, offset);
}
add_deferred_edge_to_fields(n_idx, pt, offset);
}
break;
@ -2668,6 +2977,11 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
assert(false, "Op_Parm");
break;
}
case Op_PartialSubtypeCheck:
{
assert(false, "Op_PartialSubtypeCheck");
break;
}
case Op_Phi:
{
#ifdef ASSERT
@ -2745,11 +3059,14 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
assert(adr->is_AddP(), "expecting an AddP");
Node *adr_base = get_addp_base(adr);
Node *val = n->in(MemNode::ValueIn)->uncast();
int offset = address_offset(adr, phase);
// For everything "adr_base" could point to, create a deferred edge
// to "val" from each field with the same offset.
for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) {
uint pt = i.elem;
add_edge_from_fields(pt, val->_idx, address_offset(adr, phase));
// Add field edge if it is missing.
add_field_edge(pt, adr->_idx, offset);
add_edge_from_fields(pt, val->_idx, offset);
}
break;
}

View File

@ -160,6 +160,7 @@ private:
Node* _node; // Ideal node corresponding to this PointsTo node.
int _offset; // Object fields offsets.
bool _scalar_replaceable; // Not escaped object could be replaced with scalar
bool _has_unknown_ptr; // Has edge to phantom_object
public:
PointsToNode():
@ -168,6 +169,7 @@ public:
_edges(NULL),
_node(NULL),
_offset(-1),
_has_unknown_ptr(false),
_scalar_replaceable(true) {}
@ -175,6 +177,7 @@ public:
NodeType node_type() const { return _type;}
int offset() { return _offset;}
bool scalar_replaceable() { return _scalar_replaceable;}
bool has_unknown_ptr() { return _has_unknown_ptr;}
void set_offset(int offs) { _offset = offs;}
void set_escape_state(EscapeState state) { _escape = state; }
@ -183,6 +186,7 @@ public:
_type = ntype;
}
void set_scalar_replaceable(bool v) { _scalar_replaceable = v; }
void set_has_unknown_ptr() { _has_unknown_ptr = true; }
// count of outgoing edges
uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); }
@ -236,6 +240,8 @@ private:
// are assumed to point to.
uint _oop_null; // ConP(#NULL)->_idx
uint _noop_null; // ConN(#NULL)->_idx
Node* _pcmp_neq; // ConI(#CC_GT)
Node* _pcmp_eq; // ConI(#CC_EQ)
Compile * _compile; // Compile object for current compilation
PhaseIterGVN * _igvn; // Value numbering
@ -248,6 +254,8 @@ private:
}
uint nodes_size() const { return _nodes.length(); }
bool is_null_ptr(uint idx) const { return (idx == _noop_null || idx == _oop_null); }
// Add node to ConnectionGraph.
void add_node(Node *n, PointsToNode::NodeType nt, PointsToNode::EscapeState es, bool done);
@ -331,10 +339,9 @@ private:
}
// Notify optimizer that a node has been modified
// Node: This assumes that escape analysis is run before
// PhaseIterGVN creation
void record_for_optimizer(Node *n) {
_igvn->_worklist.push(n);
_igvn->add_users_to_worklist(n);
}
// Set the escape state of a node
@ -351,6 +358,9 @@ private:
GrowableArray<uint>* worklist,
PointsToNode::EscapeState esc_state);
// Optimize objects compare.
Node* optimize_ptr_compare(Node* n);
// Compute the escape information
bool compute_escape();

View File

@ -95,7 +95,7 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) {
assert(in0 != NULL, "Only control-dependent");
const Node *p = in0->is_block_proj();
if (p != NULL && p != n) { // Control from a block projection?
assert(!n->pinned() || n->is_MachConstantBase() || n->is_SafePointScalarObject(), "only pinned MachConstantBase or SafePointScalarObject node is expected here");
assert(!n->pinned() || n->is_MachConstantBase(), "only pinned MachConstantBase node is expected here");
// Find trailing Region
Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block
uint j = 0;

View File

@ -447,6 +447,9 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) {
if (flags & Node::Flag_may_be_short_branch) {
print_prop("may_be_short_branch", "true");
}
if (flags & Node::Flag_has_call) {
print_prop("has_call", "true");
}
if (C->matcher() != NULL) {
if (C->matcher()->is_shared(node)) {

View File

@ -548,6 +548,22 @@ void Block::needed_for_next_call(Node *this_call, VectorSet &next_call, Block_Ar
set_next_call(call, next_call, bbs);
}
//------------------------------add_call_kills-------------------------------------
void Block::add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) {
// Fill in the kill mask for the call
for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) {
if( !regs.Member(r) ) { // Not already defined by the call
// Save-on-call register?
if ((save_policy[r] == 'C') ||
(save_policy[r] == 'A') ||
((save_policy[r] == 'E') && exclude_soe)) {
proj->_rout.Insert(r);
}
}
}
}
//------------------------------sched_call-------------------------------------
uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call ) {
RegMask regs;
@ -631,17 +647,7 @@ uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_
proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask());
}
// Fill in the kill mask for the call
for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) {
if( !regs.Member(r) ) { // Not already defined by the call
// Save-on-call register?
if ((save_policy[r] == 'C') ||
(save_policy[r] == 'A') ||
((save_policy[r] == 'E') && exclude_soe)) {
proj->_rout.Insert(r);
}
}
}
add_call_kills(proj, regs, save_policy, exclude_soe);
return node_cnt;
}
@ -776,6 +782,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect
}
#endif
uint max_idx = matcher.C->unique();
// Pull from worklist and schedule
while( worklist.size() ) { // Worklist is not ready
@ -815,11 +822,28 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect
phi_cnt = sched_call(matcher, cfg->_bbs, phi_cnt, worklist, ready_cnt, mcall, next_call);
continue;
}
if (n->is_Mach() && n->as_Mach()->has_call()) {
RegMask regs;
regs.Insert(matcher.c_frame_pointer());
regs.OR(n->out_RegMask());
MachProjNode *proj = new (matcher.C, 1) MachProjNode( n, 1, RegMask::Empty, MachProjNode::fat_proj );
cfg->_bbs.map(proj->_idx,this);
_nodes.insert(phi_cnt++, proj);
add_call_kills(proj, regs, matcher._c_reg_save_policy, false);
}
// Children are now all ready
for (DUIterator_Fast i5max, i5 = n->fast_outs(i5max); i5 < i5max; i5++) {
Node* m = n->fast_out(i5); // Get user
if( cfg->_bbs[m->_idx] != this ) continue;
if( m->is_Phi() ) continue;
if (m->_idx > max_idx) { // new node, skip it
assert(m->is_MachProj() && n->is_Mach() && n->as_Mach()->has_call(), "unexpected node types");
continue;
}
if( !--ready_cnt[m->_idx] )
worklist.push(m);
}

View File

@ -715,7 +715,6 @@ Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) {
long limit_con = cl->limit()->get_int();
julong trip_cnt = cl->trip_count();
long final_con = init_con + trip_cnt*stride_con;
final_con -= stride_con;
int final_int = (int)final_con;
// The final value should be in integer range since the loop
// is counted and the limit was checked for overflow.
@ -1947,7 +1946,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
}
// Nothing to do, so get out
if( !C->has_loops() && !do_split_ifs && !_verify_me && !_verify_only ) {
if( !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only ) {
_igvn.optimize(); // Cleanup NeverBranches
return;
}

View File

@ -480,21 +480,20 @@ void MachTypeNode::dump_spec(outputStream *st) const {
//=============================================================================
int MachConstantNode::constant_offset() {
int offset = _constant.offset();
// Bind the offset lazily.
if (offset == -1) {
if (_constant.offset() == -1) {
Compile::ConstantTable& constant_table = Compile::current()->constant_table();
// If called from Compile::scratch_emit_size assume the worst-case
// for load offsets: half the constant table size.
// NOTE: Don't return or calculate the actual offset (which might
// be zero) because that leads to problems with e.g. jumpXtnd on
// some architectures (cf. add-optimization in SPARC jumpXtnd).
if (Compile::current()->in_scratch_emit_size())
return constant_table.size() / 2;
offset = constant_table.table_base_offset() + constant_table.find_offset(_constant);
_constant.set_offset(offset);
int offset = constant_table.find_offset(_constant);
// If called from Compile::scratch_emit_size return the
// pre-calculated offset.
// NOTE: If the AD file does some table base offset optimizations
// later the AD file needs to take care of this fact.
if (Compile::current()->in_scratch_emit_size()) {
return constant_table.calculate_table_base_offset() + offset;
}
_constant.set_offset(constant_table.table_base_offset() + offset);
}
return offset;
return _constant.offset();
}

View File

@ -190,6 +190,9 @@ public:
// Avoid back to back some instructions on some CPUs.
bool avoid_back_to_back() const { return (flags() & Flag_avoid_back_to_back) != 0; }
// instruction implemented with a call
bool has_call() const { return (flags() & Flag_has_call) != 0; }
// First index in _in[] corresponding to operand, or -1 if there is none
int operand_index(uint operand) const;

View File

@ -81,7 +81,7 @@ void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcal
uint old_unique = C->unique();
Node* new_in = old_sosn->clone(jvms_adj, sosn_map);
if (old_unique != C->unique()) {
new_in->set_req(0, newcall->in(0)); // reset control edge
new_in->set_req(0, C->root()); // reset control edge
new_in = transform_later(new_in); // Register new node.
}
old_in = new_in;
@ -565,7 +565,6 @@ bool PhaseMacroExpand::can_eliminate_allocation(AllocateNode *alloc, GrowableArr
if (res == NULL) {
// All users were eliminated.
} else if (!res->is_CheckCastPP()) {
alloc->_is_scalar_replaceable = false; // don't try again
NOT_PRODUCT(fail_eliminate = "Allocation does not have unique CheckCastPP";)
can_eliminate = false;
} else {
@ -719,7 +718,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray <Sa
alloc,
#endif
first_ind, nfields);
sobj->init_req(0, sfpt->in(TypeFunc::Control));
sobj->init_req(0, C->root());
transform_later(sobj);
// Scan object's fields adding an input to the safepoint for each field.
@ -762,10 +761,10 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray <Sa
Node *field_val = value_from_mem(mem, basic_elem_type, field_type, field_addr_type, alloc);
if (field_val == NULL) {
// we weren't able to find a value for this field,
// give up on eliminating this allocation
alloc->_is_scalar_replaceable = false; // don't try again
// remove any extra entries we added to the safepoint
// We weren't able to find a value for this field,
// give up on eliminating this allocation.
// Remove any extra entries we added to the safepoint.
uint last = sfpt->req() - 1;
for (int k = 0; k < j; k++) {
sfpt->del_req(last--);
@ -1804,9 +1803,9 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
#ifndef PRODUCT
if (PrintEliminateLocks) {
if (alock->is_Lock()) {
tty->print_cr("++++ Eliminating: %d Lock", alock->_idx);
tty->print_cr("++++ Eliminated: %d Lock", alock->_idx);
} else {
tty->print_cr("++++ Eliminating: %d Unlock", alock->_idx);
tty->print_cr("++++ Eliminated: %d Unlock", alock->_idx);
}
}
#endif
@ -2165,11 +2164,12 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) {
_igvn.replace_node(_memproj_fallthrough, mem_phi);
}
//------------------------------expand_macro_nodes----------------------
// Returns true if a failure occurred.
bool PhaseMacroExpand::expand_macro_nodes() {
//---------------------------eliminate_macro_nodes----------------------
// Eliminate scalar replaced allocations and associated locks.
void PhaseMacroExpand::eliminate_macro_nodes() {
if (C->macro_count() == 0)
return false;
return;
// First, attempt to eliminate locks
int cnt = C->macro_count();
for (int i=0; i < cnt; i++) {
@ -2189,14 +2189,6 @@ bool PhaseMacroExpand::expand_macro_nodes() {
debug_only(int old_macro_count = C->macro_count(););
if (n->is_AbstractLock()) {
success = eliminate_locking_node(n->as_AbstractLock());
} else if (n->Opcode() == Op_LoopLimit) {
// Remove it from macro list and put on IGVN worklist to optimize.
C->remove_macro_node(n);
_igvn._worklist.push(n);
success = true;
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
_igvn.replace_node(n, n->in(1));
success = true;
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
@ -2220,18 +2212,50 @@ bool PhaseMacroExpand::expand_macro_nodes() {
assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
break;
default:
assert(false, "unknown node type in macro list");
assert(n->Opcode() == Op_LoopLimit ||
n->Opcode() == Op_Opaque1 ||
n->Opcode() == Op_Opaque2, "unknown node type in macro list");
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
}
}
}
//------------------------------expand_macro_nodes----------------------
// Returns true if a failure occurred.
bool PhaseMacroExpand::expand_macro_nodes() {
// Last attempt to eliminate macro nodes.
eliminate_macro_nodes();
// Make sure expansion will not cause node limit to be exceeded.
// Worst case is a macro node gets expanded into about 50 nodes.
// Allow 50% more for optimization.
if (C->check_node_count(C->macro_count() * 75, "out of nodes before macro expansion" ) )
return true;
// Eliminate Opaque and LoopLimit nodes. Do it after all loop optimizations.
bool progress = true;
while (progress) {
progress = false;
for (int i = C->macro_count(); i > 0; i--) {
Node * n = C->macro_node(i-1);
bool success = false;
debug_only(int old_macro_count = C->macro_count(););
if (n->Opcode() == Op_LoopLimit) {
// Remove it from macro list and put on IGVN worklist to optimize.
C->remove_macro_node(n);
_igvn._worklist.push(n);
success = true;
} else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
_igvn.replace_node(n, n->in(1));
success = true;
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
}
}
// expand "macro" nodes
// nodes are removed from the macro list as they are processed
while (C->macro_count() > 0) {
@ -2265,5 +2289,6 @@ bool PhaseMacroExpand::expand_macro_nodes() {
_igvn.set_delay_transform(false);
_igvn.optimize();
if (C->failing()) return true;
return false;
}

View File

@ -119,6 +119,7 @@ public:
PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) {
_igvn.set_delay_transform(true);
}
void eliminate_macro_nodes();
bool expand_macro_nodes();
};

View File

@ -294,7 +294,6 @@ public:
RegMask _return_value_mask;
// Inline Cache Register
static OptoReg::Name inline_cache_reg();
static const RegMask &inline_cache_reg_mask();
static int inline_cache_reg_encode();
// Register for DIVI projection of divmodI
@ -324,7 +323,6 @@ public:
// and then expanded into the inline_cache_reg and a method_oop register
static OptoReg::Name interpreter_method_oop_reg();
static const RegMask &interpreter_method_oop_reg_mask();
static int interpreter_method_oop_reg_encode();
static OptoReg::Name compiler_method_oop_reg();
@ -333,7 +331,6 @@ public:
// Interpreter's Frame Pointer Register
static OptoReg::Name interpreter_frame_pointer_reg();
static const RegMask &interpreter_frame_pointer_reg_mask();
// Java-Native calling convention
// (what you use when intercalling between Java and C++ code)
@ -371,10 +368,6 @@ public:
// registers? True for Intel but false for most RISCs
static const bool clone_shift_expressions;
// Should constant table entries be accessed with loads using
// absolute addressing? True for x86 but false for most RISCs.
static const bool constant_table_absolute_addressing;
static bool narrow_oop_use_complex_address();
// Generate implicit null check for narrow oops if it can fold

View File

@ -265,6 +265,13 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
if( phase->type( mem ) == Type::TOP ) return NodeSentinel; // caller will return NULL
assert( mem != this, "dead loop in MemNode::Ideal" );
if (can_reshape && igvn != NULL && igvn->_worklist.member(mem)) {
// This memory slice may be dead.
// Delay this mem node transformation until the memory is processed.
phase->is_IterGVN()->_worklist.push(this);
return NodeSentinel; // caller will return NULL
}
Node *address = in(MemNode::Address);
const Type *t_adr = phase->type( address );
if( t_adr == Type::TOP ) return NodeSentinel; // caller will return NULL
@ -2661,6 +2668,8 @@ uint StrIntrinsicNode::match_edge(uint idx) const {
// control copies
Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
if (can_reshape) {
Node* mem = phase->transform(in(MemNode::Memory));
@ -2675,6 +2684,12 @@ Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return NULL;
}
//------------------------------Value------------------------------------------
const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const {
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
return bottom_type();
}
//=============================================================================
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
: MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)),
@ -2715,6 +2730,8 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) {
// control copies
Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
if (remove_dead_region(phase, can_reshape)) return this;
// Don't bother trying to transform a dead node
if (in(0) && in(0)->is_top()) return NULL;
// Eliminate volatile MemBars for scalar replaced objects.
if (can_reshape && req() == (Precedent+1) &&

View File

@ -800,6 +800,7 @@ public:
virtual uint match_edge(uint idx) const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
virtual const Type *Value(PhaseTransform *phase) const;
};
//------------------------------StrComp-------------------------------------

View File

@ -641,7 +641,8 @@ public:
Flag_is_dead_loop_safe = Flag_is_cisc_alternate << 1,
Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1,
Flag_avoid_back_to_back = Flag_may_be_short_branch << 1,
_max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination
Flag_has_call = Flag_avoid_back_to_back << 1,
_max_flags = (Flag_has_call << 1) - 1 // allow flags combination
};
private:

View File

@ -890,7 +890,7 @@ class CommandLineFlags {
diagnostic(bool, TraceNMethodInstalls, false, \
"Trace nmethod intallation") \
\
diagnostic(intx, ScavengeRootsInCode, 1, \
diagnostic(intx, ScavengeRootsInCode, 2, \
"0: do not allow scavengable oops in the code cache; " \
"1: allow scavenging from the code cache; " \
"2: emit as many constants as the compiler can see") \

View File

@ -30,6 +30,27 @@
#include "runtime/simpleThresholdPolicy.inline.hpp"
#include "code/scopeDesc.hpp"
void SimpleThresholdPolicy::print_counters(const char* prefix, methodHandle mh) {
int invocation_count = mh->invocation_count();
int backedge_count = mh->backedge_count();
methodDataHandle mdh = mh->method_data();
int mdo_invocations = 0, mdo_backedges = 0;
int mdo_invocations_start = 0, mdo_backedges_start = 0;
if (mdh() != NULL) {
mdo_invocations = mdh->invocation_count();
mdo_backedges = mdh->backedge_count();
mdo_invocations_start = mdh->invocation_count_start();
mdo_backedges_start = mdh->backedge_count_start();
}
tty->print(" %stotal: %d,%d %smdo: %d(%d),%d(%d)", prefix,
invocation_count, backedge_count, prefix,
mdo_invocations, mdo_invocations_start,
mdo_backedges, mdo_backedges_start);
tty->print(" %smax levels: %d,%d", prefix,
mh->highest_comp_level(), mh->highest_osr_comp_level());
}
// Print an event.
void SimpleThresholdPolicy::print_event(EventType type, methodHandle mh, methodHandle imh,
int bci, CompLevel level) {
@ -38,8 +59,6 @@ void SimpleThresholdPolicy::print_event(EventType type, methodHandle mh, methodH
ttyLocker tty_lock;
tty->print("%lf: [", os::elapsedTime());
int invocation_count = mh->invocation_count();
int backedge_count = mh->backedge_count();
switch(type) {
case CALL:
tty->print("call");
@ -82,23 +101,9 @@ void SimpleThresholdPolicy::print_event(EventType type, methodHandle mh, methodH
print_specific(type, mh, imh, bci, level);
if (type != COMPILE) {
methodDataHandle mdh = mh->method_data();
int mdo_invocations = 0, mdo_backedges = 0;
int mdo_invocations_start = 0, mdo_backedges_start = 0;
if (mdh() != NULL) {
mdo_invocations = mdh->invocation_count();
mdo_backedges = mdh->backedge_count();
mdo_invocations_start = mdh->invocation_count_start();
mdo_backedges_start = mdh->backedge_count_start();
}
tty->print(" total: %d,%d mdo: %d(%d),%d(%d)",
invocation_count, backedge_count,
mdo_invocations, mdo_invocations_start,
mdo_backedges, mdo_backedges_start);
tty->print(" max levels: %d,%d",
mh->highest_comp_level(), mh->highest_osr_comp_level());
print_counters("", mh);
if (inlinee_event) {
tty->print(" inlinee max levels: %d,%d", imh->highest_comp_level(), imh->highest_osr_comp_level());
print_counters("inlinee ", imh);
}
tty->print(" compilable: ");
bool need_comma = false;

View File

@ -55,7 +55,7 @@ class SimpleThresholdPolicy : public CompilationPolicy {
// loop_event checks if a method should be OSR compiled at a different
// level.
CompLevel loop_event(methodOop method, CompLevel cur_level);
void print_counters(const char* prefix, methodHandle mh);
protected:
int c1_count() const { return _c1_count; }
int c2_count() const { return _c2_count; }

View File

@ -27,7 +27,7 @@
* @bug 6792161
* @summary assert("No dead instructions after post-alloc")
*
* @run main/othervm -Xcomp -XX:MaxInlineSize=120 Test6792161
* @run main/othervm/timeout=300 -Xcomp -XX:MaxInlineSize=120 Test6792161
*/
import java.lang.reflect.Constructor;

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/**
* @test
* @bug 7110586
* @summary C2 generates icorrect results
*
* @run main/othervm -Xbatch Test7110586
*/
public class Test7110586 {
static int test1() {
int i = 0;
for ( ; i < 11; i+=1) {}
return i;
}
static int test2() {
int i = 0;
for ( ; i < 11; i+=2) {}
return i;
}
static int test3() {
int i = 0;
for ( ; i < 11; i+=3) {}
return i;
}
static int test11() {
int i = 0;
for ( ; i < 11; i+=11) {}
return i;
}
static int testm1() {
int i = 0;
for ( ; i > -11; i-=1) {}
return i;
}
static int testm2() {
int i = 0;
for ( ; i > -11; i-=2) {}
return i;
}
static int testm3() {
int i = 0;
for ( ; i > -11; i-=3) {}
return i;
}
static int testm11() {
int i = 0;
for ( ; i > -11; i-=11) {}
return i;
}
public static void main(String args[]) {
int x1 = 0;
int x2 = 0;
int x3 = 0;
int x11 = 0;
int m1 = 0;
int m2 = 0;
int m3 = 0;
int m11 = 0;
for (int i=0; i<10000; i++) {
x1 = test1();
x2 = test2();
x3 = test3();
x11 = test11();
m1 = testm1();
m2 = testm2();
m3 = testm3();
m11 = testm11();
}
boolean failed = false;
if (x1 != 11) {
System.out.println("ERROR (incr = +1): " + x1 + " != 11");
failed = true;
}
if (x2 != 12) {
System.out.println("ERROR (incr = +2): " + x2 + " != 12");
failed = true;
}
if (x3 != 12) {
System.out.println("ERROR (incr = +3): " + x3 + " != 12");
failed = true;
}
if (x11 != 11) {
System.out.println("ERROR (incr = +11): " + x11 + " != 11");
failed = true;
}
if (m1 != -11) {
System.out.println("ERROR (incr = -1): " + m1 + " != -11");
failed = true;
}
if (m2 != -12) {
System.out.println("ERROR (incr = -2): " + m2 + " != -12");
failed = true;
}
if (m3 != -12) {
System.out.println("ERROR (incr = -3): " + m3 + " != -12");
failed = true;
}
if (m11 != -11) {
System.out.println("ERROR (incr = -11): " + m11 + " != -11");
failed = true;
}
if (failed) {
System.exit(97);
}
}
}