This commit is contained in:
Erik Trimble 2009-03-12 18:16:36 -07:00
commit 8d6035660e
223 changed files with 5079 additions and 2219 deletions

View File

@ -61,8 +61,8 @@ CPPFLAGS = $(SYSDEFS) $(INCLUDES)
CPPFLAGS += -DASSERT
# CFLAGS_WARN holds compiler options to suppress/enable warnings.
# Suppress warnings (for now)
CFLAGS_WARN = -w
# Compiler warnings are treated as errors
CFLAGS_WARN = -Werror
CFLAGS += $(CFLAGS_WARN)
OBJECTNAMES = \

View File

@ -67,6 +67,8 @@ ifndef USE_GCC
endif
# CFLAGS_WARN holds compiler options to suppress/enable warnings.
# Compiler warnings are treated as errors
CFLAGS_WARN = +w -errwarn
CFLAGS += $(CFLAGS_WARN)
ifeq ("${Platform_compiler}", "sparcWorks")

View File

@ -2615,6 +2615,158 @@ void MacroAssembler::cas_under_lock(Register top_ptr_reg, Register top_reg, Regi
}
}
RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
Register tmp,
int offset) {
intptr_t value = *delayed_value_addr;
if (value != 0)
return RegisterConstant(value + offset);
// load indirectly to solve generation ordering problem
Address a(tmp, (address) delayed_value_addr);
load_ptr_contents(a, tmp);
#ifdef ASSERT
tst(tmp);
breakpoint_trap(zero, xcc);
#endif
if (offset != 0)
add(tmp, offset, tmp);
return RegisterConstant(tmp);
}
void MacroAssembler::regcon_inc_ptr( RegisterConstant& dest, RegisterConstant src, Register temp ) {
assert(dest.register_or_noreg() != G0, "lost side effect");
if ((src.is_constant() && src.as_constant() == 0) ||
(src.is_register() && src.as_register() == G0)) {
// do nothing
} else if (dest.is_register()) {
add(dest.as_register(), ensure_rs2(src, temp), dest.as_register());
} else if (src.is_constant()) {
intptr_t res = dest.as_constant() + src.as_constant();
dest = RegisterConstant(res); // side effect seen by caller
} else {
assert(temp != noreg, "cannot handle constant += register");
add(src.as_register(), ensure_rs2(dest, temp), temp);
dest = RegisterConstant(temp); // side effect seen by caller
}
}
void MacroAssembler::regcon_sll_ptr( RegisterConstant& dest, RegisterConstant src, Register temp ) {
assert(dest.register_or_noreg() != G0, "lost side effect");
if (!is_simm13(src.constant_or_zero()))
src = (src.as_constant() & 0xFF);
if ((src.is_constant() && src.as_constant() == 0) ||
(src.is_register() && src.as_register() == G0)) {
// do nothing
} else if (dest.is_register()) {
sll_ptr(dest.as_register(), src, dest.as_register());
} else if (src.is_constant()) {
intptr_t res = dest.as_constant() << src.as_constant();
dest = RegisterConstant(res); // side effect seen by caller
} else {
assert(temp != noreg, "cannot handle constant <<= register");
set(dest.as_constant(), temp);
sll_ptr(temp, src, temp);
dest = RegisterConstant(temp); // side effect seen by caller
}
}
// Look up the method for a megamorphic invokeinterface call.
// The target method is determined by <intf_klass, itable_index>.
// The receiver klass is in recv_klass.
// On success, the result will be in method_result, and execution falls through.
// On failure, execution transfers to the given label.
void MacroAssembler::lookup_interface_method(Register recv_klass,
Register intf_klass,
RegisterConstant itable_index,
Register method_result,
Register scan_temp,
Register sethi_temp,
Label& L_no_such_interface) {
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
"caller must use same register for non-constant itable index as for method");
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
int vtable_base = instanceKlass::vtable_start_offset() * wordSize;
int scan_step = itableOffsetEntry::size() * wordSize;
int vte_size = vtableEntry::size() * wordSize;
lduw(recv_klass, instanceKlass::vtable_length_offset() * wordSize, scan_temp);
// %%% We should store the aligned, prescaled offset in the klassoop.
// Then the next several instructions would fold away.
int round_to_unit = ((HeapWordsPerLong > 1) ? BytesPerLong : 0);
int itb_offset = vtable_base;
if (round_to_unit != 0) {
// hoist first instruction of round_to(scan_temp, BytesPerLong):
itb_offset += round_to_unit - wordSize;
}
int itb_scale = exact_log2(vtableEntry::size() * wordSize);
sll(scan_temp, itb_scale, scan_temp);
add(scan_temp, itb_offset, scan_temp);
if (round_to_unit != 0) {
// Round up to align_object_offset boundary
// see code for instanceKlass::start_of_itable!
// Was: round_to(scan_temp, BytesPerLong);
// Hoisted: add(scan_temp, BytesPerLong-1, scan_temp);
and3(scan_temp, -round_to_unit, scan_temp);
}
add(recv_klass, scan_temp, scan_temp);
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
RegisterConstant itable_offset = itable_index;
regcon_sll_ptr(itable_offset, exact_log2(itableMethodEntry::size() * wordSize));
regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes());
add(recv_klass, ensure_rs2(itable_offset, sethi_temp), recv_klass);
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
// if (scan->interface() == intf) {
// result = (klass + scan->offset() + itable_index);
// }
// }
Label search, found_method;
for (int peel = 1; peel >= 0; peel--) {
// %%%% Could load both offset and interface in one ldx, if they were
// in the opposite order. This would save a load.
ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result);
// Check that this entry is non-null. A null entry means that
// the receiver class doesn't implement the interface, and wasn't the
// same as when the caller was compiled.
bpr(Assembler::rc_z, false, Assembler::pn, method_result, L_no_such_interface);
delayed()->cmp(method_result, intf_klass);
if (peel) {
brx(Assembler::equal, false, Assembler::pt, found_method);
} else {
brx(Assembler::notEqual, false, Assembler::pn, search);
// (invert the test to fall through to found_method...)
}
delayed()->add(scan_temp, scan_step, scan_temp);
if (!peel) break;
bind(search);
}
bind(found_method);
// Got a hit.
int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
// scan_temp[-scan_step] points to the vtable offset we need
ito_offset -= scan_step;
lduw(scan_temp, ito_offset, scan_temp);
ld_ptr(recv_klass, scan_temp, method_result);
}
void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
Register temp_reg,
Label& done, Label* slow_case,
@ -4057,6 +4209,24 @@ void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_v
card_table_write(bs->byte_map_base, tmp, store_addr);
}
// Loading values by size and signed-ness
void MacroAssembler::load_sized_value(Register s1, RegisterConstant s2, Register d,
int size_in_bytes, bool is_signed) {
switch (size_in_bytes ^ (is_signed ? -1 : 0)) {
case ~8: // fall through:
case 8: ld_long( s1, s2, d ); break;
case ~4: ldsw( s1, s2, d ); break;
case 4: lduw( s1, s2, d ); break;
case ~2: ldsh( s1, s2, d ); break;
case 2: lduh( s1, s2, d ); break;
case ~1: ldsb( s1, s2, d ); break;
case 1: ldub( s1, s2, d ); break;
default: ShouldNotReachHere();
}
}
void MacroAssembler::load_klass(Register src_oop, Register klass) {
// The number of bytes in this code is used by
// MachCallDynamicJavaNode::ret_addr_offset()

View File

@ -384,6 +384,12 @@ class Address VALUE_OBJ_CLASS_SPEC {
inline bool is_simm13(int offset = 0); // check disp+offset for overflow
Address plus_disp(int disp) const { // bump disp by a small amount
Address a = (*this);
a._disp += disp;
return a;
}
Address split_disp() const { // deal with disp overflow
Address a = (*this);
int hi_disp = _disp & ~0x3ff;
@ -1082,6 +1088,7 @@ public:
inline void add( Register s1, Register s2, Register d );
inline void add( Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none);
inline void add( Register s1, int simm13a, Register d, RelocationHolder const& rspec);
inline void add( Register s1, RegisterConstant s2, Register d, int offset = 0);
inline void add( const Address& a, Register d, int offset = 0);
void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
@ -1298,6 +1305,16 @@ public:
inline void ld( const Address& a, Register d, int offset = 0 );
inline void ldd( const Address& a, Register d, int offset = 0 );
inline void ldub( Register s1, RegisterConstant s2, Register d );
inline void ldsb( Register s1, RegisterConstant s2, Register d );
inline void lduh( Register s1, RegisterConstant s2, Register d );
inline void ldsh( Register s1, RegisterConstant s2, Register d );
inline void lduw( Register s1, RegisterConstant s2, Register d );
inline void ldsw( Register s1, RegisterConstant s2, Register d );
inline void ldx( Register s1, RegisterConstant s2, Register d );
inline void ld( Register s1, RegisterConstant s2, Register d );
inline void ldd( Register s1, RegisterConstant s2, Register d );
// pp 177
void ldsba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
@ -1518,6 +1535,13 @@ public:
inline void st( Register d, const Address& a, int offset = 0 );
inline void std( Register d, const Address& a, int offset = 0 );
inline void stb( Register d, Register s1, RegisterConstant s2 );
inline void sth( Register d, Register s1, RegisterConstant s2 );
inline void stw( Register d, Register s1, RegisterConstant s2 );
inline void stx( Register d, Register s1, RegisterConstant s2 );
inline void std( Register d, Register s1, RegisterConstant s2 );
inline void st( Register d, Register s1, RegisterConstant s2 );
// pp 177
void stba( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
@ -1835,6 +1859,7 @@ class MacroAssembler: public Assembler {
// Functions for isolating 64 bit shifts for LP64
inline void sll_ptr( Register s1, Register s2, Register d );
inline void sll_ptr( Register s1, int imm6a, Register d );
inline void sll_ptr( Register s1, RegisterConstant s2, Register d );
inline void srl_ptr( Register s1, Register s2, Register d );
inline void srl_ptr( Register s1, int imm6a, Register d );
@ -1940,20 +1965,47 @@ class MacroAssembler: public Assembler {
// st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's
inline void ld_ptr( Register s1, Register s2, Register d );
inline void ld_ptr( Register s1, int simm13a, Register d);
inline void ld_ptr( Register s1, RegisterConstant s2, Register d );
inline void ld_ptr( const Address& a, Register d, int offset = 0 );
inline void st_ptr( Register d, Register s1, Register s2 );
inline void st_ptr( Register d, Register s1, int simm13a);
inline void st_ptr( Register d, Register s1, RegisterConstant s2 );
inline void st_ptr( Register d, const Address& a, int offset = 0 );
// ld_long will perform ld for 32 bit VM's and ldx for 64 bit VM's
// st_long will perform st for 32 bit VM's and stx for 64 bit VM's
inline void ld_long( Register s1, Register s2, Register d );
inline void ld_long( Register s1, int simm13a, Register d );
inline void ld_long( Register s1, RegisterConstant s2, Register d );
inline void ld_long( const Address& a, Register d, int offset = 0 );
inline void st_long( Register d, Register s1, Register s2 );
inline void st_long( Register d, Register s1, int simm13a );
inline void st_long( Register d, Register s1, RegisterConstant s2 );
inline void st_long( Register d, const Address& a, int offset = 0 );
// Loading values by size and signed-ness
void load_sized_value(Register s1, RegisterConstant s2, Register d,
int size_in_bytes, bool is_signed);
// Helpers for address formation.
// They update the dest in place, whether it is a register or constant.
// They emit no code at all if src is a constant zero.
// If dest is a constant and src is a register, the temp argument
// is required, and becomes the result.
// If dest is a register and src is a non-simm13 constant,
// the temp argument is required, and is used to materialize the constant.
void regcon_inc_ptr( RegisterConstant& dest, RegisterConstant src,
Register temp = noreg );
void regcon_sll_ptr( RegisterConstant& dest, RegisterConstant src,
Register temp = noreg );
RegisterConstant ensure_rs2(RegisterConstant rs2, Register sethi_temp) {
guarantee(sethi_temp != noreg, "constant offset overflow");
if (is_simm13(rs2.constant_or_zero()))
return rs2; // register or short constant
set(rs2.as_constant(), sethi_temp);
return sethi_temp;
}
// --------------------------------------------------
public:
@ -2267,6 +2319,14 @@ class MacroAssembler: public Assembler {
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
// interface method calling
void lookup_interface_method(Register recv_klass,
Register intf_klass,
RegisterConstant itable_index,
Register method_result,
Register temp_reg, Register temp2_reg,
Label& no_such_interface);
// Stack overflow checking
// Note: this clobbers G3_scratch
@ -2281,6 +2341,8 @@ class MacroAssembler: public Assembler {
// stack overflow + shadow pages. Clobbers tsp and scratch registers.
void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch);
virtual RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp, int offset);
void verify_tlab();
Condition negate_condition(Condition cond);

View File

@ -143,6 +143,49 @@ inline void Assembler::ld( Register s1, Register s2, Register d) { lduw( s1, s2
inline void Assembler::ld( Register s1, int simm13a, Register d) { lduw( s1, simm13a, d); }
#endif
inline void Assembler::ldub( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldsb(s1, s2.as_register(), d);
else ldsb(s1, s2.as_constant(), d);
}
inline void Assembler::ldsb( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldsb(s1, s2.as_register(), d);
else ldsb(s1, s2.as_constant(), d);
}
inline void Assembler::lduh( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldsh(s1, s2.as_register(), d);
else ldsh(s1, s2.as_constant(), d);
}
inline void Assembler::ldsh( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldsh(s1, s2.as_register(), d);
else ldsh(s1, s2.as_constant(), d);
}
inline void Assembler::lduw( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldsw(s1, s2.as_register(), d);
else ldsw(s1, s2.as_constant(), d);
}
inline void Assembler::ldsw( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldsw(s1, s2.as_register(), d);
else ldsw(s1, s2.as_constant(), d);
}
inline void Assembler::ldx( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldx(s1, s2.as_register(), d);
else ldx(s1, s2.as_constant(), d);
}
inline void Assembler::ld( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ld(s1, s2.as_register(), d);
else ld(s1, s2.as_constant(), d);
}
inline void Assembler::ldd( Register s1, RegisterConstant s2, Register d) {
if (s2.is_register()) ldd(s1, s2.as_register(), d);
else ldd(s1, s2.as_constant(), d);
}
// form effective addresses this way:
inline void Assembler::add( Register s1, RegisterConstant s2, Register d, int offset) {
if (s2.is_register()) add(s1, s2.as_register(), d);
else { add(s1, s2.as_constant() + offset, d); offset = 0; }
if (offset != 0) add(d, offset, d);
}
inline void Assembler::ld( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); ld( a.base(), a.disp() + offset, d ); }
inline void Assembler::ldsb( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); ldsb( a.base(), a.disp() + offset, d ); }
@ -200,6 +243,27 @@ inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); a
inline void Assembler::st( Register d, Register s1, Register s2) { stw(d, s1, s2); }
inline void Assembler::st( Register d, Register s1, int simm13a) { stw(d, s1, simm13a); }
inline void Assembler::stb( Register d, Register s1, RegisterConstant s2) {
if (s2.is_register()) stb(d, s1, s2.as_register());
else stb(d, s1, s2.as_constant());
}
inline void Assembler::sth( Register d, Register s1, RegisterConstant s2) {
if (s2.is_register()) sth(d, s1, s2.as_register());
else sth(d, s1, s2.as_constant());
}
inline void Assembler::stx( Register d, Register s1, RegisterConstant s2) {
if (s2.is_register()) stx(d, s1, s2.as_register());
else stx(d, s1, s2.as_constant());
}
inline void Assembler::std( Register d, Register s1, RegisterConstant s2) {
if (s2.is_register()) std(d, s1, s2.as_register());
else std(d, s1, s2.as_constant());
}
inline void Assembler::st( Register d, Register s1, RegisterConstant s2) {
if (s2.is_register()) st(d, s1, s2.as_register());
else st(d, s1, s2.as_constant());
}
inline void Assembler::stb( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stb( d, a.base(), a.disp() + offset); }
inline void Assembler::sth( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); sth( d, a.base(), a.disp() + offset); }
inline void Assembler::stw( Register d, const Address& a, int offset) { relocate(a.rspec(offset)); stw( d, a.base(), a.disp() + offset); }
@ -244,6 +308,14 @@ inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) {
#endif
}
inline void MacroAssembler::ld_ptr( Register s1, RegisterConstant s2, Register d ) {
#ifdef _LP64
Assembler::ldx( s1, s2, d);
#else
Assembler::ld( s1, s2, d);
#endif
}
inline void MacroAssembler::ld_ptr( const Address& a, Register d, int offset ) {
#ifdef _LP64
Assembler::ldx( a, d, offset );
@ -268,6 +340,14 @@ inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) {
#endif
}
inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterConstant s2 ) {
#ifdef _LP64
Assembler::stx( d, s1, s2);
#else
Assembler::st( d, s1, s2);
#endif
}
inline void MacroAssembler::st_ptr( Register d, const Address& a, int offset) {
#ifdef _LP64
Assembler::stx( d, a, offset);
@ -293,6 +373,14 @@ inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) {
#endif
}
inline void MacroAssembler::ld_long( Register s1, RegisterConstant s2, Register d ) {
#ifdef _LP64
Assembler::ldx(s1, s2, d);
#else
Assembler::ldd(s1, s2, d);
#endif
}
inline void MacroAssembler::ld_long( const Address& a, Register d, int offset ) {
#ifdef _LP64
Assembler::ldx(a, d, offset );
@ -317,6 +405,14 @@ inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) {
#endif
}
inline void MacroAssembler::st_long( Register d, Register s1, RegisterConstant s2 ) {
#ifdef _LP64
Assembler::stx(d, s1, s2);
#else
Assembler::std(d, s1, s2);
#endif
}
inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) {
#ifdef _LP64
Assembler::stx(d, a, offset);
@ -359,6 +455,11 @@ inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) {
#endif
}
inline void MacroAssembler::sll_ptr( Register s1, RegisterConstant s2, Register d ) {
if (s2.is_register()) sll_ptr(s1, s2.as_register(), d);
else sll_ptr(s1, s2.as_constant(), d);
}
// Use the right branch for the platform
inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {

View File

@ -2465,7 +2465,10 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
// InterpreterRuntime::post_method_entry();
// }
// if (DTraceMethodProbes) {
// SharedRuntime::dtrace_method_entry(method, reciever);
// SharedRuntime::dtrace_method_entry(method, receiver);
// }
// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
// SharedRuntime::rc_trace_method_entry(method, receiver);
// }
void InterpreterMacroAssembler::notify_method_entry() {
@ -2497,6 +2500,13 @@ void InterpreterMacroAssembler::notify_method_entry() {
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry),
G2_thread, Lmethod);
}
// RedefineClasses() tracing support for obsolete method entry
if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
call_VM_leaf(noreg,
CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
G2_thread, Lmethod);
}
}

View File

@ -243,7 +243,7 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
// Regenerate the instruction sequence that performs the 64 bit
// sethi. This only does the sethi. The disp field (bottom 10 bits)
// must be handled seperately.
// must be handled separately.
static void set_data64_sethi(address instaddr, intptr_t x);
// combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st)

View File

@ -2161,6 +2161,18 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ restore();
}
// RedefineClasses() tracing support for obsolete method entry
if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
// create inner frame
__ save_frame(0);
__ mov(G2_thread, L7_thread_cache);
__ set_oop_constant(JNIHandles::make_local(method()), O1);
__ call_VM_leaf(L7_thread_cache,
CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
G2_thread, O1);
__ restore();
}
// We are in the jni frame unless saved_frame is true in which case
// we are in one frame deeper (the "inner" frame). If we are in the
// "inner" frames the args are in the Iregs and if the jni frame then

View File

@ -189,7 +189,7 @@ reg_def R_F31( SOC, SOC, Op_RegF, 31, F31->as_VMReg());
// double fp register numbers. FloatRegisterImpl in register_sparc.hpp
// wants 0-63, so we have to convert every time we want to use fp regs
// with the macroassembler, using reg_to_DoubleFloatRegister_object().
// 255 is a flag meaning 'dont go here'.
// 255 is a flag meaning "don't go here".
// I believe we can't handle callee-save doubles D32 and up until
// the place in the sparc stack crawler that asserts on the 255 is
// fixed up.
@ -462,7 +462,7 @@ extern bool can_branch_register( Node *bol, Node *cmp );
// Macros to extract hi & lo halves from a long pair.
// G0 is not part of any long pair, so assert on that.
// Prevents accidently using G1 instead of G0.
// Prevents accidentally using G1 instead of G0.
#define LONG_HI_REG(x) (x)
#define LONG_LO_REG(x) (x)
@ -1431,7 +1431,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
#ifndef _LP64
// In the LP64 build, all registers can be moved as aligned/adjacent
// pairs, so there's never any need to move the high bits seperately.
// pairs, so there's never any need to move the high bits separately.
// The 32-bit builds have to deal with the 32-bit ABI which can force
// all sorts of silly alignment problems.
@ -1624,7 +1624,7 @@ void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
Register temp_reg = G3;
assert( G5_ic_reg != temp_reg, "conflicting registers" );
// Load klass from reciever
// Load klass from receiver
__ load_klass(O0, temp_reg);
// Compare against expected klass
__ cmp(temp_reg, G5_ic_reg);
@ -4149,7 +4149,7 @@ operand cmpOp_commute() %{
//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used to simplify
// instruction definitions by not requiring the AD writer to specify seperate
// instruction definitions by not requiring the AD writer to specify separate
// instructions for every form of operand when the instruction accepts
// multiple operand types with the same basic encoding and format. The classic
// case of this is memory operands.
@ -5286,55 +5286,91 @@ instruct loadB(iRegI dst, memory mem) %{
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDSB $mem,$dst" %}
format %{ "LDSB $mem,$dst\t! byte" %}
opcode(Assembler::ldsb_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Byte (8bit UNsigned) into an int reg
instruct loadUB(iRegI dst, memory mem, immI_255 bytemask) %{
match(Set dst (AndI (LoadB mem) bytemask));
// Load Byte (8bit signed) into a Long Register
instruct loadB2L(iRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadB mem)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUB $mem,$dst" %}
format %{ "LDSB $mem,$dst\t! byte -> long" %}
opcode(Assembler::ldsb_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Byte (8bit UNsigned) into an int reg
instruct loadUB(iRegI dst, memory mem) %{
match(Set dst (LoadUB mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUB $mem,$dst\t! ubyte" %}
opcode(Assembler::ldub_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Byte (8bit UNsigned) into a Long Register
instruct loadUBL(iRegL dst, memory mem, immL_FF bytemask) %{
match(Set dst (AndL (ConvI2L (LoadB mem)) bytemask));
// Load Unsigned Byte (8bit UNsigned) into a Long Register
instruct loadUB2L(iRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadUB mem)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUB $mem,$dst" %}
format %{ "LDUB $mem,$dst\t! ubyte -> long" %}
opcode(Assembler::ldub_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
instruct loadUS2L(iRegL dst, memory mem, immL_FFFF bytemask) %{
match(Set dst (AndL (ConvI2L (LoadUS mem)) bytemask));
// Load Short (16bit signed)
instruct loadS(iRegI dst, memory mem) %{
match(Set dst (LoadS mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUH $mem,$dst" %}
opcode(Assembler::lduh_op3);
format %{ "LDSH $mem,$dst\t! short" %}
opcode(Assembler::ldsh_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Short/Char (16bit unsigned)
// Load Short (16bit signed) into a Long Register
instruct loadS2L(iRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadS mem)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDSH $mem,$dst\t! short -> long" %}
opcode(Assembler::ldsh_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned)
instruct loadUS(iRegI dst, memory mem) %{
match(Set dst (LoadUS mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUH $mem,$dst" %}
format %{ "LDUH $mem,$dst\t! ushort/char" %}
opcode(Assembler::lduh_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Unsigned Short/Char (16bit UNsigned) into a Long Register
instruct loadUS2L(iRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadUS mem)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUH $mem,$dst\t! ushort/char -> long" %}
opcode(Assembler::lduh_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
@ -5344,9 +5380,33 @@ instruct loadUS(iRegI dst, memory mem) %{
instruct loadI(iRegI dst, memory mem) %{
match(Set dst (LoadI mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUW $mem,$dst" %}
size(4);
format %{ "LDUW $mem,$dst\t! int" %}
opcode(Assembler::lduw_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mem);
%}
// Load Integer into a Long Register
instruct loadI2L(iRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadI mem)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDSW $mem,$dst\t! int -> long" %}
opcode(Assembler::ldsw_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mem);
%}
// Load Unsigned Integer into a Long Register
instruct loadUI2L(iRegL dst, memory mem) %{
match(Set dst (LoadUI2L mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDUW $mem,$dst\t! uint -> long" %}
opcode(Assembler::lduw_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mem);
@ -5356,6 +5416,7 @@ instruct loadI(iRegI dst, memory mem) %{
instruct loadL(iRegL dst, memory mem ) %{
match(Set dst (LoadL mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDX $mem,$dst\t! long" %}
opcode(Assembler::ldx_op3);
@ -5471,13 +5532,11 @@ instruct loadN(iRegN dst, memory mem) %{
format %{ "LDUW $mem,$dst\t! compressed ptr" %}
ins_encode %{
Register base = as_Register($mem$$base);
Register index = as_Register($mem$$index);
Register dst = $dst$$Register;
Register index = $mem$$index$$Register;
if (index != G0) {
__ lduw(base, index, dst);
__ lduw($mem$$base$$Register, index, $dst$$Register);
} else {
__ lduw(base, $mem$$disp, dst);
__ lduw($mem$$base$$Register, $mem$$disp, $dst$$Register);
}
%}
ins_pipe(iload_mem);
@ -5521,18 +5580,6 @@ instruct loadNKlass(iRegN dst, memory mem) %{
ins_pipe(iload_mem);
%}
// Load Short (16bit signed)
instruct loadS(iRegI dst, memory mem) %{
match(Set dst (LoadS mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDSH $mem,$dst" %}
opcode(Assembler::ldsh_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(iload_mask_mem);
%}
// Load Double
instruct loadD(regD dst, memory mem) %{
match(Set dst (LoadD mem));
@ -6847,7 +6894,7 @@ instruct mul_hi(iRegIsafe dst, iRegIsafe src1, iRegIsafe src2 ) %{
ins_pipe(sdiv_reg_reg);
%}
// Magic constant, reciprical of 10
// Magic constant, reciprocal of 10
instruct loadConI_x66666667(iRegIsafe dst) %{
effect( DEF dst );
@ -6857,7 +6904,7 @@ instruct loadConI_x66666667(iRegIsafe dst) %{
ins_pipe(ialu_hi_lo_reg);
%}
// Register Shift Right Arithmatic Long by 32-63
// Register Shift Right Arithmetic Long by 32-63
instruct sra_31( iRegI dst, iRegI src ) %{
effect( DEF dst, USE src );
format %{ "SRA $src,31,$dst\t! Used in div-by-10" %}
@ -9048,7 +9095,7 @@ instruct storeL_reversed(memory dst, iRegL src) %{
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.
//
// peepmatch ( root_instr_name [preceeding_instruction]* );
// peepmatch ( root_instr_name [preceding_instruction]* );
//
// peepconstraint %{
// (instruction_number.operand_name relational_op instruction_number.operand_name

View File

@ -1545,7 +1545,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
// Handle all the JSR stuff here, then exit.
// It's much shorter and cleaner than intermingling with the
// non-JSR normal-branch stuff occuring below.
// non-JSR normal-branch stuff occurring below.
if( is_jsr ) {
// compute return address as bci in Otos_i
__ ld_ptr(Address(Lmethod, 0, in_bytes(methodOopDesc::const_offset())), G3_scratch);
@ -3079,7 +3079,7 @@ void TemplateTable::invokeinterface(int byte_no) {
Label ok;
// Check that entry is non-null. Null entries are probably a bytecode
// problem. If the interface isn't implemented by the reciever class,
// problem. If the interface isn't implemented by the receiver class,
// the VM should throw IncompatibleClassChangeError. linkResolver checks
// this too but that's only if the entry isn't already resolved, so we
// need to check again.

View File

@ -106,6 +106,15 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
__ delayed()->nop();
masm->flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
vtable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
@ -113,9 +122,9 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
// NOTE: %%%% if any change is made to this stub make sure that the function
// pd_code_size_limit is changed to ensure the correct size for VtableStub
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
const int sparc_code_length = VtableStub::pd_code_size_limit(false);
VtableStub* s = new(sparc_code_length) VtableStub(false, vtable_index);
VtableStub* s = new(sparc_code_length) VtableStub(false, itable_index);
ResourceMark rm;
CodeBuffer cb(s->entry_point(), sparc_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
@ -139,7 +148,6 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
// are passed in the %o registers. Instead, longs are passed in G1 and G4
// and so those registers are not available here.
__ save(SP,-frame::register_save_words*wordSize,SP);
Register I0_receiver = I0; // Location of receiver after save
#ifndef PRODUCT
if (CountCompiledCalls) {
@ -151,63 +159,31 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
}
#endif /* PRODUCT */
// load start of itable entries into L0 register
const int base = instanceKlass::vtable_start_offset() * wordSize;
__ ld(Address(G3_klassOop, 0, instanceKlass::vtable_length_offset() * wordSize), L0);
// %%% Could store the aligned, prescaled offset in the klassoop.
__ sll(L0, exact_log2(vtableEntry::size() * wordSize), L0);
// see code for instanceKlass::start_of_itable!
const int vtable_alignment = align_object_offset(1);
assert(vtable_alignment == 1 || vtable_alignment == 2, "");
const int odd_bit = vtableEntry::size() * wordSize;
if (vtable_alignment == 2) {
__ and3(L0, odd_bit, L1); // isolate the odd bit
}
__ add(G3_klassOop, L0, L0);
if (vtable_alignment == 2) {
__ add(L0, L1, L0); // double the odd bit, to align up
}
// Loop over all itable entries until desired interfaceOop (G5_interface) found
__ bind(search);
// %%%% Could load both offset and interface in one ldx, if they were
// in the opposite order. This would save a load.
__ ld_ptr(L0, base + itableOffsetEntry::interface_offset_in_bytes(), L1);
// If the entry is NULL then we've reached the end of the table
// without finding the expected interface, so throw an exception
Label throw_icce;
__ bpr(Assembler::rc_z, false, Assembler::pn, L1, throw_icce);
__ delayed()->cmp(G5_interface, L1);
__ brx(Assembler::notEqual, true, Assembler::pn, search);
__ delayed()->add(L0, itableOffsetEntry::size() * wordSize, L0);
// entry found and L0 points to it, move offset of vtable for interface into L0
__ ld(L0, base + itableOffsetEntry::offset_offset_in_bytes(), L0);
// Compute itableMethodEntry and get methodOop(G5_method) and entrypoint(L0) for compiler
const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
__ add(G3_klassOop, L0, L1);
__ ld_ptr(L1, method_offset, G5_method);
Register L5_method = L5;
__ lookup_interface_method(// inputs: rec. class, interface, itable index
G3_klassOop, G5_interface, itable_index,
// outputs: method, scan temp. reg
L5_method, L2, L3,
throw_icce);
#ifndef PRODUCT
if (DebugVtables) {
Label L01;
__ ld_ptr(L1, method_offset, G5_method);
__ bpr(Assembler::rc_nz, false, Assembler::pt, G5_method, L01);
__ bpr(Assembler::rc_nz, false, Assembler::pt, L5_method, L01);
__ delayed()->nop();
__ stop("methodOop is null");
__ bind(L01);
__ verify_oop(G5_method);
__ verify_oop(L5_method);
}
#endif
// If the following load is through a NULL pointer, we'll take an OS
// exception that should translate into an AbstractMethodError. We need the
// window count to be correct at that time.
__ restore(); // Restore registers BEFORE the AME point
__ restore(L5_method, 0, G5_method);
// Restore registers *before* the AME point.
address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract
__ ld_ptr(G5_method, in_bytes(methodOopDesc::from_compiled_offset()), G3_scratch);
@ -225,6 +201,12 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
masm->flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
itable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
@ -243,8 +225,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
(UseCompressedOops ? 2*BytesPerInstWord : 0);
return basic + slop;
} else {
// save, ld, ld, sll, and, add, add, ld, cmp, br, add, ld, add, ld, ld, jmp, restore, sethi, jmpl, restore
const int basic = (20 LP64_ONLY(+ 6)) * BytesPerInstWord +
const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord +
// shift;add for load_klass
(UseCompressedOops ? 2*BytesPerInstWord : 0);
return (basic + slop);

View File

@ -129,13 +129,19 @@ Address::Address(address loc, RelocationHolder spec) {
// Convert the raw encoding form into the form expected by the constructor for
// Address. An index of 4 (rsp) corresponds to having no index, so convert
// that to noreg for the Address constructor.
Address Address::make_raw(int base, int index, int scale, int disp) {
Address Address::make_raw(int base, int index, int scale, int disp, bool disp_is_oop) {
RelocationHolder rspec;
if (disp_is_oop) {
rspec = Relocation::spec_simple(relocInfo::oop_type);
}
bool valid_index = index != rsp->encoding();
if (valid_index) {
Address madr(as_Register(base), as_Register(index), (Address::ScaleFactor)scale, in_ByteSize(disp));
madr._rspec = rspec;
return madr;
} else {
Address madr(as_Register(base), noreg, Address::no_scale, in_ByteSize(disp));
madr._rspec = rspec;
return madr;
}
}
@ -3892,6 +3898,21 @@ void Assembler::movq(Address dst, Register src) {
emit_operand(src, dst);
}
void Assembler::movsbq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
emit_byte(0x0F);
emit_byte(0xBE);
emit_operand(dst, src);
}
void Assembler::movsbq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F);
emit_byte(0xBE);
emit_byte(0xC0 | encode);
}
void Assembler::movslq(Register dst, int32_t imm32) {
// dbx shows movslq(rcx, 3) as movq $0x0000000049000000,(%rbx)
// and movslq(r8, 3); as movl $0x0000000048000000,(%rbx)
@ -3925,6 +3946,51 @@ void Assembler::movslq(Register dst, Register src) {
emit_byte(0xC0 | encode);
}
void Assembler::movswq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
emit_byte(0x0F);
emit_byte(0xBF);
emit_operand(dst, src);
}
void Assembler::movswq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F);
emit_byte(0xBF);
emit_byte(0xC0 | encode);
}
void Assembler::movzbq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
emit_byte(0x0F);
emit_byte(0xB6);
emit_operand(dst, src);
}
void Assembler::movzbq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F);
emit_byte(0xB6);
emit_byte(0xC0 | encode);
}
void Assembler::movzwq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
emit_byte(0x0F);
emit_byte(0xB7);
emit_operand(dst, src);
}
void Assembler::movzwq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
emit_byte(0x0F);
emit_byte(0xB7);
emit_byte(0xC0 | encode);
}
void Assembler::negq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
emit_byte(0xF7);
@ -6197,8 +6263,11 @@ int MacroAssembler::load_signed_byte(Register dst, Address src) {
return off;
}
// word => int32 which seems bad for 64bit
int MacroAssembler::load_signed_word(Register dst, Address src) {
// Note: load_signed_short used to be called load_signed_word.
// Although the 'w' in x86 opcodes refers to the term "word" in the assembler
// manual, which means 16 bits, that usage is found nowhere in HotSpot code.
// The term "word" in HotSpot means a 32- or 64-bit machine word.
int MacroAssembler::load_signed_short(Register dst, Address src) {
int off;
if (LP64_ONLY(true ||) VM_Version::is_P6()) {
// This is dubious to me since it seems safe to do a signed 16 => 64 bit
@ -6207,7 +6276,7 @@ int MacroAssembler::load_signed_word(Register dst, Address src) {
off = offset();
movswl(dst, src); // movsxw
} else {
off = load_unsigned_word(dst, src);
off = load_unsigned_short(dst, src);
shll(dst, 16);
sarl(dst, 16);
}
@ -6229,7 +6298,8 @@ int MacroAssembler::load_unsigned_byte(Register dst, Address src) {
return off;
}
int MacroAssembler::load_unsigned_word(Register dst, Address src) {
// Note: load_unsigned_short used to be called load_unsigned_word.
int MacroAssembler::load_unsigned_short(Register dst, Address src) {
// According to Intel Doc. AP-526, "Zero-Extension of Short", p.16,
// and "3.9 Partial Register Penalties", p. 22).
int off;
@ -6244,6 +6314,28 @@ int MacroAssembler::load_unsigned_word(Register dst, Address src) {
return off;
}
void MacroAssembler::load_sized_value(Register dst, Address src,
int size_in_bytes, bool is_signed) {
switch (size_in_bytes ^ (is_signed ? -1 : 0)) {
#ifndef _LP64
// For case 8, caller is responsible for manually loading
// the second word into another register.
case ~8: // fall through:
case 8: movl( dst, src ); break;
#else
case ~8: // fall through:
case 8: movq( dst, src ); break;
#endif
case ~4: // fall through:
case 4: movl( dst, src ); break;
case ~2: load_signed_short( dst, src ); break;
case 2: load_unsigned_short( dst, src ); break;
case ~1: load_signed_byte( dst, src ); break;
case 1: load_unsigned_byte( dst, src ); break;
default: ShouldNotReachHere();
}
}
void MacroAssembler::mov32(AddressLiteral dst, Register src) {
if (reachable(dst)) {
movl(as_Address(dst), src);
@ -6463,7 +6555,8 @@ void MacroAssembler::serialize_memory(Register thread, Register tmp) {
Address index(noreg, tmp, Address::times_1);
ExternalAddress page(os::get_memory_serialize_page());
movptr(ArrayAddress(page, index), tmp);
// Size of store must match masking code above
movl(as_Address(ArrayAddress(page, index)), tmp);
}
// Calls to C land
@ -7049,6 +7142,81 @@ void MacroAssembler::trigfunc(char trig, int num_fpu_regs_in_use) {
}
// Look up the method for a megamorphic invokeinterface call.
// The target method is determined by <intf_klass, itable_index>.
// The receiver klass is in recv_klass.
// On success, the result will be in method_result, and execution falls through.
// On failure, execution transfers to the given label.
void MacroAssembler::lookup_interface_method(Register recv_klass,
Register intf_klass,
RegisterConstant itable_index,
Register method_result,
Register scan_temp,
Label& L_no_such_interface) {
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
assert(itable_index.is_constant() || itable_index.as_register() == method_result,
"caller must use same register for non-constant itable index as for method");
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
int vtable_base = instanceKlass::vtable_start_offset() * wordSize;
int itentry_off = itableMethodEntry::method_offset_in_bytes();
int scan_step = itableOffsetEntry::size() * wordSize;
int vte_size = vtableEntry::size() * wordSize;
Address::ScaleFactor times_vte_scale = Address::times_ptr;
assert(vte_size == wordSize, "else adjust times_vte_scale");
movl(scan_temp, Address(recv_klass, instanceKlass::vtable_length_offset() * wordSize));
// %%% Could store the aligned, prescaled offset in the klassoop.
lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
if (HeapWordsPerLong > 1) {
// Round up to align_object_offset boundary
// see code for instanceKlass::start_of_itable!
round_to(scan_temp, BytesPerLong);
}
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
// for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
// if (scan->interface() == intf) {
// result = (klass + scan->offset() + itable_index);
// }
// }
Label search, found_method;
for (int peel = 1; peel >= 0; peel--) {
movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
cmpptr(intf_klass, method_result);
if (peel) {
jccb(Assembler::equal, found_method);
} else {
jccb(Assembler::notEqual, search);
// (invert the test to fall through to found_method...)
}
if (!peel) break;
bind(search);
// Check that the previous entry is non-null. A null entry means that
// the receiver class doesn't implement the interface, and wasn't the
// same as when the caller was compiled.
testptr(method_result, method_result);
jcc(Assembler::zero, L_no_such_interface);
addptr(scan_temp, scan_step);
}
bind(found_method);
// Got a hit.
movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
}
void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) {
ucomisd(dst, as_Address(src));
}
@ -7094,6 +7262,31 @@ void MacroAssembler::verify_oop(Register reg, const char* s) {
}
RegisterConstant MacroAssembler::delayed_value(intptr_t* delayed_value_addr,
Register tmp,
int offset) {
intptr_t value = *delayed_value_addr;
if (value != 0)
return RegisterConstant(value + offset);
// load indirectly to solve generation ordering problem
movptr(tmp, ExternalAddress((address) delayed_value_addr));
#ifdef ASSERT
Label L;
testl(tmp, tmp);
jccb(Assembler::notZero, L);
hlt();
bind(L);
#endif
if (offset != 0)
addptr(tmp, offset);
return RegisterConstant(tmp);
}
void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
if (!VerifyOops) return;

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -153,6 +153,21 @@ class Address VALUE_OBJ_CLASS_SPEC {
times_8 = 3,
times_ptr = LP64_ONLY(times_8) NOT_LP64(times_4)
};
static ScaleFactor times(int size) {
assert(size >= 1 && size <= 8 && is_power_of_2(size), "bad scale size");
if (size == 8) return times_8;
if (size == 4) return times_4;
if (size == 2) return times_2;
return times_1;
}
static int scale_size(ScaleFactor scale) {
assert(scale != no_scale, "");
assert(((1 << (int)times_1) == 1 &&
(1 << (int)times_2) == 2 &&
(1 << (int)times_4) == 4 &&
(1 << (int)times_8) == 8), "");
return (1 << (int)scale);
}
private:
Register _base;
@ -197,6 +212,22 @@ class Address VALUE_OBJ_CLASS_SPEC {
"inconsistent address");
}
Address(Register base, RegisterConstant index, ScaleFactor scale = times_1, int disp = 0)
: _base (base),
_index(index.register_or_noreg()),
_scale(scale),
_disp (disp + (index.constant_or_zero() * scale_size(scale))) {
if (!index.is_register()) scale = Address::no_scale;
assert(!_index->is_valid() == (scale == Address::no_scale),
"inconsistent address");
}
Address plus_disp(int disp) const {
Address a = (*this);
a._disp += disp;
return a;
}
// The following two overloads are used in connection with the
// ByteSize type (see sizes.hpp). They simplify the use of
// ByteSize'd arguments in assembly code. Note that their equivalent
@ -224,6 +255,17 @@ class Address VALUE_OBJ_CLASS_SPEC {
assert(!index->is_valid() == (scale == Address::no_scale),
"inconsistent address");
}
Address(Register base, RegisterConstant index, ScaleFactor scale, ByteSize disp)
: _base (base),
_index(index.register_or_noreg()),
_scale(scale),
_disp (in_bytes(disp) + (index.constant_or_zero() * scale_size(scale))) {
if (!index.is_register()) scale = Address::no_scale;
assert(!_index->is_valid() == (scale == Address::no_scale),
"inconsistent address");
}
#endif // ASSERT
// accessors
@ -236,11 +278,10 @@ class Address VALUE_OBJ_CLASS_SPEC {
// Convert the raw encoding form into the form expected by the constructor for
// Address. An index of 4 (rsp) corresponds to having no index, so convert
// that to noreg for the Address constructor.
static Address make_raw(int base, int index, int scale, int disp);
static Address make_raw(int base, int index, int scale, int disp, bool disp_is_oop);
static Address make_array(ArrayAddress);
private:
bool base_needs_rex() const {
return _base != noreg && _base->encoding() >= 8;
@ -1097,6 +1138,9 @@ private:
void movsbl(Register dst, Register src);
#ifdef _LP64
void movsbq(Register dst, Address src);
void movsbq(Register dst, Register src);
// Move signed 32bit immediate to 64bit extending sign
void movslq(Address dst, int32_t imm64);
void movslq(Register dst, int32_t imm64);
@ -1109,6 +1153,11 @@ private:
void movswl(Register dst, Address src);
void movswl(Register dst, Register src);
#ifdef _LP64
void movswq(Register dst, Address src);
void movswq(Register dst, Register src);
#endif
void movw(Address dst, int imm16);
void movw(Register dst, Address src);
void movw(Address dst, Register src);
@ -1116,9 +1165,19 @@ private:
void movzbl(Register dst, Address src);
void movzbl(Register dst, Register src);
#ifdef _LP64
void movzbq(Register dst, Address src);
void movzbq(Register dst, Register src);
#endif
void movzwl(Register dst, Address src);
void movzwl(Register dst, Register src);
#ifdef _LP64
void movzwq(Register dst, Address src);
void movzwq(Register dst, Register src);
#endif
void mull(Address src);
void mull(Register src);
@ -1393,17 +1452,20 @@ class MacroAssembler: public Assembler {
// The following 4 methods return the offset of the appropriate move instruction
// Support for fast byte/word loading with zero extension (depending on particular CPU)
// Support for fast byte/short loading with zero extension (depending on particular CPU)
int load_unsigned_byte(Register dst, Address src);
int load_unsigned_word(Register dst, Address src);
int load_unsigned_short(Register dst, Address src);
// Support for fast byte/word loading with sign extension (depending on particular CPU)
// Support for fast byte/short loading with sign extension (depending on particular CPU)
int load_signed_byte(Register dst, Address src);
int load_signed_word(Register dst, Address src);
int load_signed_short(Register dst, Address src);
// Support for sign-extension (hi:lo = extend_sign(lo))
void extend_sign(Register hi, Register lo);
// Loading values by size and signed-ness
void load_sized_value(Register dst, Address src, int size_in_bytes, bool is_signed);
// Support for inc/dec with optimal instruction selection depending on value
void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; }
@ -1721,6 +1783,14 @@ class MacroAssembler: public Assembler {
);
void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
// interface method calling
void lookup_interface_method(Register recv_klass,
Register intf_klass,
RegisterConstant itable_index,
Register method_result,
Register scan_temp,
Label& no_such_interface);
//----
void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
@ -1763,6 +1833,10 @@ class MacroAssembler: public Assembler {
// stack overflow + shadow pages. Also, clobbers tmp
void bang_stack_size(Register size, Register tmp);
virtual RegisterConstant delayed_value(intptr_t* delayed_value_addr,
Register tmp,
int offset);
// Support for serializing memory accesses between threads
void serialize_memory(Register thread, Register tmp);

View File

@ -554,8 +554,8 @@ void LIR_Assembler::emit_string_compare(LIR_Opr arg0, LIR_Opr arg1, LIR_Opr dst,
__ jcc (Assembler::zero, noLoop);
// compare first characters
__ load_unsigned_word(rcx, Address(rdi, 0));
__ load_unsigned_word(rbx, Address(rsi, 0));
__ load_unsigned_short(rcx, Address(rdi, 0));
__ load_unsigned_short(rbx, Address(rsi, 0));
__ subl(rcx, rbx);
__ jcc(Assembler::notZero, haveResult);
// starting loop
@ -574,8 +574,8 @@ void LIR_Assembler::emit_string_compare(LIR_Opr arg0, LIR_Opr arg1, LIR_Opr dst,
Label loop;
__ align(wordSize);
__ bind(loop);
__ load_unsigned_word(rcx, Address(rdi, rax, Address::times_2, 0));
__ load_unsigned_word(rbx, Address(rsi, rax, Address::times_2, 0));
__ load_unsigned_short(rcx, Address(rdi, rax, Address::times_2, 0));
__ load_unsigned_short(rbx, Address(rsi, rax, Address::times_2, 0));
__ subl(rcx, rbx);
__ jcc(Assembler::notZero, haveResult);
__ increment(rax);

View File

@ -501,7 +501,7 @@ void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) {
LIRItem right(x->y(), this);
left.load_item();
// dont load constants to save register
// don't load constants to save register
right.load_nonconstant();
rlock_result(x);
arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL);

View File

@ -513,7 +513,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
// compute full expression stack limit
const Address size_of_stack (rbx, methodOopDesc::max_stack_offset());
__ load_unsigned_word(rdx, size_of_stack); // get size of expression stack in words
__ load_unsigned_short(rdx, size_of_stack); // get size of expression stack in words
__ negptr(rdx); // so we can subtract in next step
// Allocate expression stack
__ lea(rsp, Address(rsp, rdx, Address::times_ptr));
@ -523,7 +523,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
#ifdef _LP64
// Make sure stack is properly aligned and sized for the abi
__ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
__ andptr(rsp, -16); // must be 16 byte boundry (see amd64 ABI)
__ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI)
#endif // _LP64
@ -659,7 +659,7 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
// Always give one monitor to allow us to start interp if sync method.
// Any additional monitors need a check when moving the expression stack
const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
__ load_unsigned_word(rax, size_of_stack); // get size of expression stack in words
__ load_unsigned_short(rax, size_of_stack); // get size of expression stack in words
__ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
__ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
@ -863,13 +863,13 @@ address InterpreterGenerator::generate_accessor_entry(void) {
__ bind(notByte);
__ cmpl(rdx, stos);
__ jcc(Assembler::notEqual, notShort);
__ load_signed_word(rax, field_address);
__ load_signed_short(rax, field_address);
__ jmp(xreturn_path);
__ bind(notShort);
__ cmpl(rdx, ctos);
__ jcc(Assembler::notEqual, notChar);
__ load_unsigned_word(rax, field_address);
__ load_unsigned_short(rax, field_address);
__ jmp(xreturn_path);
__ bind(notChar);
@ -937,7 +937,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
const Register locals = rdi;
// get parameter size (always needed)
__ load_unsigned_word(rcx, size_of_parameters);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: methodOop
// rcx: size of parameters
@ -970,7 +970,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
#ifdef _LP64
// duplicate the alignment rsp got after setting stack_base
__ subptr(rax, frame::arg_reg_save_area_bytes); // windows
__ andptr(rax, -16); // must be 16 byte boundry (see amd64 ABI)
__ andptr(rax, -16); // must be 16 byte boundary (see amd64 ABI)
#endif // _LP64
__ cmpptr(rax, rsp);
__ jcc(Assembler::equal, L);
@ -1062,12 +1062,12 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// allocate space for parameters
__ movptr(method, STATE(_method));
__ verify_oop(method);
__ load_unsigned_word(t, Address(method, methodOopDesc::size_of_parameters_offset()));
__ load_unsigned_short(t, Address(method, methodOopDesc::size_of_parameters_offset()));
__ shll(t, 2);
#ifdef _LP64
__ subptr(rsp, t);
__ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
__ andptr(rsp, -16); // must be 16 byte boundry (see amd64 ABI)
__ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI)
#else
__ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror
__ subptr(rsp, t);
@ -1659,11 +1659,11 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock));
// get parameter size (always needed)
__ load_unsigned_word(rcx, size_of_parameters);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: methodOop
// rcx: size of parameters
__ load_unsigned_word(rdx, size_of_locals); // get size of locals in words
__ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
__ subptr(rdx, rcx); // rdx = no. of additional locals
@ -1949,7 +1949,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
__ movptr(rbx, STATE(_result._to_call._callee));
// callee left args on top of expression stack, remove them
__ load_unsigned_word(rcx, Address(rbx, methodOopDesc::size_of_parameters_offset()));
__ load_unsigned_short(rcx, Address(rbx, methodOopDesc::size_of_parameters_offset()));
__ lea(rsp, Address(rsp, rcx, Address::times_ptr));
__ movl(rcx, Address(rbx, methodOopDesc::result_index_offset()));
@ -2119,7 +2119,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// Make it look like call_stub calling conventions
// Get (potential) receiver
__ load_unsigned_word(rcx, size_of_parameters); // get size of parameters in words
__ load_unsigned_short(rcx, size_of_parameters); // get size of parameters in words
ExternalAddress recursive(CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation));
__ pushptr(recursive.addr()); // make it look good in the debugger

View File

@ -192,7 +192,7 @@ void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, i
void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset) {
assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
assert(cache != index, "must use different registers");
load_unsigned_word(index, Address(rsi, bcp_offset));
load_unsigned_short(index, Address(rsi, bcp_offset));
movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below");
shlptr(index, 2); // convert from field index to ConstantPoolCacheEntry index
@ -202,7 +202,7 @@ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Regis
void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset) {
assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
assert(cache != tmp, "must use different register");
load_unsigned_word(tmp, Address(rsi, bcp_offset));
load_unsigned_short(tmp, Address(rsi, bcp_offset));
assert(sizeof(ConstantPoolCacheEntry) == 4*wordSize, "adjust code below");
// convert from field index to ConstantPoolCacheEntry index
// and from word offset to byte offset
@ -1031,7 +1031,7 @@ void InterpreterMacroAssembler::verify_method_data_pointer() {
// If the mdp is valid, it will point to a DataLayout header which is
// consistent with the bcp. The converse is highly probable also.
load_unsigned_word(rdx, Address(rcx, in_bytes(DataLayout::bci_offset())));
load_unsigned_short(rdx, Address(rcx, in_bytes(DataLayout::bci_offset())));
addptr(rdx, Address(rbx, methodOopDesc::const_offset()));
lea(rdx, Address(rdx, constMethodOopDesc::codes_offset()));
cmpptr(rdx, rsi);
@ -1512,6 +1512,15 @@ void InterpreterMacroAssembler::notify_method_entry() {
call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), rcx, rbx);
}
// RedefineClasses() tracing support for obsolete method entry
if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
get_thread(rcx);
get_method(rbx);
call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
rcx, rbx);
}
}

View File

@ -190,7 +190,7 @@ void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache,
int bcp_offset) {
assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
assert(cache != index, "must use different registers");
load_unsigned_word(index, Address(r13, bcp_offset));
load_unsigned_short(index, Address(r13, bcp_offset));
movptr(cache, Address(rbp, frame::interpreter_frame_cache_offset * wordSize));
assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
// convert from field index to ConstantPoolCacheEntry index
@ -203,7 +203,7 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
int bcp_offset) {
assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
assert(cache != tmp, "must use different register");
load_unsigned_word(tmp, Address(r13, bcp_offset));
load_unsigned_short(tmp, Address(r13, bcp_offset));
assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below");
// convert from field index to ConstantPoolCacheEntry index
// and from word offset to byte offset
@ -1063,8 +1063,8 @@ void InterpreterMacroAssembler::verify_method_data_pointer() {
// If the mdp is valid, it will point to a DataLayout header which is
// consistent with the bcp. The converse is highly probable also.
load_unsigned_word(c_rarg2,
Address(c_rarg3, in_bytes(DataLayout::bci_offset())));
load_unsigned_short(c_rarg2,
Address(c_rarg3, in_bytes(DataLayout::bci_offset())));
addptr(c_rarg2, Address(rbx, methodOopDesc::const_offset()));
lea(c_rarg2, Address(c_rarg2, constMethodOopDesc::codes_offset()));
cmpptr(c_rarg2, r13);
@ -1593,6 +1593,14 @@ void InterpreterMacroAssembler::notify_method_entry() {
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry),
r15_thread, c_rarg1);
}
// RedefineClasses() tracing support for obsolete method entry
if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
get_method(c_rarg1);
call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
r15_thread, c_rarg1);
}
}

View File

@ -1534,6 +1534,13 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
thread, rax);
}
// RedefineClasses() tracing support for obsolete method entry
if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
__ movoop(rax, JNIHandles::make_local(method()));
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
thread, rax);
}
// These are register definitions we need for locking/unlocking
const Register swap_reg = rax; // Must use rax, for cmpxchg instruction

View File

@ -1350,7 +1350,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
{
Label L;
__ mov(rax, rsp);
__ andptr(rax, -16); // must be 16 byte boundry (see amd64 ABI)
__ andptr(rax, -16); // must be 16 byte boundary (see amd64 ABI)
__ cmpptr(rax, rsp);
__ jcc(Assembler::equal, L);
__ stop("improperly aligned stack");
@ -1508,6 +1508,17 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
restore_args(masm, total_c_args, c_arg, out_regs);
}
// RedefineClasses() tracing support for obsolete method entry
if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) {
// protect the args we've loaded
save_args(masm, total_c_args, c_arg, out_regs);
__ movoop(c_rarg1, JNIHandles::make_local(method()));
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry),
r15_thread, c_rarg1);
restore_args(masm, total_c_args, c_arg, out_regs);
}
// Lock a synchronized method
// Register definitions used by locking and unlocking

View File

@ -662,13 +662,13 @@ address InterpreterGenerator::generate_accessor_entry(void) {
__ bind(notByte);
__ cmpl(rdx, stos);
__ jcc(Assembler::notEqual, notShort);
__ load_signed_word(rax, field_address);
__ load_signed_short(rax, field_address);
__ jmp(xreturn_path);
__ bind(notShort);
__ cmpl(rdx, ctos);
__ jcc(Assembler::notEqual, notChar);
__ load_unsigned_word(rax, field_address);
__ load_unsigned_short(rax, field_address);
__ jmp(xreturn_path);
__ bind(notChar);
@ -723,7 +723,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
const Address access_flags (rbx, methodOopDesc::access_flags_offset());
// get parameter size (always needed)
__ load_unsigned_word(rcx, size_of_parameters);
__ load_unsigned_short(rcx, size_of_parameters);
// native calls don't need the stack size check since they have no expression stack
// and the arguments are already on the stack and we only add a handful of words
@ -838,7 +838,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// allocate space for parameters
__ get_method(method);
__ verify_oop(method);
__ load_unsigned_word(t, Address(method, methodOopDesc::size_of_parameters_offset()));
__ load_unsigned_short(t, Address(method, methodOopDesc::size_of_parameters_offset()));
__ shlptr(t, Interpreter::logStackElementSize());
__ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror
__ subptr(rsp, t);
@ -1155,14 +1155,14 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
const Address access_flags (rbx, methodOopDesc::access_flags_offset());
// get parameter size (always needed)
__ load_unsigned_word(rcx, size_of_parameters);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx,: methodOop
// rcx: size of parameters
// rsi: sender_sp (could differ from sp+wordSize if we were called via c2i )
__ load_unsigned_word(rdx, size_of_locals); // get size of locals in words
__ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
__ subl(rdx, rcx); // rdx = no. of additional locals
// see if we've got enough room on the stack for locals plus overhead.
@ -1558,7 +1558,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// Compute size of arguments for saving when returning to deoptimized caller
__ get_method(rax);
__ verify_oop(rax);
__ load_unsigned_word(rax, Address(rax, in_bytes(methodOopDesc::size_of_parameters_offset())));
__ load_unsigned_short(rax, Address(rax, in_bytes(methodOopDesc::size_of_parameters_offset())));
__ shlptr(rax, Interpreter::logStackElementSize());
__ restore_locals();
__ subptr(rdi, rax);

View File

@ -650,7 +650,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
__ cmpl(rdx, stos);
__ jcc(Assembler::notEqual, notShort);
// stos
__ load_signed_word(rax, field_address);
__ load_signed_short(rax, field_address);
__ jmp(xreturn_path);
__ bind(notShort);
@ -662,7 +662,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
__ bind(okay);
#endif
// ctos
__ load_unsigned_word(rax, field_address);
__ load_unsigned_short(rax, field_address);
__ bind(xreturn_path);
@ -702,7 +702,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
const Address access_flags (rbx, methodOopDesc::access_flags_offset());
// get parameter size (always needed)
__ load_unsigned_word(rcx, size_of_parameters);
__ load_unsigned_short(rcx, size_of_parameters);
// native calls don't need the stack size check since they have no
// expression stack and the arguments are already on the stack and
@ -819,14 +819,14 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// allocate space for parameters
__ get_method(method);
__ verify_oop(method);
__ load_unsigned_word(t,
Address(method,
methodOopDesc::size_of_parameters_offset()));
__ load_unsigned_short(t,
Address(method,
methodOopDesc::size_of_parameters_offset()));
__ shll(t, Interpreter::logStackElementSize());
__ subptr(rsp, t);
__ subptr(rsp, frame::arg_reg_save_area_bytes); // windows
__ andptr(rsp, -16); // must be 16 byte boundry (see amd64 ABI)
__ andptr(rsp, -16); // must be 16 byte boundary (see amd64 ABI)
// get signature handler
{
@ -1165,13 +1165,13 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
const Address access_flags(rbx, methodOopDesc::access_flags_offset());
// get parameter size (always needed)
__ load_unsigned_word(rcx, size_of_parameters);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: methodOop
// rcx: size of parameters
// r13: sender_sp (could differ from sp+wordSize if we were called via c2i )
__ load_unsigned_word(rdx, size_of_locals); // get size of locals in words
__ load_unsigned_short(rdx, size_of_locals); // get size of locals in words
__ subl(rdx, rcx); // rdx = no. of additional locals
// YYY
@ -1583,7 +1583,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() {
// Compute size of arguments for saving when returning to
// deoptimized caller
__ get_method(rax);
__ load_unsigned_word(rax, Address(rax, in_bytes(methodOopDesc::
__ load_unsigned_short(rax, Address(rax, in_bytes(methodOopDesc::
size_of_parameters_offset())));
__ shll(rax, Interpreter::logStackElementSize());
__ restore_locals(); // XXX do we need this?

View File

@ -296,7 +296,7 @@ void TemplateTable::bipush() {
void TemplateTable::sipush() {
transition(vtos, itos);
__ load_unsigned_word(rax, at_bcp(1));
__ load_unsigned_short(rax, at_bcp(1));
__ bswapl(rax);
__ sarl(rax, 16);
}
@ -662,7 +662,7 @@ void TemplateTable::caload() {
index_check(rdx, rax); // kills rbx,
// rax,: index
// can do better code for P5 - may want to improve this at some point
__ load_unsigned_word(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)));
__ load_unsigned_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)));
__ mov(rax, rbx);
}
@ -677,7 +677,7 @@ void TemplateTable::fast_icaload() {
// rdx: array
index_check(rdx, rax);
// rax,: index
__ load_unsigned_word(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)));
__ load_unsigned_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)));
__ mov(rax, rbx);
}
@ -687,7 +687,7 @@ void TemplateTable::saload() {
index_check(rdx, rax); // kills rbx,
// rax,: index
// can do better code for P5 - may want to improve this at some point
__ load_signed_word(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT)));
__ load_signed_short(rbx, Address(rdx, rax, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_SHORT)));
__ mov(rax, rbx);
}
@ -1586,7 +1586,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
// Handle all the JSR stuff here, then exit.
// It's much shorter and cleaner than intermingling with the
// non-JSR normal-branch stuff occuring below.
// non-JSR normal-branch stuff occurring below.
if (is_jsr) {
// Pre-load the next target bytecode into EBX
__ load_unsigned_byte(rbx, Address(rsi, rdx, Address::times_1, 0));
@ -2310,7 +2310,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
__ cmpl(flags, ctos );
__ jcc(Assembler::notEqual, notChar);
__ load_unsigned_word(rax, lo );
__ load_unsigned_short(rax, lo );
__ push(ctos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_cgetfield, rcx, rbx);
@ -2322,7 +2322,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
__ cmpl(flags, stos );
__ jcc(Assembler::notEqual, notShort);
__ load_signed_word(rax, lo );
__ load_signed_short(rax, lo );
__ push(stos);
if (!is_static) {
patch_bytecode(Bytecodes::_fast_sgetfield, rcx, rbx);
@ -2830,8 +2830,8 @@ void TemplateTable::fast_accessfield(TosState state) {
// access field
switch (bytecode()) {
case Bytecodes::_fast_bgetfield: __ movsbl(rax, lo ); break;
case Bytecodes::_fast_sgetfield: __ load_signed_word(rax, lo ); break;
case Bytecodes::_fast_cgetfield: __ load_unsigned_word(rax, lo ); break;
case Bytecodes::_fast_sgetfield: __ load_signed_short(rax, lo ); break;
case Bytecodes::_fast_cgetfield: __ load_unsigned_short(rax, lo ); break;
case Bytecodes::_fast_igetfield: __ movl(rax, lo); break;
case Bytecodes::_fast_lgetfield: __ stop("should not be rewritten"); break;
case Bytecodes::_fast_fgetfield: __ fld_s(lo); break;
@ -3055,35 +3055,44 @@ void TemplateTable::invokeinterface(int byte_no) {
// profile this call
__ profile_virtual_call(rdx, rsi, rdi);
__ mov(rdi, rdx); // Save klassOop in rdi
Label no_such_interface, no_such_method;
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
const int base = instanceKlass::vtable_start_offset() * wordSize;
assert(vtableEntry::size() * wordSize == (1 << (int)Address::times_ptr), "adjust the scaling in the code below");
__ movl(rsi, Address(rdx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
__ lea(rdx, Address(rdx, rsi, Address::times_4, base));
if (HeapWordsPerLong > 1) {
// Round up to align_object_offset boundary
__ round_to(rdx, BytesPerLong);
}
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, rbx,
// outputs: method, scan temp. reg
rbx, rsi,
no_such_interface);
Label entry, search, interface_ok;
// rbx,: methodOop to call
// rcx: receiver
// Check for abstract method error
// Note: This should be done more efficiently via a throw_abstract_method_error
// interpreter entry point and a conditional jump to it in case of a null
// method.
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, no_such_method);
__ jmpb(entry);
__ bind(search);
__ addptr(rdx, itableOffsetEntry::size() * wordSize);
// do the call
// rcx: receiver
// rbx,: methodOop
__ jump_from_interpreted(rbx, rdx);
__ should_not_reach_here();
__ bind(entry);
// exception handling code follows...
// note: must restore interpreter registers to canonical
// state for exception handling to work correctly!
// Check that the entry is non-null. A null entry means that the receiver
// class doesn't implement the interface, and wasn't the same as the
// receiver class checked when the interface was resolved.
__ push(rdx);
__ movptr(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
__ testptr(rdx, rdx);
__ jcc(Assembler::notZero, interface_ok);
__ bind(no_such_method);
// throw exception
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
__ bind(no_such_interface);
// throw exception
__ pop(rdx); // pop saved register first.
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
@ -3091,42 +3100,6 @@ void TemplateTable::invokeinterface(int byte_no) {
InterpreterRuntime::throw_IncompatibleClassChangeError));
// the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
__ bind(interface_ok);
__ pop(rdx);
__ cmpptr(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
__ jcc(Assembler::notEqual, search);
__ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes()));
__ addptr(rdx, rdi); // Add offset to klassOop
assert(itableMethodEntry::size() * wordSize == (1 << (int)Address::times_ptr), "adjust the scaling in the code below");
__ movptr(rbx, Address(rdx, rbx, Address::times_ptr));
// rbx,: methodOop to call
// rcx: receiver
// Check for abstract method error
// Note: This should be done more efficiently via a throw_abstract_method_error
// interpreter entry point and a conditional jump to it in case of a null
// method.
{ Label L;
__ testptr(rbx, rbx);
__ jcc(Assembler::notZero, L);
// throw exception
// note: must restore interpreter registers to canonical
// state for exception handling to work correctly!
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
__ bind(L);
}
// do the call
// rcx: receiver
// rbx,: methodOop
__ jump_from_interpreted(rbx, rdx);
}
//----------------------------------------------------------------------------------------------------

View File

@ -307,7 +307,7 @@ void TemplateTable::bipush() {
void TemplateTable::sipush() {
transition(vtos, itos);
__ load_unsigned_word(rax, at_bcp(1));
__ load_unsigned_short(rax, at_bcp(1));
__ bswapl(rax);
__ sarl(rax, 16);
}
@ -645,10 +645,10 @@ void TemplateTable::caload() {
// eax: index
// rdx: array
index_check(rdx, rax); // kills rbx
__ load_unsigned_word(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)));
__ load_unsigned_short(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)));
}
// iload followed by caload frequent pair
@ -663,10 +663,10 @@ void TemplateTable::fast_icaload() {
// rdx: array
__ pop_ptr(rdx);
index_check(rdx, rax); // kills rbx
__ load_unsigned_word(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)));
__ load_unsigned_short(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_CHAR)));
}
void TemplateTable::saload() {
@ -675,10 +675,10 @@ void TemplateTable::saload() {
// eax: index
// rdx: array
index_check(rdx, rax); // kills rbx
__ load_signed_word(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_SHORT)));
__ load_signed_short(rax,
Address(rdx, rax,
Address::times_2,
arrayOopDesc::base_offset_in_bytes(T_SHORT)));
}
void TemplateTable::iload(int n) {
@ -1559,7 +1559,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) {
// Handle all the JSR stuff here, then exit.
// It's much shorter and cleaner than intermingling with the non-JSR
// normal-branch stuff occuring below.
// normal-branch stuff occurring below.
if (is_jsr) {
// Pre-load the next target bytecode into rbx
__ load_unsigned_byte(rbx, Address(r13, rdx, Address::times_1, 0));
@ -2276,7 +2276,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
__ cmpl(flags, ctos);
__ jcc(Assembler::notEqual, notChar);
// ctos
__ load_unsigned_word(rax, field);
__ load_unsigned_short(rax, field);
__ push(ctos);
// Rewrite bytecode to be faster
if (!is_static) {
@ -2288,7 +2288,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
__ cmpl(flags, stos);
__ jcc(Assembler::notEqual, notShort);
// stos
__ load_signed_word(rax, field);
__ load_signed_short(rax, field);
__ push(stos);
// Rewrite bytecode to be faster
if (!is_static) {
@ -2751,10 +2751,10 @@ void TemplateTable::fast_accessfield(TosState state) {
__ movsbl(rax, field);
break;
case Bytecodes::_fast_sgetfield:
__ load_signed_word(rax, field);
__ load_signed_short(rax, field);
break;
case Bytecodes::_fast_cgetfield:
__ load_unsigned_word(rax, field);
__ load_unsigned_short(rax, field);
break;
case Bytecodes::_fast_fgetfield:
__ movflt(xmm0, field);
@ -3010,97 +3010,55 @@ void TemplateTable::invokeinterface(int byte_no) {
// profile this call
__ profile_virtual_call(rdx, r13, r14);
__ mov(r14, rdx); // Save klassOop in r14
Label no_such_interface, no_such_method;
// Compute start of first itableOffsetEntry (which is at the end of
// the vtable)
const int base = instanceKlass::vtable_start_offset() * wordSize;
// Get length of vtable
assert(vtableEntry::size() * wordSize == 8,
"adjust the scaling in the code below");
__ movl(r13, Address(rdx,
instanceKlass::vtable_length_offset() * wordSize));
__ lea(rdx, Address(rdx, r13, Address::times_8, base));
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rdx, rax, rbx,
// outputs: method, scan temp. reg
rbx, r13,
no_such_interface);
if (HeapWordsPerLong > 1) {
// Round up to align_object_offset boundary
__ round_to(rdx, BytesPerLong);
}
// rbx,: methodOop to call
// rcx: receiver
// Check for abstract method error
// Note: This should be done more efficiently via a throw_abstract_method_error
// interpreter entry point and a conditional jump to it in case of a null
// method.
__ testptr(rbx, rbx);
__ jcc(Assembler::zero, no_such_method);
Label entry, search, interface_ok;
// do the call
// rcx: receiver
// rbx,: methodOop
__ jump_from_interpreted(rbx, rdx);
__ should_not_reach_here();
__ jmpb(entry);
__ bind(search);
__ addptr(rdx, itableOffsetEntry::size() * wordSize);
// exception handling code follows...
// note: must restore interpreter registers to canonical
// state for exception handling to work correctly!
__ bind(entry);
// Check that the entry is non-null. A null entry means that the
// receiver class doesn't implement the interface, and wasn't the
// same as the receiver class checked when the interface was
// resolved.
__ push(rdx);
__ movptr(rdx, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
__ testptr(rdx, rdx);
__ jcc(Assembler::notZero, interface_ok);
__ bind(no_such_method);
// throw exception
__ pop(rdx); // pop saved register first.
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // r13 must be correct for exception handler (was
// destroyed)
__ restore_locals(); // make sure locals pointer is correct as well
// (was destroyed)
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // r13 must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
__ bind(no_such_interface);
// throw exception
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // r13 must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_IncompatibleClassChangeError));
// the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
__ bind(interface_ok);
__ pop(rdx);
__ cmpptr(rax, Address(rdx, itableOffsetEntry::interface_offset_in_bytes()));
__ jcc(Assembler::notEqual, search);
__ movl(rdx, Address(rdx, itableOffsetEntry::offset_offset_in_bytes()));
__ addptr(rdx, r14); // Add offset to klassOop
assert(itableMethodEntry::size() * wordSize == 8,
"adjust the scaling in the code below");
__ movptr(rbx, Address(rdx, rbx, Address::times_8));
// rbx: methodOop to call
// rcx: receiver
// Check for abstract method error
// Note: This should be done more efficiently via a
// throw_abstract_method_error interpreter entry point and a
// conditional jump to it in case of a null method.
{
Label L;
__ testptr(rbx, rbx);
__ jcc(Assembler::notZero, L);
// throw exception
// note: must restore interpreter registers to canonical
// state for exception handling to work correctly!
__ pop(rbx); // pop return address (pushed by prepare_invoke)
__ restore_bcp(); // r13 must be correct for exception handler
// (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as
// well (was destroyed)
__ call_VM(noreg,
CAST_FROM_FN_PTR(address,
InterpreterRuntime::throw_AbstractMethodError));
// the call_VM checks for exception, so we should never return here.
__ should_not_reach_here();
__ bind(L);
}
__ movptr(rcx, Address(rbx, methodOopDesc::interpreter_entry_offset()));
// do the call
// rcx: receiver
// rbx: methodOop
__ jump_from_interpreted(rbx, rdx);
return;
}
//-----------------------------------------------------------------------------
// Allocation

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
*/
# include "incls/_precompiled.incl"
# include "incls/_vm_version_x86_32.cpp.incl"
# include "incls/_vm_version_x86.cpp.incl"
int VM_Version::_cpu;
@ -67,8 +67,14 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
//
// void getPsrInfo(VM_Version::CpuidInfo* cpuid_info);
//
// LP64: rcx and rdx are first and second argument registers on windows
__ push(rbp);
#ifdef _LP64
__ mov(rbp, c_rarg0); // cpuid_info address
#else
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
#endif
__ push(rbx);
__ push(rsi);
__ pushf(); // preserve rbx, and flags
@ -110,12 +116,12 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
__ jmp(done);
//
// at this point, we have a chip which supports the "cpuid" instruction
// At this point, we have a chip which supports the "cpuid" instruction
//
__ bind(detect_586);
__ xorptr(rax, rax);
__ xorl(rax, rax);
__ cpuid();
__ orptr(rax, rax);
__ orl(rax, rax);
__ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input
// value of at least 1, we give up and
// assume a 486
@ -131,12 +137,12 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
//
// cpuid(0x4) Deterministic cache params
//
__ movl(rax, 4); // and rcx already set to 0x0
__ xorl(rcx, rcx);
__ movl(rax, 4);
__ xorl(rcx, rcx); // L1 cache
__ cpuid();
__ push(rax);
__ andl(rax, 0x1f); // Determine if valid cache parameters used
__ orl(rax, rax); // rax,[4:0] == 0 indicates invalid cache
__ orl(rax, rax); // eax[4:0] == 0 indicates invalid cache
__ pop(rax);
__ jccb(Assembler::equal, std_cpuid1);
@ -225,6 +231,7 @@ void VM_Version::get_processor_features() {
_stepping = 0;
_cpuFeatures = 0;
_logical_processors_per_package = 1;
if (!Use486InstrsOnly) {
// Get raw processor info
getPsrInfo_stub(&_cpuid_info);
@ -232,6 +239,7 @@ void VM_Version::get_processor_features() {
_cpu = extended_cpu_family();
_model = extended_cpu_model();
_stepping = cpu_stepping();
if (cpu_family() > 4) { // it supports CPUID
_cpuFeatures = feature_flags();
// Logical processors are only available on P4s and above,
@ -239,21 +247,34 @@ void VM_Version::get_processor_features() {
_logical_processors_per_package = logical_processor_count();
}
}
_supports_cx8 = supports_cmpxchg8();
// if the OS doesn't support SSE, we can't use this feature even if the HW does
if( !os::supports_sse())
#ifdef _LP64
// OS should support SSE for x64 and hardware should support at least SSE2.
if (!VM_Version::supports_sse2()) {
vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported");
}
#endif
// If the OS doesn't support SSE, we can't use this feature even if the HW does
if (!os::supports_sse())
_cpuFeatures &= ~(CPU_SSE|CPU_SSE2|CPU_SSE3|CPU_SSSE3|CPU_SSE4A|CPU_SSE4_1|CPU_SSE4_2);
if (UseSSE < 4) {
_cpuFeatures &= ~CPU_SSE4_1;
_cpuFeatures &= ~CPU_SSE4_2;
}
if (UseSSE < 3) {
_cpuFeatures &= ~CPU_SSE3;
_cpuFeatures &= ~CPU_SSSE3;
_cpuFeatures &= ~CPU_SSE4A;
}
if (UseSSE < 2)
_cpuFeatures &= ~CPU_SSE2;
if (UseSSE < 1)
_cpuFeatures &= ~CPU_SSE;
@ -418,10 +439,21 @@ void VM_Version::get_processor_features() {
if( AllocatePrefetchStyle == 2 && is_intel() &&
cpu_family() == 6 && supports_sse3() ) { // watermark prefetching on Core
#ifdef _LP64
AllocatePrefetchDistance = 384;
#else
AllocatePrefetchDistance = 320;
#endif
}
assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value");
#ifdef _LP64
// Prefetch settings
PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes();
PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes();
PrefetchFieldsAhead = prefetch_fields_ahead();
#endif
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Logical CPUs per core: %u",
@ -450,6 +482,16 @@ void VM_Version::get_processor_features() {
tty->print_cr(" %d, one line", AllocatePrefetchDistance);
}
}
if (PrefetchCopyIntervalInBytes > 0) {
tty->print_cr("PrefetchCopyIntervalInBytes %d", PrefetchCopyIntervalInBytes);
}
if (PrefetchScanIntervalInBytes > 0) {
tty->print_cr("PrefetchScanIntervalInBytes %d", PrefetchScanIntervalInBytes);
}
if (PrefetchFieldsAhead > 0) {
tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead);
}
}
#endif // !PRODUCT
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -112,20 +112,6 @@ public:
} bits;
};
union ExtCpuid1Edx {
uint32_t value;
struct {
uint32_t : 22,
mmx_amd : 1,
mmx : 1,
fxsr : 1,
: 4,
long_mode : 1,
tdnow2 : 1,
tdnow : 1;
} bits;
};
union ExtCpuid1Ecx {
uint32_t value;
struct {
@ -140,6 +126,20 @@ public:
} bits;
};
union ExtCpuid1Edx {
uint32_t value;
struct {
uint32_t : 22,
mmx_amd : 1,
mmx : 1,
fxsr : 1,
: 4,
long_mode : 1,
tdnow2 : 1,
tdnow : 1;
} bits;
};
union ExtCpuid5Ex {
uint32_t value;
struct {
@ -167,17 +167,17 @@ protected:
static const char* _features_str;
enum {
CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX)
CPU_CMOV = (1 << 1),
CPU_FXSR = (1 << 2),
CPU_HT = (1 << 3),
CPU_MMX = (1 << 4),
CPU_3DNOW= (1 << 5),
CPU_SSE = (1 << 6),
CPU_SSE2 = (1 << 7),
CPU_SSE3 = (1 << 8),
CPU_SSSE3= (1 << 9),
CPU_SSE4A= (1 <<10),
CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX)
CPU_CMOV = (1 << 1),
CPU_FXSR = (1 << 2),
CPU_HT = (1 << 3),
CPU_MMX = (1 << 4),
CPU_3DNOW = (1 << 5), // 3DNow comes from cpuid 0x80000001 (EDX)
CPU_SSE = (1 << 6),
CPU_SSE2 = (1 << 7),
CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX)
CPU_SSSE3 = (1 << 9),
CPU_SSE4A = (1 << 10),
CPU_SSE4_1 = (1 << 11),
CPU_SSE4_2 = (1 << 12)
} cpuFeatureFlags;
@ -360,7 +360,7 @@ public:
result = _cpuid_info.ext_cpuid5_ecx.bits.L1_line_size;
}
if (result < 32) // not defined ?
result = 32; // 32 bytes by default for other x64
result = 32; // 32 bytes by default on x86 and other x64
return result;
}
@ -395,26 +395,36 @@ public:
// This method should be called before allocate_prefetch_style().
//
// Hardware prefetching (distance/size in bytes):
// Pentium 3 - 64 / 32
// Pentium 4 - 256 / 128
// Athlon - 64 / 32 ????
// Opteron - 128 / 64 only when 2 sequential cache lines accessed
// Core - 128 / 64
//
// Software prefetching (distance in bytes / instruction with best score):
// Pentium 3 - 128 / prefetchnta
// Pentium 4 - 512 / prefetchnta
// Athlon - 128 / prefetchnta
// Opteron - 256 / prefetchnta
// Core - 256 / prefetchnta
// It will be used only when AllocatePrefetchStyle > 0
intx count = AllocatePrefetchDistance;
if (count < 0) { // default ?
if (is_amd()) { // AMD
count = 256; // Opteron
} else { // Intel
if (cpu_family() == 6) {
count = 256;// Pentium M, Core, Core2
} else {
count = 512;// Pentium 4
}
if (count < 0) { // default ?
if (is_amd()) { // AMD
if (supports_sse2())
count = 256; // Opteron
else
count = 128; // Athlon
} else { // Intel
if (supports_sse2())
if (cpu_family() == 6) {
count = 256; // Pentium M, Core, Core2
} else {
count = 512; // Pentium 4
}
else
count = 128; // Pentium 3 (and all other old CPUs)
}
}
return count;

View File

@ -1,439 +0,0 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
class VM_Version: public Abstract_VM_Version {
public:
// cpuid result register layouts. These are all unions of a uint32_t
// (in case anyone wants access to the register as a whole) and a bitfield.
union StdCpuid1Eax {
uint32_t value;
struct {
uint32_t stepping : 4,
model : 4,
family : 4,
proc_type : 2,
: 2,
ext_model : 4,
ext_family : 8,
: 4;
} bits;
};
union StdCpuid1Ebx { // example, unused
uint32_t value;
struct {
uint32_t brand_id : 8,
clflush_size : 8,
threads_per_cpu : 8,
apic_id : 8;
} bits;
};
union StdCpuid1Ecx {
uint32_t value;
struct {
uint32_t sse3 : 1,
: 2,
monitor : 1,
: 1,
vmx : 1,
: 1,
est : 1,
: 1,
ssse3 : 1,
cid : 1,
: 2,
cmpxchg16: 1,
: 4,
dca : 1,
sse4_1 : 1,
sse4_2 : 1,
: 11;
} bits;
};
union StdCpuid1Edx {
uint32_t value;
struct {
uint32_t : 4,
tsc : 1,
: 3,
cmpxchg8 : 1,
: 6,
cmov : 1,
: 7,
mmx : 1,
fxsr : 1,
sse : 1,
sse2 : 1,
: 1,
ht : 1,
: 3;
} bits;
};
union DcpCpuid4Eax {
uint32_t value;
struct {
uint32_t cache_type : 5,
: 21,
cores_per_cpu : 6;
} bits;
};
union DcpCpuid4Ebx {
uint32_t value;
struct {
uint32_t L1_line_size : 12,
partitions : 10,
associativity : 10;
} bits;
};
union ExtCpuid1Ecx {
uint32_t value;
struct {
uint32_t LahfSahf : 1,
CmpLegacy : 1,
: 4,
abm : 1,
sse4a : 1,
misalignsse : 1,
prefetchw : 1,
: 22;
} bits;
};
union ExtCpuid1Edx {
uint32_t value;
struct {
uint32_t : 22,
mmx_amd : 1,
mmx : 1,
fxsr : 1,
: 4,
long_mode : 1,
tdnow2 : 1,
tdnow : 1;
} bits;
};
union ExtCpuid5Ex {
uint32_t value;
struct {
uint32_t L1_line_size : 8,
L1_tag_lines : 8,
L1_assoc : 8,
L1_size : 8;
} bits;
};
union ExtCpuid8Ecx {
uint32_t value;
struct {
uint32_t cores_per_cpu : 8,
: 24;
} bits;
};
protected:
static int _cpu;
static int _model;
static int _stepping;
static int _cpuFeatures; // features returned by the "cpuid" instruction
// 0 if this instruction is not available
static const char* _features_str;
enum {
CPU_CX8 = (1 << 0), // next bits are from cpuid 1 (EDX)
CPU_CMOV = (1 << 1),
CPU_FXSR = (1 << 2),
CPU_HT = (1 << 3),
CPU_MMX = (1 << 4),
CPU_3DNOW= (1 << 5), // 3DNow comes from cpuid 0x80000001 (EDX)
CPU_SSE = (1 << 6),
CPU_SSE2 = (1 << 7),
CPU_SSE3 = (1 << 8), // sse3 comes from cpuid 1 (ECX)
CPU_SSSE3= (1 << 9),
CPU_SSE4A= (1 <<10),
CPU_SSE4_1 = (1 << 11),
CPU_SSE4_2 = (1 << 12)
} cpuFeatureFlags;
// cpuid information block. All info derived from executing cpuid with
// various function numbers is stored here. Intel and AMD info is
// merged in this block: accessor methods disentangle it.
//
// The info block is laid out in subblocks of 4 dwords corresponding to
// rax, rbx, rcx and rdx, whether or not they contain anything useful.
struct CpuidInfo {
// cpuid function 0
uint32_t std_max_function;
uint32_t std_vendor_name_0;
uint32_t std_vendor_name_1;
uint32_t std_vendor_name_2;
// cpuid function 1
StdCpuid1Eax std_cpuid1_rax;
StdCpuid1Ebx std_cpuid1_rbx;
StdCpuid1Ecx std_cpuid1_rcx;
StdCpuid1Edx std_cpuid1_rdx;
// cpuid function 4 (deterministic cache parameters)
DcpCpuid4Eax dcp_cpuid4_rax;
DcpCpuid4Ebx dcp_cpuid4_rbx;
uint32_t dcp_cpuid4_rcx; // unused currently
uint32_t dcp_cpuid4_rdx; // unused currently
// cpuid function 0x80000000 // example, unused
uint32_t ext_max_function;
uint32_t ext_vendor_name_0;
uint32_t ext_vendor_name_1;
uint32_t ext_vendor_name_2;
// cpuid function 0x80000001
uint32_t ext_cpuid1_rax; // reserved
uint32_t ext_cpuid1_rbx; // reserved
ExtCpuid1Ecx ext_cpuid1_rcx;
ExtCpuid1Edx ext_cpuid1_rdx;
// cpuid functions 0x80000002 thru 0x80000004: example, unused
uint32_t proc_name_0, proc_name_1, proc_name_2, proc_name_3;
uint32_t proc_name_4, proc_name_5, proc_name_6, proc_name_7;
uint32_t proc_name_8, proc_name_9, proc_name_10,proc_name_11;
// cpuid function 0x80000005 //AMD L1, Intel reserved
uint32_t ext_cpuid5_rax; // unused currently
uint32_t ext_cpuid5_rbx; // reserved
ExtCpuid5Ex ext_cpuid5_rcx; // L1 data cache info (AMD)
ExtCpuid5Ex ext_cpuid5_rdx; // L1 instruction cache info (AMD)
// cpuid function 0x80000008
uint32_t ext_cpuid8_rax; // unused currently
uint32_t ext_cpuid8_rbx; // reserved
ExtCpuid8Ecx ext_cpuid8_rcx;
uint32_t ext_cpuid8_rdx; // reserved
};
// The actual cpuid info block
static CpuidInfo _cpuid_info;
// Extractors and predicates
static uint32_t extended_cpu_family() {
uint32_t result = _cpuid_info.std_cpuid1_rax.bits.family;
result += _cpuid_info.std_cpuid1_rax.bits.ext_family;
return result;
}
static uint32_t extended_cpu_model() {
uint32_t result = _cpuid_info.std_cpuid1_rax.bits.model;
result |= _cpuid_info.std_cpuid1_rax.bits.ext_model << 4;
return result;
}
static uint32_t cpu_stepping() {
uint32_t result = _cpuid_info.std_cpuid1_rax.bits.stepping;
return result;
}
static uint logical_processor_count() {
uint result = threads_per_core();
return result;
}
static uint32_t feature_flags() {
uint32_t result = 0;
if (_cpuid_info.std_cpuid1_rdx.bits.cmpxchg8 != 0)
result |= CPU_CX8;
if (_cpuid_info.std_cpuid1_rdx.bits.cmov != 0)
result |= CPU_CMOV;
if (_cpuid_info.std_cpuid1_rdx.bits.fxsr != 0 || is_amd() &&
_cpuid_info.ext_cpuid1_rdx.bits.fxsr != 0)
result |= CPU_FXSR;
// HT flag is set for multi-core processors also.
if (threads_per_core() > 1)
result |= CPU_HT;
if (_cpuid_info.std_cpuid1_rdx.bits.mmx != 0 || is_amd() &&
_cpuid_info.ext_cpuid1_rdx.bits.mmx != 0)
result |= CPU_MMX;
if (is_amd() && _cpuid_info.ext_cpuid1_rdx.bits.tdnow != 0)
result |= CPU_3DNOW;
if (_cpuid_info.std_cpuid1_rdx.bits.sse != 0)
result |= CPU_SSE;
if (_cpuid_info.std_cpuid1_rdx.bits.sse2 != 0)
result |= CPU_SSE2;
if (_cpuid_info.std_cpuid1_rcx.bits.sse3 != 0)
result |= CPU_SSE3;
if (_cpuid_info.std_cpuid1_rcx.bits.ssse3 != 0)
result |= CPU_SSSE3;
if (is_amd() && _cpuid_info.ext_cpuid1_rcx.bits.sse4a != 0)
result |= CPU_SSE4A;
if (_cpuid_info.std_cpuid1_rcx.bits.sse4_1 != 0)
result |= CPU_SSE4_1;
if (_cpuid_info.std_cpuid1_rcx.bits.sse4_2 != 0)
result |= CPU_SSE4_2;
return result;
}
static void get_processor_features();
public:
// Offsets for cpuid asm stub
static ByteSize std_cpuid0_offset() { return byte_offset_of(CpuidInfo, std_max_function); }
static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_rax); }
static ByteSize dcp_cpuid4_offset() { return byte_offset_of(CpuidInfo, dcp_cpuid4_rax); }
static ByteSize ext_cpuid1_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1_rax); }
static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_rax); }
static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_rax); }
// Initialization
static void initialize();
// Asserts
static void assert_is_initialized() {
assert(_cpuid_info.std_cpuid1_rax.bits.family != 0, "VM_Version not initialized");
}
//
// Processor family:
// 3 - 386
// 4 - 486
// 5 - Pentium
// 6 - PentiumPro, Pentium II, Celeron, Xeon, Pentium III, Athlon,
// Pentium M, Core Solo, Core Duo, Core2 Duo
// family 6 model: 9, 13, 14, 15
// 0x0f - Pentium 4, Opteron
//
// Note: The cpu family should be used to select between
// instruction sequences which are valid on all Intel
// processors. Use the feature test functions below to
// determine whether a particular instruction is supported.
//
static int cpu_family() { return _cpu;}
static bool is_P6() { return cpu_family() >= 6; }
static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA'
static bool is_intel() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x756e6547; } // 'uneG'
static uint cores_per_cpu() {
uint result = 1;
if (is_intel()) {
result = (_cpuid_info.dcp_cpuid4_rax.bits.cores_per_cpu + 1);
} else if (is_amd()) {
result = (_cpuid_info.ext_cpuid8_rcx.bits.cores_per_cpu + 1);
}
return result;
}
static uint threads_per_core() {
uint result = 1;
if (_cpuid_info.std_cpuid1_rdx.bits.ht != 0) {
result = _cpuid_info.std_cpuid1_rbx.bits.threads_per_cpu /
cores_per_cpu();
}
return result;
}
static intx L1_data_cache_line_size() {
intx result = 0;
if (is_intel()) {
result = (_cpuid_info.dcp_cpuid4_rbx.bits.L1_line_size + 1);
} else if (is_amd()) {
result = _cpuid_info.ext_cpuid5_rcx.bits.L1_line_size;
}
if (result < 32) // not defined ?
result = 32; // 32 bytes by default on x86
return result;
}
//
// Feature identification
//
static bool supports_cpuid() { return _cpuFeatures != 0; }
static bool supports_cmpxchg8() { return (_cpuFeatures & CPU_CX8) != 0; }
static bool supports_cmov() { return (_cpuFeatures & CPU_CMOV) != 0; }
static bool supports_fxsr() { return (_cpuFeatures & CPU_FXSR) != 0; }
static bool supports_ht() { return (_cpuFeatures & CPU_HT) != 0; }
static bool supports_mmx() { return (_cpuFeatures & CPU_MMX) != 0; }
static bool supports_sse() { return (_cpuFeatures & CPU_SSE) != 0; }
static bool supports_sse2() { return (_cpuFeatures & CPU_SSE2) != 0; }
static bool supports_sse3() { return (_cpuFeatures & CPU_SSE3) != 0; }
static bool supports_ssse3() { return (_cpuFeatures & CPU_SSSE3)!= 0; }
static bool supports_sse4_1() { return (_cpuFeatures & CPU_SSE4_1) != 0; }
static bool supports_sse4_2() { return (_cpuFeatures & CPU_SSE4_2) != 0; }
//
// AMD features
//
static bool supports_3dnow() { return (_cpuFeatures & CPU_3DNOW) != 0; }
static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_rdx.bits.mmx_amd != 0; }
static bool supports_3dnow2() { return is_amd() && _cpuid_info.ext_cpuid1_rdx.bits.tdnow2 != 0; }
static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; }
static bool supports_compare_and_exchange() { return true; }
static const char* cpu_features() { return _features_str; }
static intx allocate_prefetch_distance() {
// This method should be called before allocate_prefetch_style().
//
// Hardware prefetching (distance/size in bytes):
// Pentium 3 - 64 / 32
// Pentium 4 - 256 / 128
// Athlon - 64 / 32 ????
// Opteron - 128 / 64 only when 2 sequential cache lines accessed
// Core - 128 / 64
//
// Software prefetching (distance in bytes / instruction with best score):
// Pentium 3 - 128 / prefetchnta
// Pentium 4 - 512 / prefetchnta
// Athlon - 128 / prefetchnta
// Opteron - 256 / prefetchnta
// Core - 256 / prefetchnta
// It will be used only when AllocatePrefetchStyle > 0
intx count = AllocatePrefetchDistance;
if (count < 0) { // default ?
if (is_amd()) { // AMD
if (supports_sse2())
count = 256; // Opteron
else
count = 128; // Athlon
} else { // Intel
if (supports_sse2())
if (cpu_family() == 6) {
count = 256; // Pentium M, Core, Core2
} else {
count = 512; // Pentium 4
}
else
count = 128; // Pentium 3 (and all other old CPUs)
}
}
return count;
}
static intx allocate_prefetch_style() {
assert(AllocatePrefetchStyle >= 0, "AllocatePrefetchStyle should be positive");
// Return 0 if AllocatePrefetchDistance was not defined or
// prefetch instruction is not supported.
return (AllocatePrefetchDistance > 0 &&
(supports_3dnow() || supports_sse())) ? AllocatePrefetchStyle : 0;
}
};

View File

@ -1,419 +0,0 @@
/*
* Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_vm_version_x86_64.cpp.incl"
int VM_Version::_cpu;
int VM_Version::_model;
int VM_Version::_stepping;
int VM_Version::_cpuFeatures;
const char* VM_Version::_features_str = "";
VM_Version::CpuidInfo VM_Version::_cpuid_info = { 0, };
static BufferBlob* stub_blob;
static const int stub_size = 300;
extern "C" {
typedef void (*getPsrInfo_stub_t)(void*);
}
static getPsrInfo_stub_t getPsrInfo_stub = NULL;
class VM_Version_StubGenerator: public StubCodeGenerator {
public:
VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
address generate_getPsrInfo() {
Label std_cpuid1, ext_cpuid1, ext_cpuid5, done;
StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub");
# define __ _masm->
address start = __ pc();
//
// void getPsrInfo(VM_Version::CpuidInfo* cpuid_info);
//
// rcx and rdx are first and second argument registers on windows
__ push(rbp);
__ mov(rbp, c_rarg0); // cpuid_info address
__ push(rbx);
__ push(rsi);
//
// we have a chip which supports the "cpuid" instruction
//
__ xorl(rax, rax);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid0_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ cmpl(rax, 3); // Is cpuid(0x4) supported?
__ jccb(Assembler::belowEqual, std_cpuid1);
//
// cpuid(0x4) Deterministic cache params
//
__ movl(rax, 4);
__ xorl(rcx, rcx); // L1 cache
__ cpuid();
__ push(rax);
__ andl(rax, 0x1f); // Determine if valid cache parameters used
__ orl(rax, rax); // eax[4:0] == 0 indicates invalid cache
__ pop(rax);
__ jccb(Assembler::equal, std_cpuid1);
__ lea(rsi, Address(rbp, in_bytes(VM_Version::dcp_cpuid4_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
//
// Standard cpuid(0x1)
//
__ bind(std_cpuid1);
__ movl(rax, 1);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid1_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
__ movl(rax, 0x80000000);
__ cpuid();
__ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported?
__ jcc(Assembler::belowEqual, done);
__ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported?
__ jccb(Assembler::belowEqual, ext_cpuid1);
__ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported?
__ jccb(Assembler::belowEqual, ext_cpuid5);
//
// Extended cpuid(0x80000008)
//
__ movl(rax, 0x80000008);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
//
// Extended cpuid(0x80000005)
//
__ bind(ext_cpuid5);
__ movl(rax, 0x80000005);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid5_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
//
// Extended cpuid(0x80000001)
//
__ bind(ext_cpuid1);
__ movl(rax, 0x80000001);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1_offset())));
__ movl(Address(rsi, 0), rax);
__ movl(Address(rsi, 4), rbx);
__ movl(Address(rsi, 8), rcx);
__ movl(Address(rsi,12), rdx);
//
// return
//
__ bind(done);
__ pop(rsi);
__ pop(rbx);
__ pop(rbp);
__ ret(0);
# undef __
return start;
};
};
void VM_Version::get_processor_features() {
_logical_processors_per_package = 1;
// Get raw processor info
getPsrInfo_stub(&_cpuid_info);
assert_is_initialized();
_cpu = extended_cpu_family();
_model = extended_cpu_model();
_stepping = cpu_stepping();
_cpuFeatures = feature_flags();
// Logical processors are only available on P4s and above,
// and only if hyperthreading is available.
_logical_processors_per_package = logical_processor_count();
_supports_cx8 = supports_cmpxchg8();
// OS should support SSE for x64 and hardware should support at least SSE2.
if (!VM_Version::supports_sse2()) {
vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported");
}
if (UseSSE < 4) {
_cpuFeatures &= ~CPU_SSE4_1;
_cpuFeatures &= ~CPU_SSE4_2;
}
if (UseSSE < 3) {
_cpuFeatures &= ~CPU_SSE3;
_cpuFeatures &= ~CPU_SSSE3;
_cpuFeatures &= ~CPU_SSE4A;
}
if (UseSSE < 2)
_cpuFeatures &= ~CPU_SSE2;
if (UseSSE < 1)
_cpuFeatures &= ~CPU_SSE;
if (logical_processors_per_package() == 1) {
// HT processor could be installed on a system which doesn't support HT.
_cpuFeatures &= ~CPU_HT;
}
char buf[256];
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping,
(supports_cmov() ? ", cmov" : ""),
(supports_cmpxchg8() ? ", cx8" : ""),
(supports_fxsr() ? ", fxsr" : ""),
(supports_mmx() ? ", mmx" : ""),
(supports_sse() ? ", sse" : ""),
(supports_sse2() ? ", sse2" : ""),
(supports_sse3() ? ", sse3" : ""),
(supports_ssse3()? ", ssse3": ""),
(supports_sse4_1() ? ", sse4.1" : ""),
(supports_sse4_2() ? ", sse4.2" : ""),
(supports_mmx_ext() ? ", mmxext" : ""),
(supports_3dnow() ? ", 3dnow" : ""),
(supports_3dnow2() ? ", 3dnowext" : ""),
(supports_sse4a() ? ", sse4a": ""),
(supports_ht() ? ", ht": ""));
_features_str = strdup(buf);
// UseSSE is set to the smaller of what hardware supports and what
// the command line requires. I.e., you cannot set UseSSE to 2 on
// older Pentiums which do not support it.
if( UseSSE > 4 ) UseSSE=4;
if( UseSSE < 0 ) UseSSE=0;
if( !supports_sse4_1() ) // Drop to 3 if no SSE4 support
UseSSE = MIN2((intx)3,UseSSE);
if( !supports_sse3() ) // Drop to 2 if no SSE3 support
UseSSE = MIN2((intx)2,UseSSE);
if( !supports_sse2() ) // Drop to 1 if no SSE2 support
UseSSE = MIN2((intx)1,UseSSE);
if( !supports_sse () ) // Drop to 0 if no SSE support
UseSSE = 0;
// On new cpus instructions which update whole XMM register should be used
// to prevent partial register stall due to dependencies on high half.
//
// UseXmmLoadAndClearUpper == true --> movsd(xmm, mem)
// UseXmmLoadAndClearUpper == false --> movlpd(xmm, mem)
// UseXmmRegToRegMoveAll == true --> movaps(xmm, xmm), movapd(xmm, xmm).
// UseXmmRegToRegMoveAll == false --> movss(xmm, xmm), movsd(xmm, xmm).
if( is_amd() ) { // AMD cpus specific settings
if( FLAG_IS_DEFAULT(UseAddressNop) ) {
// Use it on all AMD cpus starting from Opteron (don't need
// a cpu check since only Opteron and new cpus support 64-bits mode).
UseAddressNop = true;
}
if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) {
if( supports_sse4a() ) {
UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron
} else {
UseXmmLoadAndClearUpper = false;
}
}
if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) {
if( supports_sse4a() ) {
UseXmmRegToRegMoveAll = true; // use movaps, movapd only on '10h'
} else {
UseXmmRegToRegMoveAll = false;
}
}
if( FLAG_IS_DEFAULT(UseXmmI2F) ) {
if( supports_sse4a() ) {
UseXmmI2F = true;
} else {
UseXmmI2F = false;
}
}
if( FLAG_IS_DEFAULT(UseXmmI2D) ) {
if( supports_sse4a() ) {
UseXmmI2D = true;
} else {
UseXmmI2D = false;
}
}
}
if( is_intel() ) { // Intel cpus specific settings
if( FLAG_IS_DEFAULT(UseStoreImmI16) ) {
UseStoreImmI16 = false; // don't use it on Intel cpus
}
if( FLAG_IS_DEFAULT(UseAddressNop) ) {
// Use it on all Intel cpus starting from PentiumPro
// (don't need a cpu check since only new cpus support 64-bits mode).
UseAddressNop = true;
}
if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) {
UseXmmLoadAndClearUpper = true; // use movsd on all Intel cpus
}
if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) {
if( supports_sse3() ) {
UseXmmRegToRegMoveAll = true; // use movaps, movapd on new Intel cpus
} else {
UseXmmRegToRegMoveAll = false;
}
}
if( cpu_family() == 6 && supports_sse3() ) { // New Intel cpus
#ifdef COMPILER2
if( FLAG_IS_DEFAULT(MaxLoopPad) ) {
// For new Intel cpus do the next optimization:
// don't align the beginning of a loop if there are enough instructions
// left (NumberOfLoopInstrToAlign defined in c2_globals.hpp)
// in current fetch line (OptoLoopAlignment) or the padding
// is big (> MaxLoopPad).
// Set MaxLoopPad to 11 for new Intel cpus to reduce number of
// generated NOP instructions. 11 is the largest size of one
// address NOP instruction '0F 1F' (see Assembler::nop(i)).
MaxLoopPad = 11;
}
#endif // COMPILER2
if( FLAG_IS_DEFAULT(UseXMMForArrayCopy) ) {
UseXMMForArrayCopy = true; // use SSE2 movq on new Intel cpus
}
if( supports_sse4_2() && supports_ht() ) { // Newest Intel cpus
if( FLAG_IS_DEFAULT(UseUnalignedLoadStores) && UseXMMForArrayCopy ) {
UseUnalignedLoadStores = true; // use movdqu on newest Intel cpus
}
}
}
}
assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value");
assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value");
// set valid Prefetch instruction
if( ReadPrefetchInstr < 0 ) ReadPrefetchInstr = 0;
if( ReadPrefetchInstr > 3 ) ReadPrefetchInstr = 3;
if( ReadPrefetchInstr == 3 && !supports_3dnow() ) ReadPrefetchInstr = 0;
if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0;
if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3;
if( AllocatePrefetchInstr == 3 && !supports_3dnow() ) AllocatePrefetchInstr=0;
// Allocation prefetch settings
intx cache_line_size = L1_data_cache_line_size();
if( cache_line_size > AllocatePrefetchStepSize )
AllocatePrefetchStepSize = cache_line_size;
if( FLAG_IS_DEFAULT(AllocatePrefetchLines) )
AllocatePrefetchLines = 3; // Optimistic value
assert(AllocatePrefetchLines > 0, "invalid value");
if( AllocatePrefetchLines < 1 ) // set valid value in product VM
AllocatePrefetchLines = 1; // Conservative value
AllocatePrefetchDistance = allocate_prefetch_distance();
AllocatePrefetchStyle = allocate_prefetch_style();
if( AllocatePrefetchStyle == 2 && is_intel() &&
cpu_family() == 6 && supports_sse3() ) { // watermark prefetching on Core
AllocatePrefetchDistance = 384;
}
assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value");
// Prefetch settings
PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes();
PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes();
PrefetchFieldsAhead = prefetch_fields_ahead();
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Logical CPUs per core: %u",
logical_processors_per_package());
tty->print_cr("UseSSE=%d",UseSSE);
tty->print("Allocation: ");
if (AllocatePrefetchStyle <= 0) {
tty->print_cr("no prefetching");
} else {
if (AllocatePrefetchInstr == 0) {
tty->print("PREFETCHNTA");
} else if (AllocatePrefetchInstr == 1) {
tty->print("PREFETCHT0");
} else if (AllocatePrefetchInstr == 2) {
tty->print("PREFETCHT2");
} else if (AllocatePrefetchInstr == 3) {
tty->print("PREFETCHW");
}
if (AllocatePrefetchLines > 1) {
tty->print_cr(" %d, %d lines with step %d bytes", AllocatePrefetchDistance, AllocatePrefetchLines, AllocatePrefetchStepSize);
} else {
tty->print_cr(" %d, one line", AllocatePrefetchDistance);
}
}
if (PrefetchCopyIntervalInBytes > 0) {
tty->print_cr("PrefetchCopyIntervalInBytes %d", PrefetchCopyIntervalInBytes);
}
if (PrefetchScanIntervalInBytes > 0) {
tty->print_cr("PrefetchScanIntervalInBytes %d", PrefetchScanIntervalInBytes);
}
if (PrefetchFieldsAhead > 0) {
tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead);
}
}
#endif // !PRODUCT
}
void VM_Version::initialize() {
ResourceMark rm;
// Making this stub must be FIRST use of assembler
stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size);
if (stub_blob == NULL) {
vm_exit_during_initialization("Unable to allocate getPsrInfo_stub");
}
CodeBuffer c(stub_blob->instructions_begin(),
stub_blob->instructions_size());
VM_Version_StubGenerator g(&c);
getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t,
g.generate_getPsrInfo());
get_processor_features();
}

View File

@ -34,10 +34,16 @@
extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
#endif
// used by compiler only; may use only caller saved registers rax, rbx, rcx.
// rdx holds first int arg, rsi, rdi, rbp are callee-save & must be preserved.
// Leave receiver in rcx; required behavior when +OptoArgsInRegisters
// is modifed to put first oop in rcx.
// These stubs are used by the compiler only.
// Argument registers, which must be preserved:
// rcx - receiver (always first argument)
// rdx - second argument (if any)
// Other registers that might be usable:
// rax - inline cache register (is interface for itable stub)
// rbx - method (used when calling out to interpreter)
// Available now, but may become callee-save at some point:
// rsi, rdi
// Note that rax and rdx are also used for return values.
//
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
const int i486_code_length = VtableStub::pd_code_size_limit(true);
@ -94,16 +100,25 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
__ jmp( Address(method, methodOopDesc::from_compiled_offset()));
masm->flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
vtable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
// Note well: pd_code_size_limit is the absolute minimum we can get away with. If you
// add code here, bump the code stub size returned by pd_code_size_limit!
const int i486_code_length = VtableStub::pd_code_size_limit(false);
VtableStub* s = new(i486_code_length) VtableStub(false, vtable_index);
VtableStub* s = new(i486_code_length) VtableStub(false, itable_index);
ResourceMark rm;
CodeBuffer cb(s->entry_point(), i486_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
@ -123,50 +138,19 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
// get receiver klass (also an implicit null-check)
address npe_addr = __ pc();
__ movptr(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
__ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes()));
__ mov(rsi, rbx); // Save klass in free register
// Most registers are in use, so save a few
__ push(rdx);
// compute itable entry offset (in words)
const int base = instanceKlass::vtable_start_offset() * wordSize;
assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
__ movl(rdx, Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
__ lea(rbx, Address(rbx, rdx, Address::times_ptr, base));
if (HeapWordsPerLong > 1) {
// Round up to align_object_offset boundary
__ round_to(rbx, BytesPerLong);
}
Label hit, next, entry, throw_icce;
__ jmpb(entry);
__ bind(next);
__ addptr(rbx, itableOffsetEntry::size() * wordSize);
__ bind(entry);
// If the entry is NULL then we've reached the end of the table
// without finding the expected interface, so throw an exception
__ movptr(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
__ testptr(rdx, rdx);
__ jcc(Assembler::zero, throw_icce);
__ cmpptr(rax, rdx);
__ jcc(Assembler::notEqual, next);
// We found a hit, move offset into rbx,
__ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
// Compute itableMethodEntry.
const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
// Most registers are in use; we'll use rax, rbx, rsi, rdi
// (If we need to make rsi, rdi callee-save, do a push/pop here.)
const Register method = rbx;
Label throw_icce;
// Get methodOop and entrypoint for compiler
const Register method = rbx;
__ movptr(method, Address(rsi, rdx, Address::times_1, method_offset));
// Restore saved register, before possible trap.
__ pop(rdx);
__ lookup_interface_method(// inputs: rec. class, interface, itable index
rsi, rax, itable_index,
// outputs: method, scan temp. reg
method, rdi,
throw_icce);
// method (rbx): methodOop
// rcx: receiver
@ -187,12 +171,15 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
__ jmp(Address(method, methodOopDesc::from_compiled_offset()));
__ bind(throw_icce);
// Restore saved register
__ pop(rdx);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
masm->flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
itable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
@ -207,7 +194,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
} else {
// Itable stub size
return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0);
}
}

View File

@ -98,17 +98,26 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
__ jmp( Address(rbx, methodOopDesc::from_compiled_offset()));
__ flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
vtable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
return s;
}
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
VtableStub* VtableStubs::create_itable_stub(int itable_index) {
// Note well: pd_code_size_limit is the absolute minimum we can get
// away with. If you add code here, bump the code stub size
// returned by pd_code_size_limit!
const int amd64_code_length = VtableStub::pd_code_size_limit(false);
VtableStub* s = new(amd64_code_length) VtableStub(false, vtable_index);
VtableStub* s = new(amd64_code_length) VtableStub(false, itable_index);
ResourceMark rm;
CodeBuffer cb(s->entry_point(), amd64_code_length);
MacroAssembler* masm = new MacroAssembler(&cb);
@ -131,68 +140,28 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
// get receiver klass (also an implicit null-check)
address npe_addr = __ pc();
__ load_klass(rbx, j_rarg0);
// Most registers are in use; we'll use rax, rbx, r10, r11
// (various calling sequences use r[cd]x, r[sd]i, r[89]; stay away from them)
__ load_klass(r10, j_rarg0);
// If we take a trap while this arg is on the stack we will not
// be able to walk the stack properly. This is not an issue except
// when there are mistakes in this assembly code that could generate
// a spurious fault. Ask me how I know...
__ push(j_rarg1); // Most registers are in use, so save one
// compute itable entry offset (in words)
const int base = instanceKlass::vtable_start_offset() * wordSize;
assert(vtableEntry::size() * wordSize == 8,
"adjust the scaling in the code below");
// Get length of vtable
__ movl(j_rarg1,
Address(rbx, instanceKlass::vtable_length_offset() * wordSize));
__ lea(rbx, Address(rbx, j_rarg1, Address::times_8, base));
if (HeapWordsPerLong > 1) {
// Round up to align_object_offset boundary
__ round_to(rbx, BytesPerLong);
}
Label hit, next, entry, throw_icce;
__ jmpb(entry);
__ bind(next);
__ addptr(rbx, itableOffsetEntry::size() * wordSize);
__ bind(entry);
// If the entry is NULL then we've reached the end of the table
// without finding the expected interface, so throw an exception
__ movptr(j_rarg1, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
__ testptr(j_rarg1, j_rarg1);
__ jcc(Assembler::zero, throw_icce);
__ cmpptr(rax, j_rarg1);
__ jccb(Assembler::notEqual, next);
// We found a hit, move offset into j_rarg1
__ movl(j_rarg1, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
// Compute itableMethodEntry
const int method_offset =
(itableMethodEntry::size() * wordSize * vtable_index) +
itableMethodEntry::method_offset_in_bytes();
const Register method = rbx;
Label throw_icce;
// Get methodOop and entrypoint for compiler
// Get klass pointer again
__ load_klass(rax, j_rarg0);
const Register method = rbx;
__ movptr(method, Address(rax, j_rarg1, Address::times_1, method_offset));
// Restore saved register, before possible trap.
__ pop(j_rarg1);
__ lookup_interface_method(// inputs: rec. class, interface, itable index
r10, rax, itable_index,
// outputs: method, scan temp. reg
method, r11,
throw_icce);
// method (rbx): methodOop
// j_rarg0: receiver
#ifdef ASSERT
if (DebugVtables) {
Label L2;
@ -211,12 +180,16 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
__ jmp(Address(method, methodOopDesc::from_compiled_offset()));
__ bind(throw_icce);
// Restore saved register
__ pop(j_rarg1);
__ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
__ flush();
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
itable_index, s->entry_point(),
(int)(s->code_end() - s->entry_point()),
(int)(s->code_end() - __ pc()));
}
guarantee(__ pc() <= s->code_end(), "overflowed buffer");
s->set_exception_points(npe_addr, ame_addr);
@ -230,7 +203,7 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
(UseCompressedOops ? 16 : 0); // 1 leaq can be 3 bytes + 1 long
} else {
// Itable stub size
return (DebugVtables ? 636 : 72) + (CountCompiledCalls ? 13 : 0) +
return (DebugVtables ? 512 : 72) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedOops ? 32 : 0); // 2 leaqs
}
}

View File

@ -130,7 +130,7 @@ reg_def XMM7b( SOC, SOC, Op_RegF, 7, xmm7->as_VMReg()->next());
// allocation. Highest priority is first. A useful heuristic is to
// give registers a low priority when they are required by machine
// instructions, like EAX and EDX. Registers which are used as
// pairs must fall on an even boundry (witness the FPR#L's in this list).
// pairs must fall on an even boundary (witness the FPR#L's in this list).
// For the Intel integer registers, the equivalent Long pairs are
// EDX:EAX, EBX:ECX, and EDI:EBP.
alloc_class chunk0( ECX, EBX, EBP, EDI, EAX, EDX, ESI, ESP,
@ -3126,14 +3126,12 @@ encode %{
enc_class movq_ld(regXD dst, memory mem) %{
MacroAssembler _masm(&cbuf);
Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
__ movq(as_XMMRegister($dst$$reg), madr);
__ movq($dst$$XMMRegister, $mem$$Address);
%}
enc_class movq_st(memory mem, regXD src) %{
MacroAssembler _masm(&cbuf);
Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
__ movq(madr, as_XMMRegister($src$$reg));
__ movq($mem$$Address, $src$$XMMRegister);
%}
enc_class pshufd_8x8(regX dst, regX src) %{
@ -3751,8 +3749,8 @@ encode %{
masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
// Load first characters
masm.load_unsigned_word(rcx, Address(rbx, 0));
masm.load_unsigned_word(rdi, Address(rax, 0));
masm.load_unsigned_short(rcx, Address(rbx, 0));
masm.load_unsigned_short(rdi, Address(rax, 0));
// Compare first characters
masm.subl(rcx, rdi);
@ -3782,8 +3780,8 @@ encode %{
// Compare the rest of the characters
masm.bind(WHILE_HEAD_LABEL);
masm.load_unsigned_word(rcx, Address(rbx, rsi, Address::times_2, 0));
masm.load_unsigned_word(rdi, Address(rax, rsi, Address::times_2, 0));
masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
masm.subl(rcx, rdi);
masm.jcc(Assembler::notZero, POP_LABEL);
masm.incrementl(rsi);
@ -3840,8 +3838,8 @@ encode %{
masm.jcc(Assembler::zero, COMPARE_LOOP_HDR);
// Compare 2-byte "tail" at end of arrays
masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
masm.load_unsigned_short(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
masm.load_unsigned_short(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
masm.cmpl(tmp1Reg, tmp2Reg);
masm.jcc(Assembler::notEqual, FALSE_LABEL);
masm.testl(resultReg, resultReg);
@ -5857,7 +5855,7 @@ operand cmpOp_commute() %{
//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used as to simplify
// instruction definitions by not requiring the AD writer to specify seperate
// instruction definitions by not requiring the AD writer to specify separate
// instructions for every form of operand when the instruction accepts
// multiple operand types with the same basic encoding and format. The classic
// case of this is memory operands.
@ -6396,21 +6394,94 @@ instruct loadB(xRegI dst, memory mem) %{
match(Set dst (LoadB mem));
ins_cost(125);
format %{ "MOVSX8 $dst,$mem" %}
opcode(0xBE, 0x0F);
ins_encode( OpcS, OpcP, RegMem(dst,mem));
ins_pipe( ialu_reg_mem );
format %{ "MOVSX8 $dst,$mem\t# byte" %}
ins_encode %{
__ movsbl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Byte (8bit UNsigned)
instruct loadUB(xRegI dst, memory mem, immI_255 bytemask) %{
match(Set dst (AndI (LoadB mem) bytemask));
// Load Byte (8bit signed) into Long Register
instruct loadB2L(eRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadB mem)));
ins_cost(375);
format %{ "MOVSX8 $dst.lo,$mem\t# byte -> long\n\t"
"MOV $dst.hi,$dst.lo\n\t"
"SAR $dst.hi,7" %}
ins_encode %{
__ movsbl($dst$$Register, $mem$$Address);
__ movl(HIGH_FROM_LOW($dst$$Register), $dst$$Register); // This is always a different register.
__ sarl(HIGH_FROM_LOW($dst$$Register), 7); // 24+1 MSB are already signed extended.
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Byte (8bit UNsigned)
instruct loadUB(xRegI dst, memory mem) %{
match(Set dst (LoadUB mem));
ins_cost(125);
format %{ "MOVZX8 $dst,$mem" %}
opcode(0xB6, 0x0F);
ins_encode( OpcS, OpcP, RegMem(dst,mem));
ins_pipe( ialu_reg_mem );
format %{ "MOVZX8 $dst,$mem\t# ubyte -> int" %}
ins_encode %{
__ movzbl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Byte (8 bit UNsigned) into Long Register
instruct loadUB2L(eRegL dst, memory mem)
%{
match(Set dst (ConvI2L (LoadUB mem)));
ins_cost(250);
format %{ "MOVZX8 $dst.lo,$mem\t# ubyte -> long\n\t"
"XOR $dst.hi,$dst.hi" %}
ins_encode %{
__ movzbl($dst$$Register, $mem$$Address);
__ xorl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register));
%}
ins_pipe(ialu_reg_mem);
%}
// Load Short (16bit signed)
instruct loadS(eRegI dst, memory mem) %{
match(Set dst (LoadS mem));
ins_cost(125);
format %{ "MOVSX $dst,$mem\t# short" %}
ins_encode %{
__ movswl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Short (16bit signed) into Long Register
instruct loadS2L(eRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadS mem)));
ins_cost(375);
format %{ "MOVSX $dst.lo,$mem\t# short -> long\n\t"
"MOV $dst.hi,$dst.lo\n\t"
"SAR $dst.hi,15" %}
ins_encode %{
__ movswl($dst$$Register, $mem$$Address);
__ movl(HIGH_FROM_LOW($dst$$Register), $dst$$Register); // This is always a different register.
__ sarl(HIGH_FROM_LOW($dst$$Register), 15); // 16+1 MSB are already signed extended.
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Short/Char (16bit unsigned)
@ -6418,10 +6489,30 @@ instruct loadUS(eRegI dst, memory mem) %{
match(Set dst (LoadUS mem));
ins_cost(125);
format %{ "MOVZX $dst,$mem" %}
opcode(0xB7, 0x0F);
ins_encode( OpcS, OpcP, RegMem(dst,mem));
ins_pipe( ialu_reg_mem );
format %{ "MOVZX $dst,$mem\t# ushort/char -> int" %}
ins_encode %{
__ movzwl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Short/Char (16 bit UNsigned) into Long Register
instruct loadUS2L(eRegL dst, memory mem)
%{
match(Set dst (ConvI2L (LoadUS mem)));
ins_cost(250);
format %{ "MOVZX $dst.lo,$mem\t# ushort/char -> long\n\t"
"XOR $dst.hi,$dst.hi" %}
ins_encode %{
__ movzwl($dst$$Register, $mem$$Address);
__ xorl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register));
%}
ins_pipe(ialu_reg_mem);
%}
// Load Integer
@ -6429,10 +6520,47 @@ instruct loadI(eRegI dst, memory mem) %{
match(Set dst (LoadI mem));
ins_cost(125);
format %{ "MOV $dst,$mem" %}
opcode(0x8B);
ins_encode( OpcP, RegMem(dst,mem));
ins_pipe( ialu_reg_mem );
format %{ "MOV $dst,$mem\t# int" %}
ins_encode %{
__ movl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Integer into Long Register
instruct loadI2L(eRegL dst, memory mem) %{
match(Set dst (ConvI2L (LoadI mem)));
ins_cost(375);
format %{ "MOV $dst.lo,$mem\t# int -> long\n\t"
"MOV $dst.hi,$dst.lo\n\t"
"SAR $dst.hi,31" %}
ins_encode %{
__ movl($dst$$Register, $mem$$Address);
__ movl(HIGH_FROM_LOW($dst$$Register), $dst$$Register); // This is always a different register.
__ sarl(HIGH_FROM_LOW($dst$$Register), 31);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Integer into Long Register
instruct loadUI2L(eRegL dst, memory mem) %{
match(Set dst (LoadUI2L mem));
ins_cost(250);
format %{ "MOV $dst.lo,$mem\t# uint -> long\n\t"
"XOR $dst.hi,$dst.hi" %}
ins_encode %{
__ movl($dst$$Register, $mem$$Address);
__ xorl(HIGH_FROM_LOW($dst$$Register), HIGH_FROM_LOW($dst$$Register));
%}
ins_pipe(ialu_reg_mem);
%}
// Load Long. Cannot clobber address while loading, so restrict address
@ -6442,11 +6570,17 @@ instruct loadL(eRegL dst, load_long_memory mem) %{
match(Set dst (LoadL mem));
ins_cost(250);
format %{ "MOV $dst.lo,$mem\n\t"
format %{ "MOV $dst.lo,$mem\t# long\n\t"
"MOV $dst.hi,$mem+4" %}
opcode(0x8B, 0x8B);
ins_encode( OpcP, RegMem(dst,mem), OpcS, RegMem_Hi(dst,mem));
ins_pipe( ialu_reg_long_mem );
ins_encode %{
Address Amemlo = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp, false);
Address Amemhi = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp + 4, false);
__ movl($dst$$Register, Amemlo);
__ movl(HIGH_FROM_LOW($dst$$Register), Amemhi);
%}
ins_pipe(ialu_reg_long_mem);
%}
// Volatile Load Long. Must be atomic, so do 64-bit FILD
@ -6521,17 +6655,6 @@ instruct loadKlass(eRegP dst, memory mem) %{
ins_pipe( ialu_reg_mem );
%}
// Load Short (16bit signed)
instruct loadS(eRegI dst, memory mem) %{
match(Set dst (LoadS mem));
ins_cost(125);
format %{ "MOVSX $dst,$mem" %}
opcode(0xBF, 0x0F);
ins_encode( OpcS, OpcP, RegMem(dst,mem));
ins_pipe( ialu_reg_mem );
%}
// Load Double
instruct loadD(regD dst, memory mem) %{
predicate(UseSSE<=1);
@ -7957,7 +8080,7 @@ instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlags
__ xchgl(as_Register(EBX_enc), as_Register(ECX_enc));
if( os::is_MP() )
__ lock();
__ cmpxchg8(Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp));
__ cmpxchg8($mem$$Address);
__ xchgl(as_Register(EBX_enc), as_Register(ECX_enc));
%}
ins_pipe( pipe_cmpxchg );
@ -11467,6 +11590,7 @@ instruct convI2X_reg(regX dst, eRegI src) %{
instruct convI2L_reg( eRegL dst, eRegI src, eFlagsReg cr) %{
match(Set dst (ConvI2L src));
effect(KILL cr);
ins_cost(375);
format %{ "MOV $dst.lo,$src\n\t"
"MOV $dst.hi,$src\n\t"
"SAR $dst.hi,31" %}
@ -11478,6 +11602,7 @@ instruct convI2L_reg( eRegL dst, eRegI src, eFlagsReg cr) %{
instruct convI2L_reg_zex(eRegL dst, eRegI src, immL_32bits mask, eFlagsReg flags ) %{
match(Set dst (AndL (ConvI2L src) mask) );
effect( KILL flags );
ins_cost(250);
format %{ "MOV $dst.lo,$src\n\t"
"XOR $dst.hi,$dst.hi" %}
opcode(0x33); // XOR
@ -11489,6 +11614,7 @@ instruct convI2L_reg_zex(eRegL dst, eRegI src, immL_32bits mask, eFlagsReg flags
instruct zerox_long(eRegL dst, eRegL src, immL_32bits mask, eFlagsReg flags ) %{
match(Set dst (AndL src mask) );
effect( KILL flags );
ins_cost(250);
format %{ "MOV $dst.lo,$src.lo\n\t"
"XOR $dst.hi,$dst.hi\n\t" %}
opcode(0x33); // XOR
@ -13220,7 +13346,7 @@ instruct safePoint_poll(eFlagsReg cr) %{
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.
//
// peepmatch ( root_instr_name [preceeding_instruction]* );
// peepmatch ( root_instr_name [preceding_instruction]* );
//
// peepconstraint %{
// (instruction_number.operand_name relational_op instruction_number.operand_name

View File

@ -3462,14 +3462,12 @@ encode %{
enc_class movq_ld(regD dst, memory mem) %{
MacroAssembler _masm(&cbuf);
Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
__ movq(as_XMMRegister($dst$$reg), madr);
__ movq($dst$$XMMRegister, $mem$$Address);
%}
enc_class movq_st(memory mem, regD src) %{
MacroAssembler _masm(&cbuf);
Address madr = Address::make_raw($mem$$base, $mem$$index, $mem$$scale, $mem$$disp);
__ movq(madr, as_XMMRegister($src$$reg));
__ movq($mem$$Address, $src$$XMMRegister);
%}
enc_class pshufd_8x8(regF dst, regF src) %{
@ -3765,8 +3763,8 @@ encode %{
masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL);
// Load first characters
masm.load_unsigned_word(rcx, Address(rbx, 0));
masm.load_unsigned_word(rdi, Address(rax, 0));
masm.load_unsigned_short(rcx, Address(rbx, 0));
masm.load_unsigned_short(rdi, Address(rax, 0));
// Compare first characters
masm.subl(rcx, rdi);
@ -3796,8 +3794,8 @@ encode %{
// Compare the rest of the characters
masm.bind(WHILE_HEAD_LABEL);
masm.load_unsigned_word(rcx, Address(rbx, rsi, Address::times_2, 0));
masm.load_unsigned_word(rdi, Address(rax, rsi, Address::times_2, 0));
masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0));
masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0));
masm.subl(rcx, rdi);
masm.jcc(Assembler::notZero, POP_LABEL);
masm.increment(rsi);
@ -3854,8 +3852,8 @@ encode %{
masm.jcc(Assembler::zero, COMPARE_LOOP_HDR);
// Compare 2-byte "tail" at end of arrays
masm.load_unsigned_word(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
masm.load_unsigned_word(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
masm.load_unsigned_short(tmp1Reg, Address(ary1Reg, resultReg, Address::times_4, base_offset));
masm.load_unsigned_short(tmp2Reg, Address(ary2Reg, resultReg, Address::times_4, base_offset));
masm.cmpl(tmp1Reg, tmp2Reg);
masm.jcc(Assembler::notEqual, FALSE_LABEL);
masm.testl(resultReg, resultReg);
@ -5483,7 +5481,7 @@ operand cmpOpUCF2() %{
//----------OPERAND CLASSES----------------------------------------------------
// Operand Classes are groups of operands that are used as to simplify
// instruction definitions by not requiring the AD writer to specify seperate
// instruction definitions by not requiring the AD writer to specify separate
// instructions for every form of operand when the instruction accepts
// multiple operand types with the same basic encoding and format. The classic
// case of this is memory operands.
@ -6031,70 +6029,88 @@ instruct loadB(rRegI dst, memory mem)
ins_cost(125);
format %{ "movsbl $dst, $mem\t# byte" %}
opcode(0x0F, 0xBE);
ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
ins_encode %{
__ movsbl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Byte (8 bit signed) into long
// instruct loadB2L(rRegL dst, memory mem)
// %{
// match(Set dst (ConvI2L (LoadB mem)));
// ins_cost(125);
// format %{ "movsbq $dst, $mem\t# byte -> long" %}
// opcode(0x0F, 0xBE);
// ins_encode(REX_reg_mem_wide(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
// ins_pipe(ialu_reg_mem);
// %}
// Load Byte (8 bit UNsigned)
instruct loadUB(rRegI dst, memory mem, immI_255 bytemask)
// Load Byte (8 bit signed) into Long Register
instruct loadB2L(rRegL dst, memory mem)
%{
match(Set dst (AndI (LoadB mem) bytemask));
match(Set dst (ConvI2L (LoadB mem)));
ins_cost(125);
format %{ "movsbq $dst, $mem\t# byte -> long" %}
ins_encode %{
__ movsbq($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Byte (8 bit UNsigned)
instruct loadUB(rRegI dst, memory mem)
%{
match(Set dst (LoadUB mem));
ins_cost(125);
format %{ "movzbl $dst, $mem\t# ubyte" %}
opcode(0x0F, 0xB6);
ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
ins_encode %{
__ movzbl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Byte (8 bit UNsigned) into long
// instruct loadUB2L(rRegL dst, memory mem, immI_255 bytemask)
// %{
// match(Set dst (ConvI2L (AndI (LoadB mem) bytemask)));
// Load Unsigned Byte (8 bit UNsigned) into Long Register
instruct loadUB2L(rRegL dst, memory mem)
%{
match(Set dst (ConvI2L (LoadUB mem)));
// ins_cost(125);
// format %{ "movzbl $dst, $mem\t# ubyte -> long" %}
// opcode(0x0F, 0xB6);
// ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
// ins_pipe(ialu_reg_mem);
// %}
ins_cost(125);
format %{ "movzbq $dst, $mem\t# ubyte -> long" %}
ins_encode %{
__ movzbq($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Short (16 bit signed)
instruct loadS(rRegI dst, memory mem)
%{
match(Set dst (LoadS mem));
ins_cost(125); // XXX
ins_cost(125);
format %{ "movswl $dst, $mem\t# short" %}
opcode(0x0F, 0xBF);
ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
ins_encode %{
__ movswl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Short (16 bit signed) into long
// instruct loadS2L(rRegL dst, memory mem)
// %{
// match(Set dst (ConvI2L (LoadS mem)));
// Load Short (16 bit signed) into Long Register
instruct loadS2L(rRegL dst, memory mem)
%{
match(Set dst (ConvI2L (LoadS mem)));
// ins_cost(125); // XXX
// format %{ "movswq $dst, $mem\t# short -> long" %}
// opcode(0x0F, 0xBF);
// ins_encode(REX_reg_mem_wide(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
// ins_pipe(ialu_reg_mem);
// %}
ins_cost(125);
format %{ "movswq $dst, $mem\t# short -> long" %}
ins_encode %{
__ movswq($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Short/Char (16 bit UNsigned)
instruct loadUS(rRegI dst, memory mem)
@ -6103,32 +6119,71 @@ instruct loadUS(rRegI dst, memory mem)
ins_cost(125);
format %{ "movzwl $dst, $mem\t# ushort/char" %}
opcode(0x0F, 0xB7);
ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
ins_encode %{
__ movzwl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Short/Char (16 bit UNsigned) into long
// instruct loadUS2L(rRegL dst, memory mem)
// %{
// match(Set dst (ConvI2L (LoadUS mem)));
// Load Unsigned Short/Char (16 bit UNsigned) into Long Register
instruct loadUS2L(rRegL dst, memory mem)
%{
match(Set dst (ConvI2L (LoadUS mem)));
// ins_cost(125);
// format %{ "movzwl $dst, $mem\t# ushort/char -> long" %}
// opcode(0x0F, 0xB7);
// ins_encode(REX_reg_mem(dst, mem), OpcP, OpcS, reg_mem(dst, mem));
// ins_pipe(ialu_reg_mem);
// %}
ins_cost(125);
format %{ "movzwq $dst, $mem\t# ushort/char -> long" %}
ins_encode %{
__ movzwq($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Integer
instruct loadI(rRegI dst, memory mem)
%{
match(Set dst (LoadI mem));
ins_cost(125); // XXX
ins_cost(125);
format %{ "movl $dst, $mem\t# int" %}
opcode(0x8B);
ins_encode(REX_reg_mem(dst, mem), OpcP, reg_mem(dst, mem));
ins_encode %{
__ movl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Integer into Long Register
instruct loadI2L(rRegL dst, memory mem)
%{
match(Set dst (ConvI2L (LoadI mem)));
ins_cost(125);
format %{ "movslq $dst, $mem\t# int -> long" %}
ins_encode %{
__ movslq($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
// Load Unsigned Integer into Long Register
instruct loadUI2L(rRegL dst, memory mem)
%{
match(Set dst (LoadUI2L mem));
ins_cost(125);
format %{ "movl $dst, $mem\t# uint -> long" %}
ins_encode %{
__ movl($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
@ -6137,10 +6192,13 @@ instruct loadL(rRegL dst, memory mem)
%{
match(Set dst (LoadL mem));
ins_cost(125); // XXX
ins_cost(125);
format %{ "movq $dst, $mem\t# long" %}
opcode(0x8B);
ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem));
ins_encode %{
__ movq($dst$$Register, $mem$$Address);
%}
ins_pipe(ialu_reg_mem); // XXX
%}
@ -8363,7 +8421,7 @@ instruct divModL_rReg_divmod(rax_RegL rax, rdx_RegL rdx, no_rax_rdx_RegL div,
//----------- DivL-By-Constant-Expansions--------------------------------------
// DivI cases are handled by the compiler
// Magic constant, reciprical of 10
// Magic constant, reciprocal of 10
instruct loadConL_0x6666666666666667(rRegL dst)
%{
effect(DEF dst);
@ -10804,16 +10862,6 @@ instruct convI2L_reg_reg(rRegL dst, rRegI src)
// ins_pipe(ialu_reg_reg);
// %}
instruct convI2L_reg_mem(rRegL dst, memory src)
%{
match(Set dst (ConvI2L (LoadI src)));
format %{ "movslq $dst, $src\t# i2l" %}
opcode(0x63); // needs REX.W
ins_encode(REX_reg_mem_wide(dst, src), OpcP, reg_mem(dst,src));
ins_pipe(ialu_reg_mem);
%}
// Zero-extend convert int to long
instruct convI2L_reg_reg_zex(rRegL dst, rRegI src, immL_32bits mask)
%{
@ -12082,7 +12130,7 @@ instruct RethrowException()
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.
//
// peepmatch ( root_instr_name [precerding_instruction]* );
// peepmatch ( root_instr_name [preceding_instruction]* );
//
// peepconstraint %{
// (instruction_number.operand_name relational_op instruction_number.operand_name

View File

@ -419,7 +419,7 @@ main(int argc, char ** argv)
goto leave;
}
mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */
if(mainClass == NULL) { /* exception occurred */
ReportExceptionDescription(env);
message = "Could not find the main class. Program will exit.";
goto leave;
@ -441,7 +441,7 @@ main(int argc, char ** argv)
goto leave;
}
mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */
if(mainClass == NULL) { /* exception occurred */
ReportExceptionDescription(env);
message = "Could not find the main class. Program will exit.";
goto leave;

View File

@ -47,7 +47,7 @@
#ifdef JAVA_ARGS
/*
* ApplicationHome is prepended to each of these entries; the resulting
* strings are concatenated (seperated by PATH_SEPARATOR) and used as the
* strings are concatenated (separated by PATH_SEPARATOR) and used as the
* value of -cp option to the launcher.
*/
#ifndef APP_CLASSPATH

View File

@ -192,7 +192,7 @@ static pid_t filename_to_pid(const char* filename) {
// check if the given path is considered a secure directory for
// the backing store files. Returns true if the directory exists
// and is considered a secure location. Returns false if the path
// is a symbolic link or if an error occured.
// is a symbolic link or if an error occurred.
//
static bool is_directory_secure(const char* path) {
struct stat statbuf;

View File

@ -419,7 +419,7 @@ main(int argc, char ** argv)
goto leave;
}
mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */
if(mainClass == NULL) { /* exception occurred */
ReportExceptionDescription(env);
message = "Could not find the main class. Program will exit.";
goto leave;
@ -441,7 +441,7 @@ main(int argc, char ** argv)
goto leave;
}
mainClass = LoadClass(env, classname);
if(mainClass == NULL) { /* exception occured */
if(mainClass == NULL) { /* exception occurred */
ReportExceptionDescription(env);
message = "Could not find the main class. Program will exit.";
goto leave;

View File

@ -47,7 +47,7 @@
#ifdef JAVA_ARGS
/*
* ApplicationHome is prepended to each of these entries; the resulting
* strings are concatenated (seperated by PATH_SEPARATOR) and used as the
* strings are concatenated (separated by PATH_SEPARATOR) and used as the
* value of -cp option to the launcher.
*/
#ifndef APP_CLASSPATH

View File

@ -194,7 +194,7 @@ static pid_t filename_to_pid(const char* filename) {
// check if the given path is considered a secure directory for
// the backing store files. Returns true if the directory exists
// and is considered a secure location. Returns false if the path
// is a symbolic link or if an error occured.
// is a symbolic link or if an error occurred.
//
static bool is_directory_secure(const char* path) {
struct stat statbuf;

View File

@ -195,7 +195,7 @@ static int filename_to_pid(const char* filename) {
// check if the given path is considered a secure directory for
// the backing store files. Returns true if the directory exists
// and is considered a secure location. Returns false if the path
// is a symbolic link or if an error occured.
// is a symbolic link or if an error occurred.
//
static bool is_directory_secure(const char* path) {
@ -994,7 +994,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
return false;
}
// if running on windows 2000 or later, set the automatic inheritence
// if running on windows 2000 or later, set the automatic inheritance
// control flags.
SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl;
_SetSecurityDescriptorControl = (SetSecurityDescriptorControlFnPtr)
@ -1002,7 +1002,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD,
"SetSecurityDescriptorControl");
if (_SetSecurityDescriptorControl != NULL) {
// We do not want to further propogate inherited DACLs, so making them
// We do not want to further propagate inherited DACLs, so making them
// protected prevents that.
if (!_SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED,
SE_DACL_PROTECTED)) {

View File

@ -532,7 +532,7 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_
if (oldAct.sa_sigaction != signalHandler) {
void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
: CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
warning("Unexpected Signal %d occured under user-defined signal handler " INTPTR_FORMAT, sig, (intptr_t)sighand);
warning("Unexpected Signal %d occurred under user-defined signal handler " INTPTR_FORMAT, sig, (intptr_t)sighand);
}
}

View File

@ -299,13 +299,17 @@ static void check_for_sse_support() {
}
#endif // AMD64
bool os::supports_sse() {
#ifdef AMD64
return true;
#else
if (sse_status == SSE_UNKNOWN)
check_for_sse_support();
return sse_status == SSE_SUPPORTED;
}
#endif // AMD64
}
bool os::is_allocatable(size_t bytes) {
#ifdef AMD64
@ -690,7 +694,7 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_
if (oldAct.sa_sigaction != signalHandler) {
void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction)
: CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
warning("Unexpected Signal %d occured under user-defined signal handler %#lx", sig, (long)sighand);
warning("Unexpected Signal %d occurred under user-defined signal handler %#lx", sig, (long)sighand);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2004 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,9 +41,10 @@
static void fence_bootstrap ();
static void setup_fpu();
static bool supports_sse();
#endif // AMD64
static bool supports_sse();
static bool is_allocatable(size_t bytes);
// Used to register dynamic code cache area with the OS

View File

@ -0,0 +1,75 @@
#
# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
#
PKGLIST = \
com.sun.hotspot.tools.compiler
#END PKGLIST
FILELIST = com/sun/hotspot/tools/compiler/*.java
ifneq "x$(ALT_BOOTDIR)" "x"
BOOTDIR := $(ALT_BOOTDIR)
endif
ifeq "x$(BOOTDIR)" "x"
JDK_HOME := $(shell dirname $(shell which java))/..
else
JDK_HOME := $(BOOTDIR)
endif
isUnix := $(shell test -r c:/; echo $$?)
ifeq "$(isUnix)" "1"
CPS := :
else
CPS := ";"
endif
SRC_DIR = src
BUILD_DIR = build
OUTPUT_DIR = $(BUILD_DIR)/classes
# gnumake 3.78.1 does not accept the *s,
# so use the shell to expand them
ALLFILES := $(patsubst %,$(SRC_DIR)/%,$(FILELIST))
ALLFILES := $(shell /bin/ls $(ALLFILES))
JAVAC = $(JDK_HOME)/bin/javac
JAR = $(JDK_HOME)/bin/jar
# Tagging it on because there's no reason not to run it
all: logc.jar
logc.jar: filelist manifest.mf
@mkdir -p $(OUTPUT_DIR)
$(JAVAC) -source 1.5 -deprecation -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) @filelist
$(JAR) cvfm logc.jar manifest.mf -C $(OUTPUT_DIR) com
.PHONY: filelist
filelist: $(ALLFILES)
@rm -f $@
@echo $(ALLFILES) > $@
clean::
rm -rf filelist logc.jar
rm -rf $(BUILD_DIR)

View File

@ -0,0 +1,18 @@
This is a very rough tool for parsing -XX:+LogCompilation output.
It's main purpose is to recreate output similar to
-XX:+PrintCompilation -XX:+PrintInlining output from a debug JVM. It
requires a 1.5 JDK to build and simply typing make should build it.
It produces a jar file, logc.jar, that can be run on the
hotspot.log from LogCompilation output like this:
java -jar logc.jar hotspot.log
This will produce something like the normal PrintCompilation output.
Adding the -i option with also report inlining like PrintInlining.
More information about the LogCompilation output can be found at
http://wikis.sun.com/display/HotSpotInternals/LogCompilation+overview
http://wikis.sun.com/display/HotSpotInternals/PrintCompilation
http://wikis.sun.com/display/HotSpotInternals/LogCompilation+tool

View File

@ -0,0 +1 @@
Main-Class: com.sun.hotspot.tools.compiler.LogCompilation

View File

@ -0,0 +1,75 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
/**
*
* @author never
*/
public abstract class BasicLogEvent implements LogEvent {
protected final String id;
protected final double start;
protected double end;
protected Compilation compilation;
BasicLogEvent(double start, String id) {
this.start = start;
this.end = start;
this.id = id;
}
public double getStart() {
return start;
}
public double getEnd() {
return end;
}
public void setEnd(double end) {
this.end = end;
}
public double getElapsedTime() {
return ((int) ((getEnd() - getStart()) * 1000)) / 1000.0;
}
public String getId() {
return id;
}
public Compilation getCompilation() {
return compilation;
}
public void setCompilation(Compilation compilation) {
this.compilation = compilation;
}
abstract public void print(PrintStream stream);
}

View File

@ -0,0 +1,183 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
public class CallSite {
private int bci;
private Method method;
private int count;
private String receiver;
private int receiver_count;
private String reason;
private List<CallSite> calls;
CallSite() {
}
CallSite(int bci, Method m) {
this.bci = bci;
this.method = m;
}
void add(CallSite site) {
if (getCalls() == null) {
setCalls(new ArrayList<CallSite>());
}
getCalls().add(site);
}
CallSite last() {
return last(-1);
}
CallSite last(int fromEnd) {
return getCalls().get(getCalls().size() + fromEnd);
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (getReason() == null) {
sb.append(" @ " + getBci() + " " + getMethod());
} else {
sb.append("- @ " + getBci() + " " + getMethod() + " " + getReason());
}
sb.append("\n");
if (getCalls() != null) {
for (CallSite site : getCalls()) {
sb.append(site);
sb.append("\n");
}
}
return sb.toString();
}
public void print(PrintStream stream) {
print(stream, 0);
}
void emit(PrintStream stream, int indent) {
for (int i = 0; i < indent; i++) {
stream.print(' ');
}
}
private static boolean compat = true;
public void print(PrintStream stream, int indent) {
emit(stream, indent);
String m = getMethod().getHolder().replace('/', '.') + "::" + getMethod().getName();
if (getReason() == null) {
stream.println(" @ " + getBci() + " " + m + " (" + getMethod().getBytes() + " bytes)");
} else {
if (isCompat()) {
stream.println(" @ " + getBci() + " " + m + " " + getReason());
} else {
stream.println("- @ " + getBci() + " " + m +
" (" + getMethod().getBytes() + " bytes) " + getReason());
}
}
if (getReceiver() != null) {
emit(stream, indent + 3);
// stream.println("type profile " + method.holder + " -> " + receiver + " (" +
// receiver_count + "/" + count + "," + (receiver_count * 100 / count) + "%)");
stream.println("type profile " + getMethod().getHolder() + " -> " + getReceiver() + " (" +
(getReceiverCount() * 100 / getCount()) + "%)");
}
if (getCalls() != null) {
for (CallSite site : getCalls()) {
site.print(stream, indent + 2);
}
}
}
public int getBci() {
return bci;
}
public void setBci(int bci) {
this.bci = bci;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getReceiver() {
return receiver;
}
public void setReceiver(String receiver) {
this.receiver = receiver;
}
public int getReceiverCount() {
return receiver_count;
}
public void setReceiver_count(int receiver_count) {
this.receiver_count = receiver_count;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public List<CallSite> getCalls() {
return calls;
}
public void setCalls(List<CallSite> calls) {
this.calls = calls;
}
public static boolean isCompat() {
return compat;
}
public static void setCompat(boolean aCompat) {
compat = aCompat;
}
}

View File

@ -0,0 +1,236 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.ArrayList;
public class Compilation implements LogEvent {
private int id;
private boolean osr;
private Method method;
private CallSite call = new CallSite();
private int osrBci;
private String icount;
private String bcount;
private String special;
private double start;
private double end;
private int attempts;
private NMethod nmethod;
private ArrayList<Phase> phases = new ArrayList<Phase>(4);
private String failureReason;
Compilation(int id) {
this.id = id;
}
Phase getPhase(String s) {
for (Phase p : getPhases()) {
if (p.getName().equals(s)) {
return p;
}
}
return null;
}
double getRegallocTime() {
return getPhase("regalloc").getElapsedTime();
}
public double getStart() {
return start;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getId());
sb.append(" ");
sb.append(getMethod());
sb.append(" ");
sb.append(getIcount());
sb.append("+");
sb.append(getBcount());
sb.append("\n");
for (CallSite site : getCall().getCalls()) {
sb.append(site);
sb.append("\n");
}
return sb.toString();
}
public void printShort(PrintStream stream) {
if (getMethod() == null) {
stream.println(getSpecial());
} else {
int bc = isOsr() ? getOsr_bci() : -1;
stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
}
}
public void print(PrintStream stream) {
print(stream, 0, false);
}
public void print(PrintStream stream, boolean printInlining) {
print(stream, 0, printInlining);
}
public void print(PrintStream stream, int indent, boolean printInlining) {
if (getMethod() == null) {
stream.println(getSpecial());
} else {
int bc = isOsr() ? getOsr_bci() : -1;
stream.print(getId() + getMethod().decodeFlags(bc) + getMethod().format(bc));
stream.println();
if (getFailureReason() != null) {
stream.println("COMPILE FAILED " + getFailureReason());
}
if (printInlining && call.getCalls() != null) {
for (CallSite site : call.getCalls()) {
site.print(stream, indent + 2);
}
}
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isOsr() {
return osr;
}
public void setOsr(boolean osr) {
this.osr = osr;
}
public int getOsr_bci() {
return osrBci;
}
public void setOsr_bci(int osrBci) {
this.osrBci = osrBci;
}
public String getIcount() {
return icount;
}
public void setICount(String icount) {
this.icount = icount;
}
public String getBcount() {
return bcount;
}
public void setBCount(String bcount) {
this.bcount = bcount;
}
public String getSpecial() {
return special;
}
public void setSpecial(String special) {
this.special = special;
}
public void setStart(double start) {
this.start = start;
}
public double getEnd() {
return end;
}
public void setEnd(double end) {
this.end = end;
}
public int getAttempts() {
return attempts;
}
public void setAttempts(int attempts) {
this.attempts = attempts;
}
public NMethod getNMethod() {
return nmethod;
}
public void setNMethod(NMethod NMethod) {
this.nmethod = NMethod;
}
public ArrayList<Phase> getPhases() {
return phases;
}
public void setPhases(ArrayList<Phase> phases) {
this.setPhases(phases);
}
public String getFailureReason() {
return failureReason;
}
public void setFailureReason(String failureReason) {
this.failureReason = failureReason;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public CallSite getCall() {
return call;
}
public void setCall(CallSite call) {
this.call = call;
}
public double getElapsedTime() {
return end - start;
}
public Compilation getCompilation() {
return this;
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
interface Constants {
static final int JVM_ACC_PUBLIC = 0x0001; /* visible to everyone */
static final int JVM_ACC_PRIVATE = 0x0002; /* visible only to the defining class */
static final int JVM_ACC_PROTECTED = 0x0004; /* visible to subclasses */
static final int JVM_ACC_STATIC = 0x0008; /* instance variable is static */
static final int JVM_ACC_FINAL = 0x0010; /* no further subclassing, overriding */
static final int JVM_ACC_SYNCHRONIZED = 0x0020; /* wrap method call in monitor lock */
static final int JVM_ACC_SUPER = 0x0020; /* funky handling of invokespecial */
static final int JVM_ACC_VOLATILE = 0x0040; /* can not cache in registers */
static final int JVM_ACC_BRIDGE = 0x0040; /* bridge method generated by compiler */
static final int JVM_ACC_TRANSIENT = 0x0080; /* not persistent */
static final int JVM_ACC_VARARGS = 0x0080; /* method declared with variable number of args */
static final int JVM_ACC_NATIVE = 0x0100; /* implemented in C */
static final int JVM_ACC_INTERFACE = 0x0200; /* class is an interface */
static final int JVM_ACC_ABSTRACT = 0x0400; /* no definition provided */
static final int JVM_ACC_STRICT = 0x0800; /* strict floating point */
static final int JVM_ACC_SYNTHETIC = 0x1000; /* compiler-generated class, method or field */
static final int JVM_ACC_ANNOTATION = 0x2000; /* annotation type */
static final int JVM_ACC_ENUM = 0x4000; /* field is declared as element of enum */
}

View File

@ -0,0 +1,212 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.*;
import java.util.regex.*;
/**
* This class is a filter class to deal with malformed XML that used
* to be produced by the JVM when generating LogCompilation. In 1.6
* and later releases it shouldn't be required.
* @author never
*/
class LogCleanupReader extends Reader {
private Reader reader;
private char[] buffer = new char[4096];
private int bufferCount;
private int bufferOffset;
private char[] line = new char[1024];
private int index;
private int length;
private char[] one = new char[1];
LogCleanupReader(Reader r) {
reader = r;
}
static final private Matcher pattern = Pattern.compile(".+ compile_id='[0-9]+'.*( compile_id='[0-9]+)").matcher("");
static final private Matcher pattern2 = Pattern.compile("' (C[12]) compile_id=").matcher("");
static final private Matcher pattern3 = Pattern.compile("'(destroy_vm)/").matcher("");
private void fill() throws IOException {
rawFill();
if (length != -1) {
boolean changed = false;
String s = new String(line, 0, length);
String orig = s;
pattern2.reset(s);
if (pattern2.find()) {
s = s.substring(0, pattern2.start(1)) + s.substring(pattern2.end(1) + 1);
changed = true;
}
pattern.reset(s);
if (pattern.lookingAt()) {
s = s.substring(0, pattern.start(1)) + s.substring(pattern.end(1) + 1);
changed = true;
}
pattern3.reset(s);
if (pattern3.find()) {
s = s.substring(0, pattern3.start(1)) + s.substring(pattern3.end(1));
changed = true;
}
if (changed) {
s.getChars(0, s.length(), line, 0);
length = s.length();
}
}
}
private void rawFill() throws IOException {
if (bufferCount == -1) {
length = -1;
return;
}
int i = 0;
boolean fillNonEOL = true;
outer:
while (true) {
if (fillNonEOL) {
int p;
for (p = bufferOffset; p < bufferCount; p++) {
char c = buffer[p];
if (c == '\r' || c == '\n') {
bufferOffset = p;
fillNonEOL = false;
continue outer;
}
if (i >= line.length) {
// copy and enlarge the line array
char[] newLine = new char[line.length * 2];
System.arraycopy(line, 0, newLine, 0, line.length);
line = newLine;
}
line[i++] = c;
}
bufferOffset = p;
} else {
int p;
for (p = bufferOffset; p < bufferCount; p++) {
char c = buffer[p];
if (c != '\r' && c != '\n') {
bufferOffset = p;
length = i;
index = 0;
return;
}
line[i++] = c;
}
bufferOffset = p;
}
if (bufferCount == -1) {
if (i == 0) {
length = -1;
} else {
length = i;
}
index = 0;
return;
}
if (bufferOffset != bufferCount) {
System.out.println(bufferOffset);
System.out.println(bufferCount);
throw new InternalError("how did we get here");
}
// load more data and try again.
bufferCount = reader.read(buffer, 0, buffer.length);
bufferOffset = 0;
}
}
public int read() throws java.io.IOException {
read(one, 0, 1);
return one[0];
}
public int read(char[] buffer) throws java.io.IOException {
return read(buffer, 0, buffer.length);
}
public int read(char[] b, int off, int len) throws java.io.IOException {
if (length == -1) {
return -1;
}
if (index == length) {
fill();
if (length == -1) {
return -1;
}
}
int n = Math.min(length - index, Math.min(b.length - off, len));
// System.out.printf("%d %d %d %d %d\n", index, length, off, len, n);
System.arraycopy(line, index, b, off, n);
index += n;
return n;
}
public long skip(long n) throws java.io.IOException {
long result = n;
while (n-- > 0) read();
return result;
}
public boolean ready() throws java.io.IOException {
return reader.ready() || (line != null && length > 0);
}
public boolean markSupported() {
return false;
}
public void mark(int unused) throws java.io.IOException {
throw new UnsupportedOperationException("mark not supported");
}
public void reset() throws java.io.IOException {
reader.reset();
line = null;
index = 0;
}
public void close() throws java.io.IOException {
reader.close();
line = null;
index = 0;
}
}

View File

@ -0,0 +1,177 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/**
* The main command line driver of a parser for LogCompilation output.
* @author never
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
public class LogCompilation extends DefaultHandler implements ErrorHandler, Constants {
public static void usage(int exitcode) {
System.out.println("Usage: LogCompilation [ -v ] [ -c ] [ -s ] [ -e | -N ] file1 ...");
System.out.println(" -c: clean up malformed 1.5 xml");
System.out.println(" -i: print inlining decisions");
System.out.println(" -S: print compilation statistics");
System.out.println(" -s: sort events by start time");
System.out.println(" -e: sort events by elapsed time");
System.out.println(" -N: sort events by name and start");
System.exit(exitcode);
}
public static void main(String[] args) throws Exception {
Comparator<LogEvent> defaultSort = LogParser.sortByStart;
boolean statistics = false;
boolean printInlining = false;
boolean cleanup = false;
int index = 0;
while (args.length > index) {
if (args[index].equals("-e")) {
defaultSort = LogParser.sortByElapsed;
index++;
} else if (args[index].equals("-n")) {
defaultSort = LogParser.sortByNameAndStart;
index++;
} else if (args[index].equals("-s")) {
defaultSort = LogParser.sortByStart;
index++;
} else if (args[index].equals("-c")) {
cleanup = true;
index++;
} else if (args[index].equals("-S")) {
statistics = true;
index++;
} else if (args[index].equals("-h")) {
usage(0);
} else if (args[index].equals("-i")) {
printInlining = true;
index++;
} else {
break;
}
}
if (index >= args.length) {
usage(1);
}
while (index < args.length) {
ArrayList<LogEvent> events = LogParser.parse(args[index], cleanup);
if (statistics) {
printStatistics(events, System.out);
} else {
Collections.sort(events, defaultSort);
for (LogEvent c : events) {
if (printInlining && c instanceof Compilation) {
Compilation comp = (Compilation)c;
comp.print(System.out, true);
} else {
c.print(System.out);
}
}
}
index++;
}
}
public static void printStatistics(ArrayList<LogEvent> events, PrintStream out) {
long cacheSize = 0;
long maxCacheSize = 0;
int nmethodsCreated = 0;
int nmethodsLive = 0;
int[] attempts = new int[32];
double regallocTime = 0;
int maxattempts = 0;
LinkedHashMap<String, Double> phaseTime = new LinkedHashMap<String, Double>(7);
LinkedHashMap<String, Integer> phaseNodes = new LinkedHashMap<String, Integer>(7);
double elapsed = 0;
for (LogEvent e : events) {
if (e instanceof Compilation) {
Compilation c = (Compilation) e;
c.printShort(out);
out.printf(" %6.4f\n", c.getElapsedTime());
attempts[c.getAttempts()]++;
maxattempts = Math.max(maxattempts,c.getAttempts());
elapsed += c.getElapsedTime();
for (Phase phase : c.getPhases()) {
out.printf("\t%s %6.4f\n", phase.getName(), phase.getElapsedTime());
Double v = phaseTime.get(phase.getName());
if (v == null) {
v = Double.valueOf(0.0);
}
phaseTime.put(phase.getName(), Double.valueOf(v.doubleValue() + phase.getElapsedTime()));
Integer v2 = phaseNodes.get(phase.getName());
if (v2 == null) {
v2 = Integer.valueOf(0);
}
phaseNodes.put(phase.getName(), Integer.valueOf(v2.intValue() + phase.getNodes()));
}
} else if (e instanceof MakeNotEntrantEvent) {
MakeNotEntrantEvent mne = (MakeNotEntrantEvent) e;
NMethod nm = mne.getNMethod();
if (mne.isZombie()) {
if (nm == null) {
System.err.println(mne.getId());
}
cacheSize -= nm.getSize();
nmethodsLive--;
}
} else if (e instanceof NMethod) {
nmethodsLive++;
nmethodsCreated++;
NMethod nm = (NMethod) e;
cacheSize += nm.getSize();
maxCacheSize = Math.max(cacheSize, maxCacheSize);
}
}
out.printf("NMethods: %d created %d live %d bytes (%d peak) in the code cache\n",
nmethodsCreated, nmethodsLive, cacheSize, maxCacheSize);
out.println("Phase times:");
for (String name : phaseTime.keySet()) {
Double v = phaseTime.get(name);
Integer v2 = phaseNodes.get(name);
out.printf("%20s %6.4f %d\n", name, v.doubleValue(), v2.intValue());
}
out.printf("%20s %6.4f\n", "total", elapsed);
if (maxattempts > 0) {
out.println("Distribution of regalloc passes:");
for (int i = 0; i <= maxattempts; i++) {
out.printf("%2d %8d\n", i, attempts[i]);
}
}
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
import java.util.*;
public interface LogEvent {
public double getStart();
public double getElapsedTime();
public Compilation getCompilation();
public void print(PrintStream stream);
}

View File

@ -0,0 +1,430 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
/**
* A SAX based parser of LogCompilation output from HotSpot. It takes a complete
* @author never
*/
package com.sun.hotspot.tools.compiler;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Stack;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;
public class LogParser extends DefaultHandler implements ErrorHandler, Constants {
static final HashMap<String, String> typeMap;
static {
typeMap = new HashMap<String, String>();
typeMap.put("[I", "int[]");
typeMap.put("[C", "char[]");
typeMap.put("[Z", "boolean[]");
typeMap.put("[L", "Object[]");
typeMap.put("[B", "byte[]");
}
static Comparator<LogEvent> sortByStart = new Comparator<LogEvent>() {
public int compare(LogEvent a, LogEvent b) {
double difference = (a.getStart() - b.getStart());
if (difference < 0) {
return -1;
}
if (difference > 0) {
return 1;
}
return 0;
}
@Override
public boolean equals(Object other) {
return false;
}
@Override
public int hashCode() {
return 7;
}
};
static Comparator<LogEvent> sortByNameAndStart = new Comparator<LogEvent>() {
public int compare(LogEvent a, LogEvent b) {
Compilation c1 = a.getCompilation();
Compilation c2 = b.getCompilation();
if (c1 != null && c2 != null) {
int result = c1.getMethod().toString().compareTo(c2.getMethod().toString());
if (result != 0) {
return result;
}
}
double difference = (a.getStart() - b.getStart());
if (difference < 0) {
return -1;
}
if (difference > 0) {
return 1;
}
return 0;
}
public boolean equals(Object other) {
return false;
}
@Override
public int hashCode() {
return 7;
}
};
static Comparator<LogEvent> sortByElapsed = new Comparator<LogEvent>() {
public int compare(LogEvent a, LogEvent b) {
double difference = (a.getElapsedTime() - b.getElapsedTime());
if (difference < 0) {
return -1;
}
if (difference > 0) {
return 1;
}
return 0;
}
@Override
public boolean equals(Object other) {
return false;
}
@Override
public int hashCode() {
return 7;
}
};
private ArrayList<LogEvent> events = new ArrayList<LogEvent>();
private HashMap<String, String> types = new HashMap<String, String>();
private HashMap<String, Method> methods = new HashMap<String, Method>();
private LinkedHashMap<String, NMethod> nmethods = new LinkedHashMap<String, NMethod>();
private HashMap<String, Compilation> compiles = new HashMap<String, Compilation>();
private String failureReason;
private int bci;
private Stack<CallSite> scopes = new Stack<CallSite>();
private Compilation compile;
private CallSite site;
private Stack<Phase> phaseStack = new Stack<Phase>();
private UncommonTrapEvent currentTrap;
long parseLong(String l) {
try {
return Long.decode(l).longValue();
} catch (NumberFormatException nfe) {
int split = l.length() - 8;
String s1 = "0x" + l.substring(split);
String s2 = l.substring(0, split);
long v1 = Long.decode(s1).longValue() & 0xffffffffL;
long v2 = (Long.decode(s2).longValue() & 0xffffffffL) << 32;
if (!l.equals("0x" + Long.toHexString(v1 + v2))) {
System.out.println(l);
System.out.println(s1);
System.out.println(s2);
System.out.println(v1);
System.out.println(v2);
System.out.println(Long.toHexString(v1 + v2));
throw new InternalError("bad conversion");
}
return v1 + v2;
}
}
public static ArrayList<LogEvent> parse(String file, boolean cleanup) throws Exception {
return parse(new FileReader(file), cleanup);
}
public static ArrayList<LogEvent> parse(Reader reader, boolean cleanup) throws Exception {
// Create the XML input factory
SAXParserFactory factory = SAXParserFactory.newInstance();
// Create the XML LogEvent reader
SAXParser p = factory.newSAXParser();
if (cleanup) {
// some versions of the log have slightly malformed XML, so clean it
// up before passing it to SAX
reader = new LogCleanupReader(reader);
}
LogParser log = new LogParser();
p.parse(new InputSource(reader), log);
// Associate compilations with their NMethods
for (NMethod nm : log.nmethods.values()) {
Compilation c = log.compiles.get(nm.getId());
nm.setCompilation(c);
// Native wrappers for methods don't have a compilation
if (c != null) {
c.setNMethod(nm);
}
}
// Initially we want the LogEvent log sorted by timestamp
Collections.sort(log.events, sortByStart);
return log.events;
}
String search(Attributes attr, String name) {
return search(attr, name, null);
}
String search(Attributes attr, String name, String defaultValue) {
String result = attr.getValue(name);
if (result != null) {
return result;
}
if (defaultValue != null) {
return defaultValue;
}
for (int i = 0; i < attr.getLength(); i++) {
System.out.println(attr.getQName(i) + " " + attr.getValue(attr.getQName(i)));
}
throw new InternalError("can't find " + name);
}
int indent = 0;
String compile_id;
String type(String id) {
String result = types.get(id);
if (result == null) {
throw new InternalError(id);
}
String remapped = typeMap.get(result);
if (remapped != null) {
return remapped;
}
return result;
}
void type(String id, String name) {
assert type(id) == null;
types.put(id, name);
}
Method method(String id) {
Method result = methods.get(id);
if (result == null) {
throw new InternalError(id);
}
return result;
}
public String makeId(Attributes atts) {
String id = atts.getValue("compile_id");
String kind = atts.getValue("kind");
if (kind != null && kind.equals("osr")) {
id += "%";
}
return id;
}
@Override
public void startElement(String uri,
String localName,
String qname,
Attributes atts) {
if (qname.equals("phase")) {
Phase p = new Phase(search(atts, "name"),
Double.parseDouble(search(atts, "stamp")),
Integer.parseInt(search(atts, "nodes")));
phaseStack.push(p);
} else if (qname.equals("phase_done")) {
Phase p = phaseStack.pop();
p.setEndNodes(Integer.parseInt(search(atts, "nodes")));
p.setEnd(Double.parseDouble(search(atts, "stamp")));
compile.getPhases().add(p);
} else if (qname.equals("task")) {
compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1")));
compile.setStart(Double.parseDouble(search(atts, "stamp")));
compile.setICount(search(atts, "count", "0"));
compile.setBCount(search(atts, "backedge_count", "0"));
String method = atts.getValue("method");
int space = method.indexOf(' ');
method = method.substring(0, space) + "::" +
method.substring(space + 1, method.indexOf(' ', space + 1) + 1);
String compiler = atts.getValue("compiler");
if (compiler == null) {
compiler = "";
}
String kind = atts.getValue("compile_kind");
if (kind == null) {
kind = "normal";
}
if (kind.equals("osr")) {
compile.setOsr(true);
compile.setOsr_bci(Integer.parseInt(search(atts, "osr_bci")));
} else if (kind.equals("c2i")) {
compile.setSpecial("--- adapter " + method);
} else {
compile.setSpecial(compile.getId() + " " + method + " (0 bytes)");
}
events.add(compile);
compiles.put(makeId(atts), compile);
} else if (qname.equals("type")) {
type(search(atts, "id"), search(atts, "name"));
} else if (qname.equals("bc")) {
bci = Integer.parseInt(search(atts, "bci"));
} else if (qname.equals("klass")) {
type(search(atts, "id"), search(atts, "name"));
} else if (qname.equals("method")) {
String id = search(atts, "id");
Method m = new Method();
m.setHolder(type(search(atts, "holder")));
m.setName(search(atts, "name"));
m.setReturnType(type(search(atts, "return")));
m.setArguments(search(atts, "arguments", "void"));
m.setBytes(search(atts, "bytes"));
m.setIICount(search(atts, "iicount"));
m.setFlags(search(atts, "flags"));
methods.put(id, m);
} else if (qname.equals("call")) {
site = new CallSite(bci, method(search(atts, "method")));
site.setCount(Integer.parseInt(search(atts, "count")));
String receiver = atts.getValue("receiver");
if (receiver != null) {
site.setReceiver(type(receiver));
site.setReceiver_count(Integer.parseInt(search(atts, "receiver_count")));
}
scopes.peek().add(site);
} else if (qname.equals("regalloc")) {
compile.setAttempts(Integer.parseInt(search(atts, "attempts")));
} else if (qname.equals("inline_fail")) {
scopes.peek().last().setReason(search(atts, "reason"));
} else if (qname.equals("failure")) {
failureReason = search(atts, "reason");
} else if (qname.equals("task_done")) {
compile.setEnd(Double.parseDouble(search(atts, "stamp")));
if (Integer.parseInt(search(atts, "success")) == 0) {
compile.setFailureReason(failureReason);
}
} else if (qname.equals("make_not_entrant")) {
String id = makeId(atts);
NMethod nm = nmethods.get(id);
if (nm == null) throw new InternalError();
LogEvent e = new MakeNotEntrantEvent(Double.parseDouble(search(atts, "stamp")), id,
atts.getValue("zombie") != null, nm);
events.add(e);
} else if (qname.equals("uncommon_trap")) {
String id = atts.getValue("compile_id");
if (id != null) {
id = makeId(atts);
currentTrap = new UncommonTrapEvent(Double.parseDouble(search(atts, "stamp")),
id,
atts.getValue("reason"),
atts.getValue("action"),
Integer.parseInt(search(atts, "count", "0")));
events.add(currentTrap);
} else {
// uncommon trap inserted during parsing.
// ignore for now
}
} else if (qname.equals("jvms")) {
// <jvms bci='4' method='java/io/DataInputStream readChar ()C' bytes='40' count='5815' iicount='20815'/>
if (currentTrap != null) {
currentTrap.addJVMS(atts.getValue("method"), Integer.parseInt(atts.getValue("bci")));
} else {
System.err.println("Missing uncommon_trap for jvms");
}
} else if (qname.equals("nmethod")) {
String id = makeId(atts);
NMethod nm = new NMethod(Double.parseDouble(search(atts, "stamp")),
id,
parseLong(atts.getValue("address")),
parseLong(atts.getValue("size")));
nmethods.put(id, nm);
events.add(nm);
} else if (qname.equals("parse")) {
Method m = method(search(atts, "method"));
if (scopes.size() == 0) {
compile.setMethod(m);
scopes.push(compile.getCall());
} else {
if (site.getMethod() == m) {
scopes.push(site);
} else if (scopes.peek().getCalls().size() > 2 && m == scopes.peek().last(-2).getMethod()) {
scopes.push(scopes.peek().last(-2));
} else {
System.out.println(site.getMethod());
System.out.println(m);
throw new InternalError("call site and parse don't match");
}
}
}
}
@Override
public void endElement(String uri,
String localName,
String qname) {
if (qname.equals("parse")) {
indent -= 2;
scopes.pop();
} else if (qname.equals("uncommon_trap")) {
currentTrap = null;
} else if (qname.equals("task")) {
types.clear();
methods.clear();
site = null;
}
}
@Override
public void warning(org.xml.sax.SAXParseException e) {
System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
e.printStackTrace();
}
@Override
public void error(org.xml.sax.SAXParseException e) {
System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
e.printStackTrace();
}
@Override
public void fatalError(org.xml.sax.SAXParseException e) {
System.err.println(e.getMessage() + " at line " + e.getLineNumber() + ", column " + e.getColumnNumber());
e.printStackTrace();
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
class MakeNotEntrantEvent extends BasicLogEvent {
private final boolean zombie;
private NMethod nmethod;
MakeNotEntrantEvent(double s, String i, boolean z, NMethod nm) {
super(s, i);
zombie = z;
nmethod = nm;
}
public NMethod getNMethod() {
return nmethod;
}
public void print(PrintStream stream) {
if (isZombie()) {
stream.printf("%s make_zombie\n", getId());
} else {
stream.printf("%s make_not_entrant\n", getId());
}
}
public boolean isZombie() {
return zombie;
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.util.Arrays;
public class Method implements Constants {
private String holder;
private String name;
private String returnType;
private String arguments;
private String bytes;
private String iicount;
private String flags;
String decodeFlags(int osr_bci) {
int f = Integer.parseInt(getFlags());
char[] c = new char[4];
Arrays.fill(c, ' ');
if (osr_bci >= 0) {
c[0] = '%';
}
if ((f & JVM_ACC_SYNCHRONIZED) != 0) {
c[1] = 's';
}
return new String(c);
}
String format(int osr_bci) {
if (osr_bci >= 0) {
return getHolder().replace('/', '.') + "::" + getName() + " @ " + osr_bci + " (" + getBytes() + " bytes)";
} else {
return getHolder().replace('/', '.') + "::" + getName() + " (" + getBytes() + " bytes)";
}
}
@Override
public String toString() {
return getHolder().replace('/', '.') + "::" + getName() + " (" + getBytes() + " bytes)";
}
public String getHolder() {
return holder;
}
public void setHolder(String holder) {
this.holder = holder;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getReturnType() {
return returnType;
}
public void setReturnType(String returnType) {
this.returnType = returnType;
}
public String getArguments() {
return arguments;
}
public void setArguments(String arguments) {
this.arguments = arguments;
}
public String getBytes() {
return bytes;
}
public void setBytes(String bytes) {
this.bytes = bytes;
}
public String getIICount() {
return iicount;
}
public void setIICount(String iicount) {
this.iicount = iicount;
}
public String getFlags() {
return flags;
}
public void setFlags(String flags) {
this.flags = flags;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
public class NMethod extends BasicLogEvent {
private long address;
private long size;
NMethod(double s, String i, long a, long sz) {
super(s, i);
address = a;
size = sz;
}
public void print(PrintStream out) {
// XXX Currently we do nothing
// throw new InternalError();
}
public long getAddress() {
return address;
}
public void setAddress(long address) {
this.address = address;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
public class Phase extends BasicLogEvent {
private final int startNodes;
private int endNodes;
Phase(String n, double s, int nodes) {
super(s, n);
startNodes = nodes;
}
int getNodes() {
return getStartNodes();
}
void setEndNodes(int n) {
endNodes = n;
}
public String getName() {
return getId();
}
public int getStartNodes() {
return startNodes;
}
public int getEndNodes() {
return endNodes;
}
@Override
public void print(PrintStream stream) {
throw new UnsupportedOperationException("Not supported yet.");
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package com.sun.hotspot.tools.compiler;
import java.io.PrintStream;
class UncommonTrapEvent extends BasicLogEvent {
private final String reason;
private final String action;
private int count;
private String jvms = "";
UncommonTrapEvent(double s, String i, String r, String a, int c) {
super(s, i);
reason = r;
action = a;
count = c;
}
public void addJVMS(String method, int bci) {
setJvms(getJvms() + " @" + bci + " " + method + "\n");
}
public void updateCount(UncommonTrapEvent trap) {
setCount(Math.max(getCount(), trap.getCount()));
}
public void print(PrintStream stream) {
stream.printf("%s uncommon trap %s %s\n", getId(), getReason(), getAction());
stream.print(getJvms());
}
public String getReason() {
return reason;
}
public String getAction() {
return action;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getJvms() {
return jvms;
}
public void setJvms(String jvms) {
this.jvms = jvms;
}
public void setCompilation(Compilation compilation) {
this.compilation = compilation;
}
}

View File

@ -247,6 +247,7 @@ class BuildConfig {
sysDefines.add("HOTSPOT_BUILD_USER="+System.getProperty("user.name"));
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
sysDefines.add("_JNI_IMPLEMENTATION_");
sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i486\\\"");
sysDefines.addAll(defines);

View File

@ -365,7 +365,7 @@ public class Database {
// HACK ALERT. The compilation of ad_<arch> files is very slow.
// We want to start compiling them as early as possible. The compilation
// order on unix is dependant on the order we emit files here.
// order on unix is dependent on the order we emit files here.
// By sorting the output before emitting it, we expect
// that ad_<arch> will be compiled early.
boolean shouldSortObjFiles = true;

View File

@ -88,7 +88,7 @@ reg_class X_REG(AX, BX); // form a matcher register class of X_REG
// these are used for constraints, etc.
alloc_class class1(AX, BX); // form an allocation class of registers
// used by the register allocator for seperate
// used by the register allocator for separate
// allocation of target register classes
3. Pipeline Syntax for Scheduling
@ -150,7 +150,7 @@ D. Delimiters
b. %} (block terminator)
c. EOF (file terminator)
4. Each statement must start on a seperate line
4. Each statement must start on a separate line
5. Identifiers cannot contain: (){}%;,"/\

View File

@ -79,6 +79,7 @@ typedef unsigned int uintptr_t;
// Macros
// Debugging note: Put a breakpoint on "abort".
#undef assert
#define assert(cond, msg) { if (!(cond)) { fprintf(stderr, "assert fails %s %d: %s\n", __FILE__, __LINE__, msg); abort(); }}
#define max(a, b) (((a)>(b)) ? (a) : (b))

View File

@ -298,7 +298,7 @@ void ADLParser::matchrule_clone_and_swap(MatchRule* rule, const char* instr_iden
rule->count_commutative_op(count);
if (count > 0) {
// Clone match rule and swap commutative operation's operands.
rule->swap_commutative_op(instr_ident, count, match_rules_cnt);
rule->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);
}
}
@ -2586,7 +2586,7 @@ void ADLParser::peep_constraint_parse(Peephole &peep) {
while( _curchar != ')' ) {
// Get information on the left instruction and its operand
// left-instructions's number
intptr_t left_inst = get_int();
int left_inst = get_int();
// Left-instruction's operand
skipws();
if( _curchar != '.' ) {
@ -2602,7 +2602,7 @@ void ADLParser::peep_constraint_parse(Peephole &peep) {
skipws();
// Get information on the right instruction and its operand
intptr_t right_inst; // Right-instructions's number
int right_inst; // Right-instructions's number
if( isdigit(_curchar) ) {
right_inst = get_int();
// Right-instruction's operand
@ -3497,22 +3497,24 @@ FormatRule* ADLParser::template_parse(void) {
// (1)
// Check if there is a string to pass through to output
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
// If at the start of a comment, skip past it
if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else {
// ELSE advance to the next character, or start of the next line
next_char_or_line();
{
char *start = _ptr; // Record start of the next string
while ((_curchar != '$') && ((_curchar != '%') || (*(_ptr+1) != '}')) ) {
// If at the start of a comment, skip past it
if( (_curchar == '/') && ((*(_ptr+1) == '/') || (*(_ptr+1) == '*')) ) {
skipws_no_preproc();
} else {
// ELSE advance to the next character, or start of the next line
next_char_or_line();
}
}
// If a string was found, terminate it and record in EncClass
if ( start != _ptr ) {
*_ptr = '\0'; // Terminate the string
// Add flag to _strings list indicating we should check _rep_vars
format->_strings.addName(NameList::_signal2);
format->_strings.addName(start);
}
}
// If a string was found, terminate it and record in EncClass
if ( start != _ptr ) {
*_ptr = '\0'; // Terminate the string
// Add flag to _strings list indicating we should check _rep_vars
format->_strings.addName(NameList::_signal2);
format->_strings.addName(start);
}
// (2)
@ -3563,10 +3565,10 @@ FormatRule* ADLParser::template_parse(void) {
// copy it and record in FormatRule
if ( _curchar == '$' ) {
next_char(); // Move past the '$'
char* rep_var = get_ident(); // Nil terminate the variable name
rep_var = strdup(rep_var);// Copy the string
char* next_rep_var = get_ident(); // Nil terminate the variable name
next_rep_var = strdup(next_rep_var);// Copy the string
*_ptr = _curchar; // and replace Nil with original character
format->_rep_vars.addName(rep_var);
format->_rep_vars.addName(next_rep_var);
// Add flag to _strings list indicating we should check _rep_vars
format->_strings.addName(NameList::_signal);
}
@ -3714,13 +3716,13 @@ ExpandRule* ADLParser::expand_parse(InstructForm *instr) {
parse_err(SYNERR, "identifier expected at %c\n", _curchar);
continue;
} // Check that you have a valid operand
const Form *form = instr->_localNames[ident2];
if (!form) {
const Form *form2 = instr->_localNames[ident2];
if (!form2) {
parse_err(SYNERR, "operand name expected at %s\n", ident2);
continue;
}
oper = form->is_operand();
if (oper == NULL && !form->is_opclass()) {
oper = form2->is_operand();
if (oper == NULL && !form2->is_opclass()) {
parse_err(SYNERR, "operand name expected at %s\n", ident2);
continue;
} // Add operand to list
@ -4271,7 +4273,7 @@ int ADLParser::get_int(void) {
int result; // Storage for integer result
if( _curline == NULL ) // Return NULL at EOF.
return NULL;
return 0;
skipws(); // Skip whitespace before identifier
start = end = _ptr; // Start points at first character
@ -4553,7 +4555,7 @@ void ADLParser::parse_err(int flag, const char *fmt, ...) {
//---------------------------ensure_start_of_line------------------------------
// A preprocessor directive has been encountered. Be sure it has fallen at
// the begining of a line, or else report an error.
// the beginning of a line, or else report an error.
void ADLParser::ensure_start_of_line(void) {
if (_curchar == '\n') { next_line(); return; }
assert( _ptr >= _curline && _ptr < _curline+strlen(_curline),

View File

@ -436,10 +436,12 @@ void ArchDesc::build_chain_rule(OperandForm *oper) {
if ((oper->_matrule) && (oper->_matrule->_lChild == NULL) &&
(oper->_matrule->_rChild == NULL)) {
const Form *form = _globalNames[oper->_matrule->_opType];
if ((form) && form->is_operand() &&
(form->ideal_only() == false)) {
add_chain_rule_entry(oper->_matrule->_opType, oper->cost(), oper->_ident);
{
const Form *form = _globalNames[oper->_matrule->_opType];
if ((form) && form->is_operand() &&
(form->ideal_only() == false)) {
add_chain_rule_entry(oper->_matrule->_opType, oper->cost(), oper->_ident);
}
}
// Check for additional chain rules
if (oper->_matrule->_next) {
@ -1015,12 +1017,12 @@ void ArchDesc::initBaseOpTypes() {
int idealIndex = 0;
for (idealIndex = 1; idealIndex < _last_machine_leaf; ++idealIndex) {
const char *idealName = NodeClassNames[idealIndex];
_idealIndex.Insert((void*)idealName, (void*)idealIndex);
_idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex);
}
for ( idealIndex = _last_machine_leaf+1;
idealIndex < _last_opcode; ++idealIndex) {
const char *idealName = NodeClassNames[idealIndex];
_idealIndex.Insert((void*)idealName, (void*)idealIndex);
_idealIndex.Insert((void*) idealName, (void*) (intptr_t) idealIndex);
}
}

View File

@ -870,7 +870,7 @@ void ExprDict::print_asserts(FILE *fp) {
}
// Print out the dictionary contents as key-value pairs
static void dumpekey(const void* key) { fprintf(stdout, "%s", key); }
static void dumpekey(const void* key) { fprintf(stdout, "%s", (char*) key); }
static void dumpexpr(const void* expr) { fflush(stdout); ((Expr*)expr)->print(); }
void ExprDict::dump() {
@ -1020,7 +1020,7 @@ void ProductionState::set_cost_bounds(const char *result, const Expr *cost, bool
}
// Print out the dictionary contents as key-value pairs
static void print_key (const void* key) { fprintf(stdout, "%s", key); }
static void print_key (const void* key) { fprintf(stdout, "%s", (char*) key); }
static void print_production(const void* production) { fflush(stdout); ((Production*)production)->print(); }
void ProductionState::print() {

View File

@ -275,7 +275,7 @@ void Dict::print(PrintKeyOrValue print_key, PrintKeyOrValue print_value) {
// Convert string to hash key. This algorithm implements a universal hash
// function with the multipliers frozen (ok, so it's not universal). The
// multipliers (and allowable characters) are all odd, so the resultant sum
// is odd - guarenteed not divisible by any power of two, so the hash tables
// is odd - guaranteed not divisible by any power of two, so the hash tables
// can be any power of two with good results. Also, I choose multipliers
// that have only 2 bits set (the low is always set to be odd) so
// multiplication requires only shifts and adds. Characters are required to
@ -296,7 +296,7 @@ int hashstr(const void *t) {
}
//------------------------------hashptr--------------------------------------
// Slimey cheap hash function; no guarenteed performance. Better than the
// Slimey cheap hash function; no guaranteed performance. Better than the
// default for pointers, especially on MS-DOS machines.
int hashptr(const void *key) {
#ifdef __TURBOC__
@ -306,7 +306,7 @@ int hashptr(const void *key) {
#endif
}
// Slimey cheap hash function; no guarenteed performance.
// Slimey cheap hash function; no guaranteed performance.
int hashkey(const void *key) {
return (int)((intptr_t)key);
}

View File

@ -89,10 +89,10 @@ class Dict { // Dictionary structure
// Hashing functions
int hashstr(const void *s); // Nice string hash
// Slimey cheap hash function; no guarenteed performance. Better than the
// Slimey cheap hash function; no guaranteed performance. Better than the
// default for pointers, especially on MS-DOS machines.
int hashptr(const void *key);
// Slimey cheap hash function; no guarenteed performance.
// Slimey cheap hash function; no guaranteed performance.
int hashkey(const void *key);
// Key comparators

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,8 @@
// FILEBUFF.CPP - Routines for handling a parser file buffer
#include "adlc.hpp"
using namespace std;
//------------------------------FileBuff---------------------------------------
// Create a new parsing buffer
FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(archDesc) {
@ -48,10 +50,10 @@ FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(arc
file_error(SEMERR, 0, "Buffer allocation failed\n");
exit(1); // Exit on allocation failure
}
*_bigbuf = '\n'; // Lead with a sentinal newline
_buf = _bigbuf+1; // Skip sentinal
*_bigbuf = '\n'; // Lead with a sentinel newline
_buf = _bigbuf+1; // Skip sentinel
_bufmax = _buf; // Buffer is empty
_bufeol = _bigbuf; // _bufeol points at sentinal
_bufeol = _bigbuf; // _bufeol points at sentinel
_filepos = -1; // filepos is in sync with _bufeol
_bufoff = _offset = 0L; // Offset at file start
@ -60,8 +62,8 @@ FileBuff::FileBuff( BufferedFile *fptr, ArchDesc& archDesc) : _fp(fptr), _AD(arc
file_error(SEMERR, 0, "File read error, no input read\n");
exit(1); // Exit on read error
}
*_bufmax = '\n'; // End with a sentinal new-line
*(_bufmax+1) = '\0'; // Then end with a sentinal NULL
*_bufmax = '\n'; // End with a sentinel new-line
*(_bufmax+1) = '\0'; // Then end with a sentinel NULL
}
//------------------------------~FileBuff--------------------------------------
@ -79,7 +81,7 @@ char *FileBuff::get_line(void) {
_linenum++;
retval = ++_bufeol; // return character following end of previous line
if (*retval == '\0') return NULL; // Check for EOF sentinal
if (*retval == '\0') return NULL; // Check for EOF sentinel
// Search for newline character which must end each line
for(_filepos++; *_bufeol != '\n'; _bufeol++)
_filepos++; // keep filepos in sync with _bufeol
@ -217,7 +219,7 @@ static int printline( ostream& os, const char *fname, int line,
off = expandtab(os,off,*s++,'-','-');
if( i == len ) os << '^'; // Mark end of region
os << '\n'; // End of marked line
return 0L; // All done
return 0; // All done
}
//------------------------------print------------------------------------------

View File

@ -26,6 +26,7 @@
#include <iostream>
using namespace std;
// STRUCTURE FOR HANDLING INPUT AND OUTPUT FILES
typedef struct {
const char *_name;
@ -36,7 +37,7 @@ class ArchDesc;
//------------------------------FileBuff--------------------------------------
// This class defines a nicely behaved buffer of text. Entire file of text
// is read into buffer at creation, with sentinals at start and end.
// is read into buffer at creation, with sentinels at start and end.
class FileBuff {
friend class FileBuffRegion;
private:
@ -45,8 +46,8 @@ class FileBuff {
long _bufoff; // Start of buffer file offset
char *_buf; // The buffer itself.
char *_bigbuf; // The buffer plus sentinals; actual heap area
char *_bufmax; // A pointer to the buffer end sentinal
char *_bigbuf; // The buffer plus sentinels; actual heap area
char *_bufmax; // A pointer to the buffer end sentinel
char *_bufeol; // A pointer to the last complete line end
int _err; // Error flag for file seek/read operations
@ -72,7 +73,7 @@ class FileBuff {
// This converts a pointer into the buffer to a file offset. It only works
// when the pointer is valid (i.e. just obtained from getline()).
int getoff(const char *s) { return _bufoff+(int)(s-_buf); }
long getoff(const char* s) { return _bufoff + (s - _buf); }
};
//------------------------------FileBuffRegion---------------------------------
@ -95,8 +96,6 @@ class FileBuffRegion {
FileBuffRegion *copy(); // Deep copy
FileBuffRegion *merge(FileBuffRegion*); // Merge 2 regions; delete input
// void print(std::ostream&);
// friend std::ostream& operator<< (std::ostream&, FileBuffRegion&);
void print(ostream&);
friend ostream& operator<< (ostream&, FileBuffRegion&);
};

View File

@ -70,6 +70,7 @@ const char *NameList::iter() {
else return (_iter <_cur-1 ? _names[++_iter] : NULL);
}
const char *NameList::current() { return (_iter < _cur ? _names[_iter] : NULL); }
const char *NameList::peek(int skip) { return (_iter + skip < _cur ? _names[_iter + skip] : NULL); }
// Return 'true' if current entry is signal
bool NameList::current_is_signal() {
@ -248,11 +249,13 @@ Form::DataType Form::ideal_to_Reg_type(const char *name) const {
// True if 'opType', an ideal name, loads or stores.
Form::DataType Form::is_load_from_memory(const char *opType) const {
if( strcmp(opType,"LoadB")==0 ) return Form::idealB;
if( strcmp(opType,"LoadUB")==0 ) return Form::idealB;
if( strcmp(opType,"LoadUS")==0 ) return Form::idealC;
if( strcmp(opType,"LoadD")==0 ) return Form::idealD;
if( strcmp(opType,"LoadD_unaligned")==0 ) return Form::idealD;
if( strcmp(opType,"LoadF")==0 ) return Form::idealF;
if( strcmp(opType,"LoadI")==0 ) return Form::idealI;
if( strcmp(opType,"LoadUI2L")==0 ) return Form::idealI;
if( strcmp(opType,"LoadKlass")==0 ) return Form::idealP;
if( strcmp(opType,"LoadNKlass")==0 ) return Form::idealN;
if( strcmp(opType,"LoadL")==0 ) return Form::idealL;
@ -370,7 +373,7 @@ bool FormDict::operator ==(const FormDict &d) const {
}
// Print out the dictionary contents as key-value pairs
static void dumpkey (const void* key) { fprintf(stdout, "%s", key); }
static void dumpkey (const void* key) { fprintf(stdout, "%s", (char*) key); }
static void dumpform(const void* form) { fflush(stdout); ((Form*)form)->dump(); }
void FormDict::dump() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -124,7 +124,7 @@ protected:
public:
// Public Data
Form *_next; // Next pointer for form lists
long _linenum; // Line number for debugging
int _linenum; // Line number for debugging
// Dynamic type check for common forms.
virtual OpClassForm *is_opclass() const;
@ -342,6 +342,7 @@ public:
void reset(); // Reset iteration
const char *iter(); // after reset(), first element : else next
const char *current(); // return current element in iteration.
const char *peek(int skip = 1); // returns element + skip in iteration if there is one
bool current_is_signal(); // Return 'true' if current entry is signal
bool is_signal(const char *entry); // Return true if entry is a signal

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -273,13 +273,13 @@ int RegClass::regs_in_word( int wordnum, bool stack_also ) {
for(_regDefs.reset(); (name = _regDefs.iter()) != NULL;) {
int rnum = ((RegDef*)_regDef[name])->register_num();
if( (rnum >> 5) == wordnum )
word |= (1L<<(rnum&31));
word |= (1 << (rnum & 31));
}
if( stack_also ) {
// Now also collect stack bits
for( int i = 0; i < 32; i++ )
if( wordnum*32+i >= RegisterForm::_reg_ctr )
word |= (1L<<i);
word |= (1 << i);
}
return word;
@ -592,10 +592,10 @@ void PeepMatch::add_instruction(int parent, int position, const char *name,
int input) {
if( position > _max_position ) _max_position = position;
_parent.addName((char *)parent);
_position.addName((char *)position);
_parent.addName((char*) (intptr_t) parent);
_position.addName((char*) (intptr_t) position);
_instrs.addName(name);
_input.addName((char *)input);
_input.addName((char*) (intptr_t) input);
}
// Access info about instructions in the peep-match rule
@ -603,7 +603,7 @@ int PeepMatch::max_position() {
return _max_position;
}
const char *PeepMatch::instruction_name(intptr_t position) {
const char *PeepMatch::instruction_name(int position) {
return _instrs.name(position);
}
@ -615,11 +615,11 @@ void PeepMatch::reset() {
_input.reset();
}
void PeepMatch::next_instruction( intptr_t &parent, intptr_t &position, const char * &name, intptr_t &input ){
parent = (intptr_t)_parent.iter();
position = (intptr_t)_position.iter();
void PeepMatch::next_instruction(int &parent, int &position, const char* &name, int &input) {
parent = (int) (intptr_t) _parent.iter();
position = (int) (intptr_t) _position.iter();
name = _instrs.iter();
input = (intptr_t)_input.iter();
input = (int) (intptr_t) _input.iter();
}
// 'true' if current position in iteration is a placeholder, not matched.
@ -637,15 +637,15 @@ void PeepMatch::output(FILE *fp) { // Write info to output files
}
//------------------------------PeepConstraint---------------------------------
PeepConstraint::PeepConstraint(intptr_t left_inst, char *left_op, char *relation,
intptr_t right_inst, char *right_op)
PeepConstraint::PeepConstraint(int left_inst, char* left_op, char* relation,
int right_inst, char* right_op)
: _left_inst(left_inst), _left_op(left_op), _relation(relation),
_right_inst(right_inst), _right_op(right_op), _next(NULL) {}
PeepConstraint::~PeepConstraint() {
}
// Check if constraints use instruction at position
bool PeepConstraint::constrains_instruction(intptr_t position) {
bool PeepConstraint::constrains_instruction(int position) {
// Check local instruction constraints
if( _left_inst == position ) return true;
if( _right_inst == position ) return true;
@ -692,7 +692,7 @@ void PeepReplace::add_instruction(char *root) {
}
void PeepReplace::add_operand( int inst_num, char *inst_operand ) {
_instruction.add_signal();
_operand_inst_num.addName((char*)inst_num);
_operand_inst_num.addName((char*) (intptr_t) inst_num);
_operand_op_name.addName(inst_operand);
}
@ -702,15 +702,15 @@ void PeepReplace::reset() {
_operand_inst_num.reset();
_operand_op_name.reset();
}
void PeepReplace::next_instruction(const char * &inst){
void PeepReplace::next_instruction(const char* &inst){
inst = _instruction.iter();
intptr_t inst_num = (intptr_t)_operand_inst_num.iter();
const char *inst_operand = _operand_op_name.iter();
int inst_num = (int) (intptr_t) _operand_inst_num.iter();
const char* inst_operand = _operand_op_name.iter();
}
void PeepReplace::next_operand( intptr_t &inst_num, const char * &inst_operand ) {
const char *inst = _instruction.iter();
inst_num = (intptr_t)_operand_inst_num.iter();
inst_operand = _operand_op_name.iter();
void PeepReplace::next_operand(int &inst_num, const char* &inst_operand) {
const char* inst = _instruction.iter();
inst_num = (int) (intptr_t) _operand_inst_num.iter();
inst_operand = _operand_op_name.iter();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -457,10 +457,10 @@ public:
// Access info about instructions in the peep-match rule
int max_position();
const char *instruction_name(intptr_t position);
const char *instruction_name(int position);
// Iterate through all info on matched instructions
void reset();
void next_instruction( intptr_t &parent, intptr_t &position, const char * &name, intptr_t &input );
void next_instruction(int &parent, int &position, const char* &name, int &input);
// 'true' if current position in iteration is a placeholder, not matched.
bool is_placeholder();
@ -474,20 +474,20 @@ private:
PeepConstraint *_next; // Additional constraints ANDed together
public:
const intptr_t _left_inst;
const char *_left_op;
const char *_relation;
const intptr_t _right_inst;
const char *_right_op;
const int _left_inst;
const char* _left_op;
const char* _relation;
const int _right_inst;
const char* _right_op;
public:
// Public Methods
PeepConstraint(intptr_t left_inst, char *left_op, char *relation,
intptr_t right_inst, char *right_op);
PeepConstraint(int left_inst, char* left_op, char* relation,
int right_inst, char* right_op);
~PeepConstraint();
// Check if constraints use instruction at position
bool constrains_instruction(intptr_t position);
bool constrains_instruction(int position);
// Add another constraint
void append(PeepConstraint *next_peep_constraint);
@ -519,7 +519,7 @@ public:
// Access contents of peepreplace
void reset();
void next_instruction(const char * &root);
void next_operand( intptr_t &inst_num, const char * &inst_operand );
void next_operand(int &inst_num, const char * &inst_operand );
// Utilities
void dump();

View File

@ -844,8 +844,12 @@ void InstructForm::build_components() {
for (_parameters.reset(); (name = _parameters.iter()) != NULL;) {
OperandForm *opForm = (OperandForm*)_localNames[name];
const Form *form = _effects[name];
Effect *e = form ? form->is_effect() : NULL;
Effect* e = NULL;
{
const Form* form = _effects[name];
e = form ? form->is_effect() : NULL;
}
if (e != NULL) {
has_temp |= e->is(Component::TEMP);
@ -858,19 +862,7 @@ void InstructForm::build_components() {
OperandForm* kill = (OperandForm*)_localNames[kill_name];
globalAD->syntax_err(_linenum, "%s: %s %s must be at the end of the argument list\n",
_ident, kill->_ident, kill_name);
} else if (e->isa(Component::KILL)) {
kill_name = name;
}
// TEMPs are real uses and need to be among the first parameters
// listed, otherwise the numbering of operands and inputs gets
// screwy, so enforce this restriction during parse.
if (kill_name != NULL &&
e->isa(Component::TEMP) && !e->isa(Component::DEF)) {
OperandForm* kill = (OperandForm*)_localNames[kill_name];
globalAD->syntax_err(_linenum, "%s: %s %s must follow %s %s in the argument list\n",
_ident, kill->_ident, kill_name, opForm->_ident, name);
} else if (e->isa(Component::KILL)) {
} else if (e->isa(Component::KILL) && !e->isa(Component::USE)) {
kill_name = name;
}
}
@ -1122,7 +1114,7 @@ bool InstructForm::cisc_spills_to(ArchDesc &AD, InstructForm *instr) {
const char *op_name = NULL;
const char *reg_type = NULL;
FormDict &globals = AD.globalNames();
cisc_spill_operand = _matrule->cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type);
cisc_spill_operand = _matrule->matchrule_cisc_spill_match(globals, AD.get_registers(), instr->_matrule, op_name, reg_type);
if( (cisc_spill_operand != Not_cisc_spillable) && (op_name != NULL) && equivalent_predicates(this, instr) ) {
cisc_spill_operand = operand_position(op_name, Component::USE);
int def_oper = operand_position(op_name, Component::DEF);
@ -1217,13 +1209,17 @@ void InstructForm::rep_var_format(FILE *fp, const char *rep_var) {
// Seach through operands to determine parameters unique positions.
void InstructForm::set_unique_opnds() {
uint* uniq_idx = NULL;
uint nopnds = num_opnds();
int nopnds = num_opnds();
uint num_uniq = nopnds;
uint i;
int i;
_uniq_idx_length = 0;
if ( nopnds > 0 ) {
// Allocate index array with reserve.
uniq_idx = (uint*) malloc(sizeof(uint)*(nopnds + 2));
for( i = 0; i < nopnds+2; i++ ) {
// Allocate index array. Worst case we're mapping from each
// component back to an index and any DEF always goes at 0 so the
// length of the array has to be the number of components + 1.
_uniq_idx_length = _components.count() + 1;
uniq_idx = (uint*) malloc(sizeof(uint)*(_uniq_idx_length));
for( i = 0; i < _uniq_idx_length; i++ ) {
uniq_idx[i] = i;
}
}
@ -1238,8 +1234,8 @@ void InstructForm::set_unique_opnds() {
_parameters.reset();
while( (name = _parameters.iter()) != NULL ) {
count = 0;
uint position = 0;
uint uniq_position = 0;
int position = 0;
int uniq_position = 0;
_components.reset();
Component *comp = NULL;
if( sets_result() ) {
@ -1255,6 +1251,7 @@ void InstructForm::set_unique_opnds() {
}
if( strcmp(name, comp->_name)==0 ) {
if( ++count > 1 ) {
assert(position < _uniq_idx_length, "out of bounds");
uniq_idx[position] = uniq_position;
has_dupl_use = true;
} else {
@ -1284,7 +1281,7 @@ void InstructForm::set_unique_opnds() {
_num_uniq = num_uniq;
}
// Generate index values needed for determing the operand position
// Generate index values needed for determining the operand position
void InstructForm::index_temps(FILE *fp, FormDict &globals, const char *prefix, const char *receiver) {
uint idx = 0; // position of operand in match rule
int cur_num_opnds = num_opnds();
@ -2200,8 +2197,8 @@ int OperandForm::operand_position(const char *name, int usedef) {
// Return zero-based position in component list, only counting constants;
// Return -1 if not in list.
int OperandForm::constant_position(FormDict &globals, const Component *last) {
// Iterate through components and count constants preceeding 'constant'
uint position = 0;
// Iterate through components and count constants preceding 'constant'
int position = 0;
Component *comp;
_components.reset();
while( (comp = _components.iter()) != NULL && (comp != last) ) {
@ -2238,7 +2235,7 @@ int OperandForm::constant_position(FormDict &globals, const char *name) {
// Return zero-based position in component list, only counting constants;
// Return -1 if not in list.
int OperandForm::register_position(FormDict &globals, const char *reg_name) {
// Iterate through components and count registers preceeding 'last'
// Iterate through components and count registers preceding 'last'
uint position = 0;
Component *comp;
_components.reset();
@ -2304,7 +2301,7 @@ void OperandForm::disp_is_oop(FILE *fp, FormDict &globals) {
if ( op->is_base_constant(globals) == Form::idealP ) {
// Find the constant's index: _c0, _c1, _c2, ... , _cN
uint idx = op->constant_position( globals, rep_var);
fprintf(fp," virtual bool disp_is_oop() const {", _ident);
fprintf(fp," virtual bool disp_is_oop() const {");
fprintf(fp, " return _c%d->isa_oop_ptr();", idx);
fprintf(fp, " }\n");
}
@ -3042,9 +3039,9 @@ bool MatchNode::find_type(const char *type, int &position) const {
// Recursive call collecting info on top-level operands, not transitive.
// Implementation does not modify state of internal structures.
void MatchNode::append_components(FormDict &locals, ComponentList &components,
bool deflag) const {
int usedef = deflag ? Component::DEF : Component::USE;
void MatchNode::append_components(FormDict& locals, ComponentList& components,
bool def_flag) const {
int usedef = def_flag ? Component::DEF : Component::USE;
FormDict &globals = _AD.globalNames();
assert (_name != NULL, "MatchNode::build_components encountered empty node\n");
@ -3062,10 +3059,10 @@ void MatchNode::append_components(FormDict &locals, ComponentList &components,
return;
}
// Promote results of "Set" to DEF
bool def_flag = (!strcmp(_opType, "Set")) ? true : false;
if (_lChild) _lChild->append_components(locals, components, def_flag);
def_flag = false; // only applies to component immediately following 'Set'
if (_rChild) _rChild->append_components(locals, components, def_flag);
bool tmpdef_flag = (!strcmp(_opType, "Set")) ? true : false;
if (_lChild) _lChild->append_components(locals, components, tmpdef_flag);
tmpdef_flag = false; // only applies to component immediately following 'Set'
if (_rChild) _rChild->append_components(locals, components, tmpdef_flag);
}
// Find the n'th base-operand in the match node,
@ -3313,8 +3310,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {
static const char *needs_ideal_memory_list[] = {
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
"StoreB","StoreC","Store" ,"StoreFP",
"LoadI" ,"LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
"LoadB" ,"LoadUS" ,"LoadS" ,"Load" ,
"LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
"Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B",
"Store8B","Store4B","Store8C","Store4C","Store2C",
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
@ -3411,9 +3408,9 @@ bool static root_ops_match(FormDict &globals, const char *op1, const char *op2)
return (form1 == form2);
}
//-------------------------cisc_spill_match------------------------------------
//-------------------------cisc_spill_match_node-------------------------------
// Recursively check two MatchRules for legal conversion via cisc-spilling
int MatchNode::cisc_spill_match(FormDict &globals, RegisterForm *registers, MatchNode *mRule2, const char * &operand, const char * &reg_type) {
int MatchNode::cisc_spill_match(FormDict& globals, RegisterForm* registers, MatchNode* mRule2, const char* &operand, const char* &reg_type) {
int cisc_spillable = Maybe_cisc_spillable;
int left_spillable = Maybe_cisc_spillable;
int right_spillable = Maybe_cisc_spillable;
@ -3434,10 +3431,16 @@ int MatchNode::cisc_spill_match(FormDict &globals, RegisterForm *registers, Mat
const InstructForm *form2_inst = form2 ? form2->is_instruction() : NULL;
const char *name_left = mRule2->_lChild ? mRule2->_lChild->_opType : NULL;
const char *name_right = mRule2->_rChild ? mRule2->_rChild->_opType : NULL;
DataType data_type = Form::none;
if (form->is_operand()) {
// Make sure the loadX matches the type of the reg
data_type = form->ideal_to_Reg_type(form->is_operand()->ideal_type(globals));
}
// Detect reg vs (loadX memory)
if( form->is_cisc_reg(globals)
&& form2_inst
&& (is_load_from_memory(mRule2->_opType) != Form::none) // reg vs. (load memory)
&& data_type != Form::none
&& (is_load_from_memory(mRule2->_opType) == data_type) // reg vs. (load memory)
&& (name_left != NULL) // NOT (load)
&& (name_right == NULL) ) { // NOT (load memory foo)
const Form *form2_left = name_left ? globals[name_left] : NULL;
@ -3487,13 +3490,13 @@ int MatchNode::cisc_spill_match(FormDict &globals, RegisterForm *registers, Mat
return cisc_spillable;
}
//---------------------------cisc_spill_match----------------------------------
//---------------------------cisc_spill_match_rule------------------------------
// Recursively check two MatchRules for legal conversion via cisc-spilling
// This method handles the root of Match tree,
// general recursive checks done in MatchNode
int MatchRule::cisc_spill_match(FormDict &globals, RegisterForm *registers,
MatchRule *mRule2, const char * &operand,
const char * &reg_type) {
int MatchRule::matchrule_cisc_spill_match(FormDict& globals, RegisterForm* registers,
MatchRule* mRule2, const char* &operand,
const char* &reg_type) {
int cisc_spillable = Maybe_cisc_spillable;
int left_spillable = Maybe_cisc_spillable;
int right_spillable = Maybe_cisc_spillable;
@ -3531,7 +3534,7 @@ int MatchRule::cisc_spill_match(FormDict &globals, RegisterForm *registers,
//----------------------------- equivalent ------------------------------------
// Recursively check to see if two match rules are equivalent.
// This rule handles the root.
bool MatchRule::equivalent(FormDict &globals, MatchRule *mRule2) {
bool MatchRule::equivalent(FormDict &globals, MatchNode *mRule2) {
// Check that each sets a result
if (sets_result() != mRule2->sets_result()) {
return false;
@ -3647,7 +3650,7 @@ void MatchNode::swap_commutative_op(bool atroot, int id) {
//-------------------------- swap_commutative_op ------------------------------
// Recursively swap specified commutative operation with subtree operands.
void MatchRule::swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) {
void MatchRule::matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt) {
assert(match_rules_cnt < 100," too many match rule clones");
// Clone
MatchRule* clone = new MatchRule(_AD, this);
@ -3660,8 +3663,8 @@ void MatchRule::swap_commutative_op(const char* instr_ident, int count, int& mat
clone->_next = this->_next;
this-> _next = clone;
if( (--count) > 0 ) {
this-> swap_commutative_op(instr_ident, count, match_rules_cnt);
clone->swap_commutative_op(instr_ident, count, match_rules_cnt);
this-> matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);
clone->matchrule_swap_commutative_op(instr_ident, count, match_rules_cnt);
}
}
@ -3693,7 +3696,7 @@ MatchRule::~MatchRule() {
// Recursive call collecting info on top-level operands, not transitive.
// Implementation does not modify state of internal structures.
void MatchRule::append_components(FormDict &locals, ComponentList &components) const {
void MatchRule::append_components(FormDict& locals, ComponentList& components, bool def_flag) const {
assert (_name != NULL, "MatchNode::build_components encountered empty node\n");
MatchNode::append_components(locals, components,

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -101,6 +101,7 @@ public:
const char *_ins_pipe; // Instruction Scheduline description class
uint *_uniq_idx; // Indexes of unique operands
int _uniq_idx_length; // Length of _uniq_idx array
uint _num_uniq; // Number of unique operands
ComponentList _components; // List of Components matches MachNode's
// operand structure
@ -257,11 +258,13 @@ public:
void set_unique_opnds();
uint num_unique_opnds() { return _num_uniq; }
uint unique_opnds_idx(int idx) {
if( _uniq_idx != NULL && idx > 0 )
if( _uniq_idx != NULL && idx > 0 ) {
assert(idx < _uniq_idx_length, "out of bounds");
return _uniq_idx[idx];
else
} else {
return idx;
}
}
}
// Operands which are only KILLs aren't part of the input array and
// require special handling in some cases. Their position in this
@ -274,7 +277,7 @@ public:
//
// Generate the format call for the replacement variable
void rep_var_format(FILE *fp, const char *rep_var);
// Generate index values needed for determing the operand position
// Generate index values needed for determining the operand position
void index_temps (FILE *fp, FormDict &globals, const char *prefix = "", const char *receiver = "");
// ---------------------------
@ -341,7 +344,7 @@ public:
// --------------------------- Code Block
// Add code
void add_code(const char *string_preceeding_replacement_var);
void add_code(const char *string_preceding_replacement_var);
// Add a replacement variable or one of its subfields
// Subfields are stored with a leading '$'
void add_rep_var(char *replacement_var);
@ -917,8 +920,8 @@ public:
// return 1 if found and position is incremented by operand offset in rule
bool find_name(const char *str, int &position) const;
bool find_type(const char *str, int &position) const;
void append_components(FormDict &locals, ComponentList &components,
bool def_flag) const;
virtual void append_components(FormDict& locals, ComponentList& components,
bool def_flag = false) const;
bool base_operand(uint &position, FormDict &globals,
const char * &result, const char * &name,
const char * &opType) const;
@ -944,12 +947,12 @@ public:
const char *reduce_left (FormDict &globals) const;
// Recursive version of check in MatchRule
int cisc_spill_match(FormDict &globals, RegisterForm *registers,
MatchNode *mRule2, const char * &operand,
const char * &reg_type);
int cisc_spill_match(FormDict& globals, RegisterForm* registers,
MatchNode* mRule2, const char* &operand,
const char* &reg_type);
int cisc_spill_merge(int left_result, int right_result);
bool equivalent(FormDict &globals, MatchNode *mNode2);
virtual bool equivalent(FormDict& globals, MatchNode* mNode2);
void count_commutative_op(int& count);
void swap_commutative_op(bool atroot, int count);
@ -976,7 +979,7 @@ public:
MatchRule(ArchDesc &ad, MatchNode* mroot, int depth, char* construct, int numleaves);
~MatchRule();
void append_components(FormDict &locals, ComponentList &components) const;
virtual void append_components(FormDict& locals, ComponentList& components, bool def_flag = false) const;
// Recursive call on all operands' match rules in my match rule.
bool base_operand(uint &position, FormDict &globals,
const char * &result, const char * &name,
@ -1003,14 +1006,14 @@ public:
Form::DataType is_ideal_store() const;// node matches ideal 'StoreXNode'
// Check if 'mRule2' is a cisc-spill variant of this MatchRule
int cisc_spill_match(FormDict &globals, RegisterForm *registers,
MatchRule *mRule2, const char * &operand,
const char * &reg_type);
int matchrule_cisc_spill_match(FormDict &globals, RegisterForm* registers,
MatchRule* mRule2, const char* &operand,
const char* &reg_type);
// Check if 'mRule2' is equivalent to this MatchRule
bool equivalent(FormDict &globals, MatchRule *mRule2);
virtual bool equivalent(FormDict& globals, MatchNode* mRule2);
void swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt);
void matchrule_swap_commutative_op(const char* instr_ident, int count, int& match_rules_cnt);
void dump();
void output(FILE *fp);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -349,7 +349,7 @@ void ArchDesc::close_files(int delete_out)
}
else {
if (_ADL_file._name) printf("%s --> ", _ADL_file._name);
printf("%s, %s, %s, %s, %s, %s, %s, %s, %s",
printf("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s",
_CPP_file._name,
_CPP_CLONE_file._name,
_CPP_EXPAND_file._name,
@ -358,7 +358,8 @@ void ArchDesc::close_files(int delete_out)
_CPP_MISC_file._name,
_CPP_PEEPHOLE_file._name,
_CPP_PIPELINE_file._name,
_HPP_file._name, _DFA_file._name);
_HPP_file._name,
_DFA_file._name);
}
printf("\n");
}
@ -431,7 +432,7 @@ int get_legal_text(FileBuff &fbuf, char **legal_text)
legal_end = fbuf.get_line();
}
*legal_text = legal_start;
return (legal_end - legal_start);
return (int) (legal_end - legal_start);
}
// VS2005 has its own definition, identical to this one.

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -225,11 +225,11 @@ static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, Pi
pipeclass->_parameters.reset();
while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {
const PipeClassOperandForm *pipeopnd =
const PipeClassOperandForm *tmppipeopnd =
(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
if (pipeopnd)
templen += 10 + (int)strlen(pipeopnd->_stage);
if (tmppipeopnd)
templen += 10 + (int)strlen(tmppipeopnd->_stage);
else
templen += 19;
@ -253,10 +253,10 @@ static int pipeline_reads_initializer(FILE *fp_cpp, NameList &pipeline_reads, Pi
pipeclass->_parameters.reset();
while ( (paramname = pipeclass->_parameters.iter()) != NULL ) {
const PipeClassOperandForm *pipeopnd =
const PipeClassOperandForm *tmppipeopnd =
(const PipeClassOperandForm *)pipeclass->_localUsage[paramname];
templen += sprintf(&operand_stages[templen], " stage_%s%c\n",
pipeopnd ? pipeopnd->_stage : "undefined",
tmppipeopnd ? tmppipeopnd->_stage : "undefined",
(++i < paramcount ? ',' : ' ') );
}
@ -1042,10 +1042,10 @@ static void defineOut_RegMask(FILE *fp, const char *node, const char *regMask) {
// Scan the peepmatch and output a test for each instruction
static void check_peepmatch_instruction_tree(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) {
intptr_t parent = -1;
intptr_t inst_position = 0;
const char *inst_name = NULL;
intptr_t input = 0;
int parent = -1;
int inst_position = 0;
const char* inst_name = NULL;
int input = 0;
fprintf(fp, " // Check instruction sub-tree\n");
pmatch->reset();
for( pmatch->next_instruction( parent, inst_position, inst_name, input );
@ -1055,14 +1055,14 @@ static void check_peepmatch_instruction_tree(FILE *fp, PeepMatch *pmatch, PeepCo
if( ! pmatch->is_placeholder() ) {
// Define temporaries 'inst#', based on parent and parent's input index
if( parent != -1 ) { // root was initialized
fprintf(fp, " inst%ld = inst%ld->in(%ld);\n",
fprintf(fp, " inst%d = inst%d->in(%d);\n",
inst_position, parent, input);
}
// When not the root
// Test we have the correct instruction by comparing the rule
if( parent != -1 ) {
fprintf(fp, " matches = matches && ( inst%ld->rule() == %s_rule );",
fprintf(fp, " matches = matches && ( inst%d->rule() == %s_rule );",
inst_position, inst_name);
}
} else {
@ -1073,20 +1073,20 @@ static void check_peepmatch_instruction_tree(FILE *fp, PeepMatch *pmatch, PeepCo
}
}
static void print_block_index(FILE *fp, intptr_t inst_position) {
static void print_block_index(FILE *fp, int inst_position) {
assert( inst_position >= 0, "Instruction number less than zero");
fprintf(fp, "block_index");
if( inst_position != 0 ) {
fprintf(fp, " - %ld", inst_position);
fprintf(fp, " - %d", inst_position);
}
}
// Scan the peepmatch and output a test for each instruction
static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, PeepConstraint *pconstraint) {
intptr_t parent = -1;
intptr_t inst_position = 0;
const char *inst_name = NULL;
intptr_t input = 0;
int parent = -1;
int inst_position = 0;
const char* inst_name = NULL;
int input = 0;
fprintf(fp, " // Check instruction sub-tree\n");
pmatch->reset();
for( pmatch->next_instruction( parent, inst_position, inst_name, input );
@ -1101,14 +1101,14 @@ static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, Pe
print_block_index(fp, inst_position);
fprintf(fp, " > 0 ) {\n Node *n = block->_nodes.at(");
print_block_index(fp, inst_position);
fprintf(fp, ");\n inst%ld = (n->is_Mach()) ? ", inst_position);
fprintf(fp, ");\n inst%d = (n->is_Mach()) ? ", inst_position);
fprintf(fp, "n->as_Mach() : NULL;\n }\n");
}
// When not the root
// Test we have the correct instruction by comparing the rule.
if( parent != -1 ) {
fprintf(fp, " matches = matches && (inst%ld != NULL) && (inst%ld->rule() == %s_rule);\n",
fprintf(fp, " matches = matches && (inst%d != NULL) && (inst%d->rule() == %s_rule);\n",
inst_position, inst_position, inst_name);
}
} else {
@ -1121,10 +1121,10 @@ static void check_peepmatch_instruction_sequence(FILE *fp, PeepMatch *pmatch, Pe
// Build mapping for register indices, num_edges to input
static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMatch *pmatch ) {
intptr_t parent = -1;
intptr_t inst_position = 0;
const char *inst_name = NULL;
intptr_t input = 0;
int parent = -1;
int inst_position = 0;
const char* inst_name = NULL;
int input = 0;
fprintf(fp, " // Build map to register info\n");
pmatch->reset();
for( pmatch->next_instruction( parent, inst_position, inst_name, input );
@ -1136,9 +1136,9 @@ static void build_instruction_index_mapping( FILE *fp, FormDict &globals, PeepMa
InstructForm *inst = globals[inst_name]->is_instruction();
if( inst != NULL ) {
char inst_prefix[] = "instXXXX_";
sprintf(inst_prefix, "inst%ld_", inst_position);
sprintf(inst_prefix, "inst%d_", inst_position);
char receiver[] = "instXXXX->";
sprintf(receiver, "inst%ld->", inst_position);
sprintf(receiver, "inst%d->", inst_position);
inst->index_temps( fp, globals, inst_prefix, receiver );
}
}
@ -1168,7 +1168,7 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch
}
// LEFT
intptr_t left_index = pconstraint->_left_inst;
int left_index = pconstraint->_left_inst;
const char *left_op = pconstraint->_left_op;
// Access info on the instructions whose operands are compared
InstructForm *inst_left = globals[pmatch->instruction_name(left_index)]->is_instruction();
@ -1191,7 +1191,7 @@ static void check_peepconstraints(FILE *fp, FormDict &globals, PeepMatch *pmatch
// RIGHT
int right_op_index = -1;
intptr_t right_index = pconstraint->_right_inst;
int right_index = pconstraint->_right_inst;
const char *right_op = pconstraint->_right_op;
if( right_index != -1 ) { // Match operand
// Access info on the instructions whose operands are compared
@ -1351,7 +1351,7 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch
assert( root_form != NULL, "Replacement instruction was not previously defined");
fprintf(fp, " %sNode *root = new (C) %sNode();\n", root_inst, root_inst);
intptr_t inst_num;
int inst_num;
const char *op_name;
int opnds_index = 0; // define result operand
// Then install the use-operands for the new sub-tree
@ -1362,7 +1362,6 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch
InstructForm *inst_form;
inst_form = globals[pmatch->instruction_name(inst_num)]->is_instruction();
assert( inst_form, "Parser should guaranty this is an instruction");
int op_base = inst_form->oper_input_base(globals);
int inst_op_num = inst_form->operand_position(op_name, Component::USE);
if( inst_op_num == NameList::Not_in_list )
inst_op_num = inst_form->operand_position(op_name, Component::USE_DEF);
@ -1379,32 +1378,32 @@ static void generate_peepreplace( FILE *fp, FormDict &globals, PeepMatch *pmatch
// Add unmatched edges from root of match tree
int op_base = root_form->oper_input_base(globals);
for( int unmatched_edge = 1; unmatched_edge < op_base; ++unmatched_edge ) {
fprintf(fp, " root->add_req(inst%ld->in(%d)); // unmatched ideal edge\n",
fprintf(fp, " root->add_req(inst%d->in(%d)); // unmatched ideal edge\n",
inst_num, unmatched_edge);
}
// If new instruction captures bottom type
if( root_form->captures_bottom_type() ) {
// Get bottom type from instruction whose result we are replacing
fprintf(fp, " root->_bottom_type = inst%ld->bottom_type();\n", inst_num);
fprintf(fp, " root->_bottom_type = inst%d->bottom_type();\n", inst_num);
}
// Define result register and result operand
fprintf(fp, " ra_->add_reference(root, inst%ld);\n", inst_num);
fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%ld));\n", inst_num);
fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%ld), ra_->get_reg_first(inst%ld));\n", inst_num, inst_num);
fprintf(fp, " root->_opnds[0] = inst%ld->_opnds[0]->clone(C); // result\n", inst_num);
fprintf(fp, " ra_->add_reference(root, inst%d);\n", inst_num);
fprintf(fp, " ra_->set_oop (root, ra_->is_oop(inst%d));\n", inst_num);
fprintf(fp, " ra_->set_pair(root->_idx, ra_->get_reg_second(inst%d), ra_->get_reg_first(inst%d));\n", inst_num, inst_num);
fprintf(fp, " root->_opnds[0] = inst%d->_opnds[0]->clone(C); // result\n", inst_num);
fprintf(fp, " // ----- Done with initial setup -----\n");
} else {
if( (op_form == NULL) || (op_form->is_base_constant(globals) == Form::none) ) {
// Do not have ideal edges for constants after matching
fprintf(fp, " for( unsigned x%d = inst%ld_idx%d; x%d < inst%ld_idx%d; x%d++ )\n",
fprintf(fp, " for( unsigned x%d = inst%d_idx%d; x%d < inst%d_idx%d; x%d++ )\n",
inst_op_num, inst_num, inst_op_num,
inst_op_num, inst_num, inst_op_num+1, inst_op_num );
fprintf(fp, " root->add_req( inst%ld->in(x%d) );\n",
fprintf(fp, " root->add_req( inst%d->in(x%d) );\n",
inst_num, inst_op_num );
} else {
fprintf(fp, " // no ideal edge for constants after matching\n");
}
fprintf(fp, " root->_opnds[%d] = inst%ld->_opnds[%d]->clone(C);\n",
fprintf(fp, " root->_opnds[%d] = inst%d->_opnds[%d]->clone(C);\n",
opnds_index, inst_num, inst_op_num );
}
++opnds_index;
@ -1443,7 +1442,7 @@ void ArchDesc::definePeephole(FILE *fp, InstructForm *node) {
}
for( int i = 0; i <= max_position; ++i ) {
if( i == 0 ) {
fprintf(fp, " MachNode *inst0 = this;\n", i);
fprintf(fp, " MachNode *inst0 = this;\n");
} else {
fprintf(fp, " MachNode *inst%d = NULL;\n", i);
}
@ -1743,7 +1742,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
}
// delete the rest of edges
fprintf(fp," for(int i = idx%d - 1; i >= (int)idx%d; i--) {\n", cur_num_opnds, new_num_opnds);
fprintf(fp," del_req(i);\n", i);
fprintf(fp," del_req(i);\n");
fprintf(fp," }\n");
fprintf(fp," _num_opnds = %d;\n", new_num_opnds);
}
@ -1817,7 +1816,7 @@ void ArchDesc::defineExpand(FILE *fp, InstructForm *node) {
fprintf(fp,"\n");
if( node->expands() ) {
fprintf(fp," return result;\n",cnt-1);
fprintf(fp," return result;\n");
} else {
fprintf(fp," return this;\n");
}
@ -2140,8 +2139,59 @@ public:
// A subfield variable, '$$' prefix
emit_field( rep_var );
} else {
// A replacement variable, '$' prefix
emit_rep_var( rep_var );
if (_strings_to_emit.peek() != NULL &&
strcmp(_strings_to_emit.peek(), "$Address") == 0) {
fprintf(_fp, "Address::make_raw(");
emit_rep_var( rep_var );
fprintf(_fp,"->base(ra_,this,idx%d), ", _operand_idx);
_reg_status = LITERAL_ACCESSED;
emit_rep_var( rep_var );
fprintf(_fp,"->index(ra_,this,idx%d), ", _operand_idx);
_reg_status = LITERAL_ACCESSED;
emit_rep_var( rep_var );
fprintf(_fp,"->scale(), ");
_reg_status = LITERAL_ACCESSED;
emit_rep_var( rep_var );
Form::DataType stack_type = _operand ? _operand->is_user_name_for_sReg() : Form::none;
if( _operand && _operand_idx==0 && stack_type != Form::none ) {
fprintf(_fp,"->disp(ra_,this,0), ");
} else {
fprintf(_fp,"->disp(ra_,this,idx%d), ", _operand_idx);
}
_reg_status = LITERAL_ACCESSED;
emit_rep_var( rep_var );
fprintf(_fp,"->disp_is_oop())");
// skip trailing $Address
_strings_to_emit.iter();
} else {
// A replacement variable, '$' prefix
const char* next = _strings_to_emit.peek();
const char* next2 = _strings_to_emit.peek(2);
if (next != NULL && next2 != NULL && strcmp(next2, "$Register") == 0 &&
(strcmp(next, "$base") == 0 || strcmp(next, "$index") == 0)) {
// handle $rev_var$$base$$Register and $rev_var$$index$$Register by
// producing as_Register(opnd_array(#)->base(ra_,this,idx1)).
fprintf(_fp, "as_Register(");
// emit the operand reference
emit_rep_var( rep_var );
rep_var = _strings_to_emit.iter();
assert(strcmp(rep_var, "$base") == 0 || strcmp(rep_var, "$index") == 0, "bad pattern");
// handle base or index
emit_field(rep_var);
rep_var = _strings_to_emit.iter();
assert(strcmp(rep_var, "$Register") == 0, "bad pattern");
// close up the parens
fprintf(_fp, ")");
} else {
emit_rep_var( rep_var );
}
}
} // end replacement and/or subfield
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -574,7 +574,7 @@ void gen_inst_format(FILE *fp, FormDict &globals, InstructForm &inst, bool for_c
// Generate the user-defined portion of the format
if( inst._format ) {
// If there are replacement variables,
// Generate index values needed for determing the operand position
// Generate index values needed for determining the operand position
if( inst._format->_rep_vars.count() )
inst.index_temps(fp, globals);
@ -1832,7 +1832,7 @@ void ArchDesc::declareClasses(FILE *fp) {
break;
case Form::idealP:
case Form::idealN:
fprintf(fp," return opnd_array(1)->type();\n",result);
fprintf(fp," return opnd_array(1)->type();\n");
break;
case Form::idealD:
fprintf(fp," return TypeD::make(opnd_array(1)->constantD());\n");

View File

@ -31,7 +31,7 @@
// The AbstractAssembler is generating code into a CodeBuffer. To make code generation faster,
// the assembler keeps a copy of the code buffers boundaries & modifies them when
// emitting bytes rather than using the code buffers accessor functions all the time.
// The code buffer is updated via set_code_end(...) after emiting a whole instruction.
// The code buffer is updated via set_code_end(...) after emitting a whole instruction.
AbstractAssembler::AbstractAssembler(CodeBuffer* code) {
if (code == NULL) return;
@ -239,6 +239,78 @@ void Label::patch_instructions(MacroAssembler* masm) {
}
}
struct DelayedConstant {
typedef void (*value_fn_t)();
BasicType type;
intptr_t value;
value_fn_t value_fn;
// This limit of 20 is generous for initial uses.
// The limit needs to be large enough to store the field offsets
// into classes which do not have statically fixed layouts.
// (Initial use is for method handle object offsets.)
// Look for uses of "delayed_value" in the source code
// and make sure this number is generous enough to handle all of them.
enum { DC_LIMIT = 20 };
static DelayedConstant delayed_constants[DC_LIMIT];
static DelayedConstant* add(BasicType type, value_fn_t value_fn);
bool match(BasicType t, value_fn_t cfn) {
return type == t && value_fn == cfn;
}
static void update_all();
};
DelayedConstant DelayedConstant::delayed_constants[DC_LIMIT];
// Default C structure initialization rules have the following effect here:
// = { { (BasicType)0, (intptr_t)NULL }, ... };
DelayedConstant* DelayedConstant::add(BasicType type,
DelayedConstant::value_fn_t cfn) {
for (int i = 0; i < DC_LIMIT; i++) {
DelayedConstant* dcon = &delayed_constants[i];
if (dcon->match(type, cfn))
return dcon;
if (dcon->value_fn == NULL) {
// (cmpxchg not because this is multi-threaded but because I'm paranoid)
if (Atomic::cmpxchg_ptr(CAST_FROM_FN_PTR(void*, cfn), &dcon->value_fn, NULL) == NULL) {
dcon->type = type;
return dcon;
}
}
}
// If this assert is hit (in pre-integration testing!) then re-evaluate
// the comment on the definition of DC_LIMIT.
guarantee(false, "too many delayed constants");
return NULL;
}
void DelayedConstant::update_all() {
for (int i = 0; i < DC_LIMIT; i++) {
DelayedConstant* dcon = &delayed_constants[i];
if (dcon->value_fn != NULL && dcon->value == 0) {
typedef int (*int_fn_t)();
typedef address (*address_fn_t)();
switch (dcon->type) {
case T_INT: dcon->value = (intptr_t) ((int_fn_t) dcon->value_fn)(); break;
case T_ADDRESS: dcon->value = (intptr_t) ((address_fn_t)dcon->value_fn)(); break;
}
}
}
}
intptr_t* AbstractAssembler::delayed_value_addr(int(*value_fn)()) {
DelayedConstant* dcon = DelayedConstant::add(T_INT, (DelayedConstant::value_fn_t) value_fn);
return &dcon->value;
}
intptr_t* AbstractAssembler::delayed_value_addr(address(*value_fn)()) {
DelayedConstant* dcon = DelayedConstant::add(T_ADDRESS, (DelayedConstant::value_fn_t) value_fn);
return &dcon->value;
}
void AbstractAssembler::update_delayed_values() {
DelayedConstant::update_all();
}
void AbstractAssembler::block_comment(const char* comment) {
if (sect() == CodeBuffer::SECT_INSTS) {

View File

@ -22,7 +22,7 @@
*
*/
// This file contains platform-independant assembler declarations.
// This file contains platform-independent assembler declarations.
class CodeBuffer;
class MacroAssembler;
@ -140,6 +140,28 @@ class Label VALUE_OBJ_CLASS_SPEC {
}
};
// A union type for code which has to assemble both constant and
// non-constant operands, when the distinction cannot be made
// statically.
class RegisterConstant VALUE_OBJ_CLASS_SPEC {
private:
Register _r;
intptr_t _c;
public:
RegisterConstant(): _r(noreg), _c(0) {}
RegisterConstant(Register r): _r(r), _c(0) {}
RegisterConstant(intptr_t c): _r(noreg), _c(c) {}
Register as_register() const { assert(is_register(),""); return _r; }
intptr_t as_constant() const { assert(is_constant(),""); return _c; }
Register register_or_noreg() const { return _r; }
intptr_t constant_or_zero() const { return _c; }
bool is_register() const { return _r != noreg; }
bool is_constant() const { return _r == noreg; }
};
// The Abstract Assembler: Pure assembler doing NO optimizations on the
// instruction level; i.e., what you write is what you get.
@ -280,6 +302,26 @@ class AbstractAssembler : public ResourceObj {
inline address address_constant(Label& L);
inline address address_table_constant(GrowableArray<Label*> label);
// Bootstrapping aid to cope with delayed determination of constants.
// Returns a static address which will eventually contain the constant.
// The value zero (NULL) stands instead of a constant which is still uncomputed.
// Thus, the eventual value of the constant must not be zero.
// This is fine, since this is designed for embedding object field
// offsets in code which must be generated before the object class is loaded.
// Field offsets are never zero, since an object's header (mark word)
// is located at offset zero.
RegisterConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0) {
return delayed_value(delayed_value_addr(value_fn), tmp, offset);
}
RegisterConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0) {
return delayed_value(delayed_value_addr(value_fn), tmp, offset);
}
virtual RegisterConstant delayed_value(intptr_t* delayed_value_addr, Register tmp, int offset) = 0;
// Last overloading is platform-dependent; look in assembler_<arch>.cpp.
static intptr_t* delayed_value_addr(int(*constant_fn)());
static intptr_t* delayed_value_addr(address(*constant_fn)());
static void update_delayed_values();
// Bang stack to trigger StackOverflowError at a safe location
// implementation delegates to machine-specific bang_stack_with_offset
void generate_stack_overflow_check( int frame_size_in_bytes );

View File

@ -541,7 +541,7 @@ void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) {
// is report a value that will meet correctly with any downstream
// reference types on paths that will truly be executed. This null type
// meets with any reference type to yield that same reference type.
// (The compiler will generate an unconditonal exception here.)
// (The compiler will generate an unconditional exception here.)
push(null_type());
return;
}

View File

@ -156,7 +156,7 @@ symbolOop SymbolTable::basic_add(int index, u1 *name, int len,
symbolOop test = lookup(index, (char*)name, len, hashValue);
if (test != NULL) {
// A race occured and another thread introduced the symbol, this one
// A race occurred and another thread introduced the symbol, this one
// will be dropped and collected.
return test;
}
@ -193,7 +193,7 @@ bool SymbolTable::basic_add(constantPoolHandle cp, int names_count,
int index = hash_to_index(hashValues[i]);
symbolOop test = lookup(index, names[i], lengths[i], hashValues[i]);
if (test != NULL) {
// A race occured and another thread introduced the symbol, this one
// A race occurred and another thread introduced the symbol, this one
// will be dropped and collected. Use test instead.
cp->symbol_at_put(cp_indices[i], test);
} else {

View File

@ -380,7 +380,7 @@ address nmethod::handler_for_exception_and_pc(Handle exception, address pc) {
void nmethod::add_handler_for_exception_and_pc(Handle exception, address pc, address handler) {
// There are potential race conditions during exception cache updates, so we
// must own the ExceptionCache_lock before doing ANY modifications. Because
// we dont lock during reads, it is possible to have several threads attempt
// we don't lock during reads, it is possible to have several threads attempt
// to update the cache with the same data. We need to check for already inserted
// copies of the current data before adding it.

View File

@ -167,7 +167,7 @@ class nmethod : public CodeBlob {
nmFlags flags; // various flags to keep track of nmethod state
bool _markedForDeoptimization; // Used for stack deoptimization
enum { alive = 0,
not_entrant = 1, // uncommon trap has happend but activations may still exist
not_entrant = 1, // uncommon trap has happened but activations may still exist
zombie = 2,
unloaded = 3 };

View File

@ -393,7 +393,7 @@ class CMSAdaptiveSizePolicy : public AdaptiveSizePolicy {
// Restarts the concurrent phases timer.
void concurrent_phases_resume();
// Time begining and end of the marking phase for
// Time beginning and end of the marking phase for
// a synchronous MS collection. A MS collection
// that finishes in the foreground can have started
// in the background. These methods capture the

View File

@ -69,7 +69,7 @@ class CMSGCAdaptivePolicyCounters : public GCAdaptivePolicyCounters {
// end of the sweep of the tenured generation.
PerfVariable* _avg_cms_free_counter;
// Average of the free space in the tenured generation at the
// start of the sweep of the tenured genertion.
// start of the sweep of the tenured generation.
PerfVariable* _avg_cms_free_at_sweep_counter;
// Average of the free space in the tenured generation at the
// after any resizing of the tenured generation at the end

View File

@ -4178,7 +4178,7 @@ bool CMSCollector::do_marking_mt(bool asynch) {
// and is deferred for now; see CR# TBF. 07252005YSR. XXX
assert(!CMSAbortSemantics || tsk.aborted(), "Inconsistency");
// If _restart_addr is non-NULL, a marking stack overflow
// occured; we need to do a fresh marking iteration from the
// occurred; we need to do a fresh marking iteration from the
// indicated restart address.
if (_foregroundGCIsActive && asynch) {
// We may be running into repeated stack overflows, having
@ -4221,7 +4221,7 @@ bool CMSCollector::do_marking_st(bool asynch) {
// should be incremental with periodic yields.
_markBitMap.iterate(&markFromRootsClosure);
// If _restart_addr is non-NULL, a marking stack overflow
// occured; we need to do a fresh iteration from the
// occurred; we need to do a fresh iteration from the
// indicated restart address.
while (_restart_addr != NULL) {
if (_foregroundGCIsActive && asynch) {

View File

@ -133,14 +133,12 @@ void ConcurrentG1RefineThread::queueBasedRefinement() {
_co_tracker.update(false);
if (G1SmoothConcRefine) {
start_vtime_sec = os::elapsedVTime();
prev_buffer_num = curr_buffer_num;
_sts.leave();
os::sleep(Thread::current(), (jlong) _interval_ms, false);
_sts.join();
start_vtime_sec = os::elapsedVTime();
}
n_logs++;
}
// Make sure we harvest the PYA, if any.

View File

@ -420,6 +420,10 @@ ConcurrentMark::ConcurrentMark(ReservedSpace rs,
_has_overflown(false),
_concurrent(false),
_has_aborted(false),
_restart_for_overflow(false),
_concurrent_marking_in_progress(false),
_should_gray_objects(false),
// _verbose_level set below

View File

@ -107,7 +107,7 @@ void ConcurrentMarkThread::run() {
if (PrintGC) {
gclog_or_tty->date_stamp(PrintGCDateStamps);
gclog_or_tty->stamp(PrintGCTimeStamps);
tty->print_cr("[GC concurrent-mark-start]");
gclog_or_tty->print_cr("[GC concurrent-mark-start]");
}
if (!g1_policy->in_young_gc_mode()) {
@ -320,8 +320,6 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() {
set_in_progress();
clear_started();
if (TraceConcurrentMark) gclog_or_tty->print_cr("CM-starting");
return;
}
// Note: this method, although exported by the ConcurrentMarkSweepThread,

View File

@ -78,8 +78,8 @@ size_t DirtyCardQueueSet::num_par_ids() {
void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
int max_completed_queue,
Mutex* lock) {
PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue);
Mutex* lock, PtrQueueSet* fl_owner) {
PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner);
set_buffer_size(DCQBarrierQueueBufferSize);
set_process_completed_threshold(DCQBarrierProcessCompletedThreshold);

View File

@ -88,7 +88,7 @@ public:
void initialize(Monitor* cbl_mon, Mutex* fl_lock,
int max_completed_queue = 0,
Mutex* lock = NULL);
Mutex* lock = NULL, PtrQueueSet* fl_owner = NULL);
// The number of parallel ids that can be claimed to allow collector or
// mutator threads to do card-processing work.

View File

@ -136,6 +136,14 @@ public:
int calls() { return _calls; }
};
class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure {
public:
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
*card_ptr = CardTableModRefBS::dirty_card_val();
return true;
}
};
YoungList::YoungList(G1CollectedHeap* g1h)
: _g1h(g1h), _head(NULL),
_scan_only_head(NULL), _scan_only_tail(NULL), _curr_scan_only(NULL),
@ -812,6 +820,40 @@ public:
}
};
class RebuildRSOutOfRegionClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
UpdateRSOopClosure _cl;
int _worker_i;
public:
RebuildRSOutOfRegionClosure(G1CollectedHeap* g1, int worker_i = 0) :
_cl(g1->g1_rem_set()->as_HRInto_G1RemSet(), worker_i),
_worker_i(worker_i),
_g1h(g1)
{ }
bool doHeapRegion(HeapRegion* r) {
if (!r->continuesHumongous()) {
_cl.set_from(r);
r->oop_iterate(&_cl);
}
return false;
}
};
class ParRebuildRSTask: public AbstractGangTask {
G1CollectedHeap* _g1;
public:
ParRebuildRSTask(G1CollectedHeap* g1)
: AbstractGangTask("ParRebuildRSTask"),
_g1(g1)
{ }
void work(int i) {
RebuildRSOutOfRegionClosure rebuild_rs(_g1, i);
_g1->heap_region_par_iterate_chunked(&rebuild_rs, i,
HeapRegion::RebuildRSClaimValue);
}
};
void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
size_t word_size) {
ResourceMark rm;
@ -918,24 +960,35 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
reset_gc_time_stamp();
// Since everything potentially moved, we will clear all remembered
// sets, and clear all cards. Later we will also cards in the used
// portion of the heap after the resizing (which could be a shrinking.)
// We will also reset the GC time stamps of the regions.
// sets, and clear all cards. Later we will rebuild remebered
// sets. We will also reset the GC time stamps of the regions.
PostMCRemSetClearClosure rs_clear(mr_bs());
heap_region_iterate(&rs_clear);
// Resize the heap if necessary.
resize_if_necessary_after_full_collection(full ? 0 : word_size);
// Since everything potentially moved, we will clear all remembered
// sets, but also dirty all cards corresponding to used regions.
PostMCRemSetInvalidateClosure rs_invalidate(mr_bs());
heap_region_iterate(&rs_invalidate);
if (_cg1r->use_cache()) {
_cg1r->clear_and_record_card_counts();
_cg1r->clear_hot_cache();
}
// Rebuild remembered sets of all regions.
if (ParallelGCThreads > 0) {
ParRebuildRSTask rebuild_rs_task(this);
assert(check_heap_region_claim_values(
HeapRegion::InitialClaimValue), "sanity check");
set_par_threads(workers()->total_workers());
workers()->run_task(&rebuild_rs_task);
set_par_threads(0);
assert(check_heap_region_claim_values(
HeapRegion::RebuildRSClaimValue), "sanity check");
reset_heap_region_claim_values();
} else {
RebuildRSOutOfRegionClosure rebuild_rs(this);
heap_region_iterate(&rebuild_rs);
}
if (PrintGC) {
print_size_transition(gclog_or_tty, g1h_prev_used, used(), capacity());
}
@ -961,7 +1014,8 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
// dirtied, so this should abandon those logs, and set "do_traversal"
// to true.
concurrent_g1_refine()->set_pya_restart();
assert(!G1DeferredRSUpdate
|| (G1DeferredRSUpdate && (dirty_card_queue_set().completed_buffers_num() == 0)), "Should not be any");
assert(regions_accounted_for(), "Region leakage!");
}
@ -1466,6 +1520,13 @@ jint G1CollectedHeap::initialize() {
G1DirtyCardQueueMax,
Shared_DirtyCardQ_lock);
}
if (G1DeferredRSUpdate) {
dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
DirtyCardQ_FL_lock,
0,
Shared_DirtyCardQ_lock,
&JavaThread::dirty_card_queue_set());
}
// In case we're keeping closure specialization stats, initialize those
// counts and that mechanism.
SpecializationStats::clear();
@ -2316,7 +2377,6 @@ class VerifyMarkedObjsClosure: public ObjectClosure {
void
G1CollectedHeap::checkConcurrentMark() {
VerifyMarkedObjsClosure verifycl(this);
doConcurrentMark();
// MutexLockerEx x(getMarkBitMapLock(),
// Mutex::_no_safepoint_check_flag);
object_iterate(&verifycl);
@ -2493,7 +2553,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
guarantee(_in_cset_fast_test == NULL, "invariant");
guarantee(_in_cset_fast_test_base == NULL, "invariant");
_in_cset_fast_test_length = n_regions();
_in_cset_fast_test_length = max_regions();
_in_cset_fast_test_base =
NEW_C_HEAP_ARRAY(bool, _in_cset_fast_test_length);
memset(_in_cset_fast_test_base, false,
@ -2513,7 +2573,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
}
save_marks();
// We must do this before any possible evacuation that should propogate
// We must do this before any possible evacuation that should propagate
// marks, including evacuation of popular objects in a popular pause.
if (mark_in_progress()) {
double start_time_sec = os::elapsedTime();
@ -2626,9 +2686,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(HeapRegion* popular_region) {
#endif // SCAN_ONLY_VERBOSE
double end_time_sec = os::elapsedTime();
if (!evacuation_failed()) {
g1_policy()->record_pause_time((end_time_sec - start_time_sec)*1000.0);
}
double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS;
g1_policy()->record_pause_time_ms(pause_time_ms);
GCOverheadReporter::recordSTWEnd(end_time_sec);
g1_policy()->record_collection_pause_end(popular_region != NULL,
abandoned);
@ -2919,27 +2978,51 @@ public:
}
};
class RecreateRSetEntriesClosure: public OopClosure {
class UpdateRSetImmediate : public OopsInHeapRegionClosure {
private:
G1CollectedHeap* _g1;
G1RemSet* _g1_rem_set;
HeapRegion* _from;
public:
RecreateRSetEntriesClosure(G1CollectedHeap* g1, HeapRegion* from) :
_g1(g1), _g1_rem_set(g1->g1_rem_set()), _from(from)
{}
UpdateRSetImmediate(G1CollectedHeap* g1) :
_g1(g1), _g1_rem_set(g1->g1_rem_set()) {}
void do_oop(narrowOop* p) {
guarantee(false, "NYI");
}
void do_oop(oop* p) {
assert(_from->is_in_reserved(p), "paranoia");
if (*p != NULL) {
_g1_rem_set->write_ref(_from, p);
if (*p != NULL && !_from->is_survivor()) {
_g1_rem_set->par_write_ref(_from, p, 0);
}
}
};
class UpdateRSetDeferred : public OopsInHeapRegionClosure {
private:
G1CollectedHeap* _g1;
DirtyCardQueue *_dcq;
CardTableModRefBS* _ct_bs;
public:
UpdateRSetDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) :
_g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) {}
void do_oop(narrowOop* p) {
guarantee(false, "NYI");
}
void do_oop(oop* p) {
assert(_from->is_in_reserved(p), "paranoia");
if (!_from->is_in_reserved(*p) && !_from->is_survivor()) {
size_t card_index = _ct_bs->index_for(p);
if (_ct_bs->mark_card_deferred(card_index)) {
_dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index));
}
}
}
};
class RemoveSelfPointerClosure: public ObjectClosure {
private:
G1CollectedHeap* _g1;
@ -2947,11 +3030,11 @@ private:
HeapRegion* _hr;
size_t _prev_marked_bytes;
size_t _next_marked_bytes;
OopsInHeapRegionClosure *_cl;
public:
RemoveSelfPointerClosure(G1CollectedHeap* g1, HeapRegion* hr) :
_g1(g1), _cm(_g1->concurrent_mark()), _hr(hr),
_prev_marked_bytes(0), _next_marked_bytes(0)
{}
RemoveSelfPointerClosure(G1CollectedHeap* g1, OopsInHeapRegionClosure* cl) :
_g1(g1), _cm(_g1->concurrent_mark()), _prev_marked_bytes(0),
_next_marked_bytes(0), _cl(cl) {}
size_t prev_marked_bytes() { return _prev_marked_bytes; }
size_t next_marked_bytes() { return _next_marked_bytes; }
@ -2989,8 +3072,7 @@ public:
// that, if evacuation fails, we might have remembered set
// entries missing given that we skipped cards on the
// collection set. So, we'll recreate such entries now.
RecreateRSetEntriesClosure cl(_g1, _hr);
obj->oop_iterate(&cl);
obj->oop_iterate(_cl);
assert(_cm->isPrevMarked(obj), "Should be marked!");
} else {
// The object has been either evacuated or is dead. Fill it with a
@ -3003,14 +3085,23 @@ public:
};
void G1CollectedHeap::remove_self_forwarding_pointers() {
UpdateRSetImmediate immediate_update(_g1h);
DirtyCardQueue dcq(&_g1h->dirty_card_queue_set());
UpdateRSetDeferred deferred_update(_g1h, &dcq);
OopsInHeapRegionClosure *cl;
if (G1DeferredRSUpdate) {
cl = &deferred_update;
} else {
cl = &immediate_update;
}
HeapRegion* cur = g1_policy()->collection_set();
while (cur != NULL) {
assert(g1_policy()->assertMarkedBytesDataOK(), "Should be!");
RemoveSelfPointerClosure rspc(_g1h, cl);
if (cur->evacuation_failed()) {
RemoveSelfPointerClosure rspc(_g1h, cur);
assert(cur->in_collection_set(), "bad CS");
cl->set_region(cur);
cur->object_iterate(&rspc);
// A number of manipulations to make the TAMS be the current top,
@ -3519,6 +3610,9 @@ class G1ParScanThreadState : public StackObj {
protected:
G1CollectedHeap* _g1h;
RefToScanQueue* _refs;
DirtyCardQueue _dcq;
CardTableModRefBS* _ct_bs;
G1RemSet* _g1_rem;
typedef GrowableArray<oop*> OverflowQueue;
OverflowQueue* _overflowed_refs;
@ -3560,10 +3654,32 @@ protected:
void add_to_undo_waste(size_t waste) { _undo_waste += waste; }
DirtyCardQueue& dirty_card_queue() { return _dcq; }
CardTableModRefBS* ctbs() { return _ct_bs; }
void immediate_rs_update(HeapRegion* from, oop* p, int tid) {
_g1_rem->par_write_ref(from, p, tid);
}
void deferred_rs_update(HeapRegion* from, oop* p, int tid) {
// If the new value of the field points to the same region or
// is the to-space, we don't need to include it in the Rset updates.
if (!from->is_in_reserved(*p) && !from->is_survivor()) {
size_t card_index = ctbs()->index_for(p);
// If the card hasn't been added to the buffer, do it.
if (ctbs()->mark_card_deferred(card_index)) {
dirty_card_queue().enqueue((jbyte*)ctbs()->byte_for_index(card_index));
}
}
}
public:
G1ParScanThreadState(G1CollectedHeap* g1h, int queue_num)
: _g1h(g1h),
_refs(g1h->task_queue(queue_num)),
_dcq(&g1h->dirty_card_queue_set()),
_ct_bs((CardTableModRefBS*)_g1h->barrier_set()),
_g1_rem(g1h->g1_rem_set()),
_hash_seed(17), _queue_num(queue_num),
_term_attempts(0),
_age_table(false),
@ -3641,6 +3757,14 @@ public:
int refs_to_scan() { return refs()->size(); }
int overflowed_refs_to_scan() { return overflowed_refs()->length(); }
void update_rs(HeapRegion* from, oop* p, int tid) {
if (G1DeferredRSUpdate) {
deferred_rs_update(from, p, tid);
} else {
immediate_rs_update(from, p, tid);
}
}
HeapWord* allocate_slow(GCAllocPurpose purpose, size_t word_sz) {
HeapWord* obj = NULL;
@ -3809,7 +3933,6 @@ public:
}
};
G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
_g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()),
_par_scan_state(par_scan_state) { }
@ -3835,7 +3958,7 @@ void G1ParScanClosure::do_oop_nv(oop* p) {
assert(obj == *p, "the value of *p should not have changed");
_par_scan_state->push_on_queue(p);
} else {
_g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num());
_par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
}
}
}
@ -3973,13 +4096,13 @@ void G1ParCopyClosure<do_gen_barrier, barrier,
}
// When scanning the RS, we only care about objs in CS.
if (barrier == G1BarrierRS) {
_g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num());
_par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
}
}
// When scanning moved objs, must look at all oops.
if (barrier == G1BarrierEvac && obj != NULL) {
_g1_rem->par_write_ref(_from, p, _par_scan_state->queue_num());
_par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
}
if (do_gen_barrier && obj != NULL) {
@ -4128,6 +4251,7 @@ public:
G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss);
G1ParScanPermClosure only_scan_perm_cl(_g1h, &pss);
G1ParScanHeapRSClosure only_scan_heap_rs_cl(_g1h, &pss);
G1ParScanAndMarkExtRootClosure scan_mark_root_cl(_g1h, &pss);
G1ParScanAndMarkPermClosure scan_mark_perm_cl(_g1h, &pss);
G1ParScanAndMarkHeapRSClosure scan_mark_heap_rs_cl(_g1h, &pss);
@ -4383,7 +4507,6 @@ void G1CollectedHeap::evacuate_collection_set() {
g1_rem_set()->prepare_for_oops_into_collection_set_do();
concurrent_g1_refine()->set_use_cache(false);
int n_workers = (ParallelGCThreads > 0 ? workers()->total_workers() : 1);
set_par_threads(n_workers);
G1ParTask g1_par_task(this, n_workers, _task_queues);
@ -4391,8 +4514,9 @@ void G1CollectedHeap::evacuate_collection_set() {
change_strong_roots_parity(); // In preparation for parallel strong roots.
rem_set()->prepare_for_younger_refs_iterate(true);
double start_par = os::elapsedTime();
assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
double start_par = os::elapsedTime();
if (ParallelGCThreads > 0) {
// The individual threads will set their evac-failure closures.
workers()->run_task(&g1_par_task);
@ -4412,8 +4536,8 @@ void G1CollectedHeap::evacuate_collection_set() {
G1KeepAliveClosure keep_alive(this);
JNIHandles::weak_oops_do(&is_alive, &keep_alive);
}
g1_rem_set()->cleanup_after_oops_into_collection_set_do();
concurrent_g1_refine()->set_use_cache(true);
finalize_for_evac_failure();
@ -4424,7 +4548,6 @@ void G1CollectedHeap::evacuate_collection_set() {
if (evacuation_failed()) {
remove_self_forwarding_pointers();
if (PrintGCDetails) {
gclog_or_tty->print(" (evacuation failed)");
} else if (PrintGC) {
@ -4432,6 +4555,14 @@ void G1CollectedHeap::evacuate_collection_set() {
}
}
if (G1DeferredRSUpdate) {
RedirtyLoggedCardTableEntryFastClosure redirty;
dirty_card_queue_set().set_closure(&redirty);
dirty_card_queue_set().apply_closure_to_all_completed_buffers();
JavaThread::dirty_card_queue_set().merge_bufferlists(&dirty_card_queue_set());
assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
}
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
}

View File

@ -457,6 +457,10 @@ protected:
// And it's mod ref barrier set, used to track updates for the above.
ModRefBarrierSet* _mr_bs;
// A set of cards that cover the objects for which the Rsets should be updated
// concurrently after the collection.
DirtyCardQueueSet _dirty_card_queue_set;
// The Heap Region Rem Set Iterator.
HeapRegionRemSetIterator** _rem_set_iterator;
@ -666,6 +670,9 @@ public:
RefToScanQueue *task_queue(int i);
// A set of cards where updates happened during the GC
DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; }
// Create a G1CollectedHeap with the specified policy.
// Must call the initialize method afterwards.
// May not return if something goes wrong.

View File

@ -1014,7 +1014,7 @@ void G1CollectorPolicy::record_full_collection_end() {
_all_full_gc_times_ms->add(full_gc_time_ms);
update_recent_gc_times(end_sec, full_gc_time_sec);
update_recent_gc_times(end_sec, full_gc_time_ms);
_g1->clear_full_collection();
@ -1475,6 +1475,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular,
size_t cur_used_bytes = _g1->used();
assert(cur_used_bytes == _g1->recalculate_used(), "It should!");
bool last_pause_included_initial_mark = false;
bool update_stats = !abandoned && !_g1->evacuation_failed();
#ifndef PRODUCT
if (G1YoungSurvRateVerbose) {
@ -1535,7 +1536,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular,
_n_pauses++;
if (!abandoned) {
if (update_stats) {
_recent_CH_strong_roots_times_ms->add(_cur_CH_strong_roots_dur_ms);
_recent_G1_strong_roots_times_ms->add(_cur_G1_strong_roots_dur_ms);
_recent_evac_times_ms->add(evac_ms);
@ -1636,7 +1637,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular,
double termination_time = avg_value(_par_last_termination_times_ms);
double parallel_other_time;
if (!abandoned) {
if (update_stats) {
MainBodySummary* body_summary = summary->main_body_summary();
guarantee(body_summary != NULL, "should not be null!");
@ -1852,7 +1853,7 @@ void G1CollectorPolicy::record_collection_pause_end(bool popular,
// <NEW PREDICTION>
if (!popular && !abandoned) {
if (!popular && update_stats) {
double pause_time_ms = elapsed_ms;
size_t diff = 0;

View File

@ -966,7 +966,7 @@ public:
record_termination_time(0, ms);
}
void record_pause_time(double ms) {
void record_pause_time_ms(double ms) {
_last_pause_time_ms = ms;
}

View File

@ -105,33 +105,6 @@ StupidG1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
_g1->heap_region_iterate(&rc);
}
class UpdateRSOopClosure: public OopClosure {
HeapRegion* _from;
HRInto_G1RemSet* _rs;
int _worker_i;
public:
UpdateRSOopClosure(HRInto_G1RemSet* rs, int worker_i = 0) :
_from(NULL), _rs(rs), _worker_i(worker_i) {
guarantee(_rs != NULL, "Requires an HRIntoG1RemSet");
}
void set_from(HeapRegion* from) {
assert(from != NULL, "from region must be non-NULL");
_from = from;
}
virtual void do_oop(narrowOop* p) {
guarantee(false, "NYI");
}
virtual void do_oop(oop* p) {
assert(_from != NULL, "from region must be non-NULL");
_rs->par_write_ref(_from, p, _worker_i);
}
// Override: this closure is idempotent.
// bool idempotent() { return true; }
bool apply_to_weak_ref_discovered_field() { return true; }
};
class UpdateRSOutOfRegionClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
ModRefBarrierSet* _mr_bs;
@ -177,11 +150,19 @@ HRInto_G1RemSet::HRInto_G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs)
_cards_scanned(NULL), _total_cards_scanned(0)
{
_seq_task = new SubTasksDone(NumSeqTasks);
_new_refs = NEW_C_HEAP_ARRAY(GrowableArray<oop*>*, ParallelGCThreads);
guarantee(n_workers() > 0, "There should be some workers");
_new_refs = NEW_C_HEAP_ARRAY(GrowableArray<oop*>*, n_workers());
for (uint i = 0; i < n_workers(); i++) {
_new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray<oop*>(8192,true);
}
}
HRInto_G1RemSet::~HRInto_G1RemSet() {
delete _seq_task;
for (uint i = 0; i < n_workers(); i++) {
delete _new_refs[i];
}
FREE_C_HEAP_ARRAY(GrowableArray<oop*>*, _new_refs);
}
void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) {
@ -281,8 +262,9 @@ public:
if (!_ct_bs->is_card_claimed(card_index) &&
!_ct_bs->is_card_dirty(card_index)) {
assert(_ct_bs->is_card_clean(card_index) ||
_ct_bs->is_card_claimed(card_index),
"Card is either dirty, clean, or claimed");
_ct_bs->is_card_claimed(card_index) ||
_ct_bs->is_card_deferred(card_index),
"Card is either clean, claimed or deferred");
if (_ct_bs->claim_card(card_index))
scanCard(card_index, card_region);
}
@ -338,14 +320,12 @@ void HRInto_G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) {
_g1p->record_scan_rs_start_time(worker_i, rs_time_start * 1000.0);
_g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0);
if (ParallelGCThreads > 0) {
// In this case, we called scanNewRefsRS and recorded the corresponding
// time.
double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i);
if (scan_new_refs_time_ms > 0.0) {
closure_app_time_ms += scan_new_refs_time_ms;
}
double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i);
if (scan_new_refs_time_ms > 0.0) {
closure_app_time_ms += scan_new_refs_time_ms;
}
_g1p->record_obj_copy_time(worker_i, closure_app_time_ms);
}
@ -469,8 +449,8 @@ HRInto_G1RemSet::scanNewRefsRS(OopsInHeapRegionClosure* oc,
double scan_new_refs_start_sec = os::elapsedTime();
G1CollectedHeap* g1h = G1CollectedHeap::heap();
CardTableModRefBS* ct_bs = (CardTableModRefBS*) (g1h->barrier_set());
while (_new_refs[worker_i]->is_nonempty()) {
oop* p = _new_refs[worker_i]->pop();
for (int i = 0; i < _new_refs[worker_i]->length(); i++) {
oop* p = _new_refs[worker_i]->at(i);
oop obj = *p;
// *p was in the collection set when p was pushed on "_new_refs", but
// another thread may have processed this location from an RS, so it
@ -480,10 +460,6 @@ HRInto_G1RemSet::scanNewRefsRS(OopsInHeapRegionClosure* oc,
HeapRegion* r = g1h->heap_region_containing(p);
DEBUG_ONLY(HeapRegion* to = g1h->heap_region_containing(obj));
assert(ParallelGCThreads > 1
|| to->rem_set()->contains_reference(p),
"Invariant: pushed after being added."
"(Not reliable in parallel code.)");
oc->set_region(r);
// If "p" has already been processed concurrently, this is
// idempotent.
@ -538,8 +514,8 @@ HRInto_G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
}
} else {
assert(worker_i == 0, "invariant");
updateRS(0);
scanNewRefsRS(oc, 0);
scanRS(oc, 0);
}
}
@ -559,11 +535,7 @@ prepare_for_oops_into_collection_set_do() {
assert(!_par_traversal_in_progress, "Invariant between iterations.");
if (ParallelGCThreads > 0) {
set_par_traversal(true);
int n_workers = _g1->workers()->total_workers();
_seq_task->set_par_threads(n_workers);
for (uint i = 0; i < ParallelGCThreads; i++)
_new_refs[i] = new (ResourceObj::C_HEAP) GrowableArray<oop*>(8192,true);
_seq_task->set_par_threads((int)n_workers());
if (cg1r->do_traversal()) {
updateRS(0);
// Have to do this again after updaters
@ -587,6 +559,53 @@ class cleanUpIteratorsClosure : public HeapRegionClosure {
}
};
class UpdateRSetOopsIntoCSImmediate : public OopClosure {
G1CollectedHeap* _g1;
public:
UpdateRSetOopsIntoCSImmediate(G1CollectedHeap* g1) : _g1(g1) { }
virtual void do_oop(narrowOop* p) {
guarantee(false, "NYI");
}
virtual void do_oop(oop* p) {
HeapRegion* to = _g1->heap_region_containing(*p);
if (to->in_collection_set()) {
if (to->rem_set()->add_reference(p, 0)) {
_g1->schedule_popular_region_evac(to);
}
}
}
};
class UpdateRSetOopsIntoCSDeferred : public OopClosure {
G1CollectedHeap* _g1;
CardTableModRefBS* _ct_bs;
DirtyCardQueue* _dcq;
public:
UpdateRSetOopsIntoCSDeferred(G1CollectedHeap* g1, DirtyCardQueue* dcq) :
_g1(g1), _ct_bs((CardTableModRefBS*)_g1->barrier_set()), _dcq(dcq) { }
virtual void do_oop(narrowOop* p) {
guarantee(false, "NYI");
}
virtual void do_oop(oop* p) {
oop obj = *p;
if (_g1->obj_in_cs(obj)) {
size_t card_index = _ct_bs->index_for(p);
if (_ct_bs->mark_card_deferred(card_index)) {
_dcq->enqueue((jbyte*)_ct_bs->byte_for_index(card_index));
}
}
}
};
void HRInto_G1RemSet::new_refs_iterate(OopClosure* cl) {
for (size_t i = 0; i < n_workers(); i++) {
for (int j = 0; j < _new_refs[i]->length(); j++) {
oop* p = _new_refs[i]->at(j);
cl->do_oop(p);
}
}
}
void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() {
guarantee( _cards_scanned != NULL, "invariant" );
_total_cards_scanned = 0;
@ -609,11 +628,25 @@ void HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do() {
if (cg1r->do_traversal()) {
cg1r->cg1rThread()->set_do_traversal(false);
}
for (uint i = 0; i < ParallelGCThreads; i++) {
delete _new_refs[i];
}
set_par_traversal(false);
}
if (_g1->evacuation_failed()) {
// Restore remembered sets for the regions pointing into
// the collection set.
if (G1DeferredRSUpdate) {
DirtyCardQueue dcq(&_g1->dirty_card_queue_set());
UpdateRSetOopsIntoCSDeferred deferred_update(_g1, &dcq);
new_refs_iterate(&deferred_update);
} else {
UpdateRSetOopsIntoCSImmediate immediate_update(_g1);
new_refs_iterate(&immediate_update);
}
}
for (uint i = 0; i < n_workers(); i++) {
_new_refs[i]->clear();
}
assert(!_par_traversal_in_progress, "Invariant between iterations.");
}
@ -683,7 +716,8 @@ public:
bool doHeapRegion(HeapRegion* r) {
if (!r->in_collection_set() &&
!r->continuesHumongous() &&
!r->is_young()) {
!r->is_young() &&
!r->is_survivor()) {
_update_rs_oop_cl.set_from(r);
UpdateRSObjectClosure update_rs_obj_cl(&_update_rs_oop_cl);
@ -820,7 +854,7 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {
// before all the cards on the region are dirtied. This is unlikely,
// and it doesn't happen often, but it can happen. So, the extra
// check below filters out those cards.
if (r->is_young()) {
if (r->is_young() || r->is_survivor()) {
return;
}
// While we are processing RSet buffers during the collection, we

View File

@ -155,6 +155,7 @@ protected:
bool _par_traversal_in_progress;
void set_par_traversal(bool b);
GrowableArray<oop*>** _new_refs;
void new_refs_iterate(OopClosure* cl);
public:
// This is called to reset dual hash tables after the gc pause
@ -214,3 +215,27 @@ public:
int n() { return _n; };
HeapWord* start_first() { return _start_first; }
};
class UpdateRSOopClosure: public OopClosure {
HeapRegion* _from;
HRInto_G1RemSet* _rs;
int _worker_i;
public:
UpdateRSOopClosure(HRInto_G1RemSet* rs, int worker_i = 0) :
_from(NULL), _rs(rs), _worker_i(worker_i) {
guarantee(_rs != NULL, "Requires an HRIntoG1RemSet");
}
void set_from(HeapRegion* from) {
assert(from != NULL, "from region must be non-NULL");
_from = from;
}
virtual void do_oop(narrowOop* p);
virtual void do_oop(oop* p);
// Override: this closure is idempotent.
// bool idempotent() { return true; }
bool apply_to_weak_ref_discovered_field() { return true; }
};

View File

@ -31,24 +31,7 @@ inline size_t G1RemSet::n_workers() {
}
inline void HRInto_G1RemSet::write_ref_nv(HeapRegion* from, oop* p) {
oop obj = *p;
assert(from != NULL && from->is_in_reserved(p),
"p is not in a from");
HeapRegion* to = _g1->heap_region_containing(obj);
if (from != to && to != NULL) {
if (!to->popular() && !from->is_survivor()) {
#if G1_REM_SET_LOGGING
gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS"
" for region [" PTR_FORMAT ", " PTR_FORMAT ")",
p, obj,
to->bottom(), to->end());
#endif
assert(to->rem_set() != NULL, "Need per-region 'into' remsets.");
if (to->rem_set()->add_reference(p)) {
_g1->schedule_popular_region_evac(to);
}
}
}
par_write_ref(from, p, 0);
}
inline void HRInto_G1RemSet::write_ref(HeapRegion* from, oop* p) {
@ -82,7 +65,22 @@ inline void HRInto_G1RemSet::par_write_ref(HeapRegion* from, oop* p, int tid) {
HeapRegion* to = _g1->heap_region_containing(obj);
// The test below could be optimized by applying a bit op to to and from.
if (to != NULL && from != NULL && from != to) {
if (!to->popular() && !from->is_survivor()) {
bool update_delayed = false;
// There is a tricky infinite loop if we keep pushing
// self forwarding pointers onto our _new_refs list.
// The _par_traversal_in_progress flag is true during the collection pause,
// false during the evacuation failure handing.
if (_par_traversal_in_progress &&
to->in_collection_set() && !self_forwarded(obj)) {
_new_refs[tid]->push(p);
// Deferred updates to the Cset are either discarded (in the normal case),
// or processed (if an evacuation failure occurs) at the end
// of the collection.
// See HRInto_G1RemSet::cleanup_after_oops_into_collection_set_do().
update_delayed = true;
}
if (!to->popular() && !update_delayed) {
#if G1_REM_SET_LOGGING
gclog_or_tty->print_cr("Adding " PTR_FORMAT " (" PTR_FORMAT ") to RS"
" for region [" PTR_FORMAT ", " PTR_FORMAT ")",
@ -94,11 +92,14 @@ inline void HRInto_G1RemSet::par_write_ref(HeapRegion* from, oop* p, int tid) {
_g1->schedule_popular_region_evac(to);
}
}
// There is a tricky infinite loop if we keep pushing
// self forwarding pointers onto our _new_refs list.
if (_par_traversal_in_progress &&
to->in_collection_set() && !self_forwarded(obj)) {
_new_refs[tid]->push(p);
}
}
}
inline void UpdateRSOopClosure::do_oop(narrowOop* p) {
guarantee(false, "NYI");
}
inline void UpdateRSOopClosure::do_oop(oop* p) {
assert(_from != NULL, "from region must be non-NULL");
_rs->par_write_ref(_from, p, _worker_i);
}

View File

@ -172,6 +172,9 @@
develop(bool, G1RSBarrierUseQueue, true, \
"If true, use queueing RS barrier") \
\
develop(bool, G1DeferredRSUpdate, true, \
"If true, use deferred RS updates") \
\
develop(bool, G1RSLogCheckCardTable, false, \
"If true, verify that no dirty cards remain after RS log " \
"processing.") \

Some files were not shown because too many files have changed in this diff Show More