This commit is contained in:
Morris Meyer 2014-02-28 08:02:20 -08:00
commit c696dd6700
119 changed files with 3098 additions and 2772 deletions

View File

@ -48,7 +48,7 @@ public class Block extends VMObject {
preOrderField = new CIntField(type.getCIntegerField("_pre_order"), 0);
domDepthField = new CIntField(type.getCIntegerField("_dom_depth"), 0);
idomField = type.getAddressField("_idom");
freqField = type.getJFloatField("_freq");
freqField = type.getJDoubleField("_freq");
}
private static AddressField nodesField;
@ -57,7 +57,7 @@ public class Block extends VMObject {
private static CIntField preOrderField;
private static CIntField domDepthField;
private static AddressField idomField;
private static JFloatField freqField;
private static JDoubleField freqField;
public Block(Address addr) {
super(addr);
@ -67,8 +67,8 @@ public class Block extends VMObject {
return (int)preOrderField.getValue(getAddress());
}
public float freq() {
return (float)freqField.getValue(getAddress());
public double freq() {
return (double)freqField.getValue(getAddress());
}
public Node_List nodes() {

View File

@ -2360,18 +2360,6 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return RegMask();
}
const RegMask Matcher::mathExactI_result_proj_mask() {
return RARG4_BITS64_REG_mask();
}
const RegMask Matcher::mathExactL_result_proj_mask() {
return RARG4_BITS64_REG_mask();
}
const RegMask Matcher::mathExactI_flags_proj_mask() {
return INT_FLAGS_mask();
}
%}
//----------ENCODING BLOCK-----------------------------------------------------
@ -7572,16 +7560,6 @@ instruct getAndSetN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src) %{
//----------Arithmetic Instructions--------------------------------------------
// Addition Instructions
// PPC has no instruction setting overflow of 32-bit integer.
//instruct addExactI_rReg(rarg4RegI dst, rRegI src, flagsReg cr) %{
// match(AddExactI dst src);
// effect(DEF cr);
//
// format %{ "ADD $dst, $dst, $src \t// addExact int, sets $cr" %}
// ins_encode( enc_add(dst, dst, src) );
// ins_pipe(pipe_class_default);
//%}
// Register Addition
instruct addI_reg_reg(iRegIdst dst, iRegIsrc_iRegL2Isrc src1, iRegIsrc_iRegL2Isrc src2) %{
match(Set dst (AddI src1 src2));

View File

@ -237,6 +237,10 @@ inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const {
inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
return (ConstantPoolCache**)sp_addr_at( LcpoolCache->sp_offset_in_saved_window());
}
inline oop* frame::interpreter_frame_temp_oop_addr() const {
return (oop *)(fp() + interpreter_frame_oop_temp_offset);
}
#endif // CC_INTERP

View File

@ -2037,19 +2037,6 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return L7_REGP_mask();
}
const RegMask Matcher::mathExactI_result_proj_mask() {
return G1_REGI_mask();
}
const RegMask Matcher::mathExactL_result_proj_mask() {
return G1_REGL_mask();
}
const RegMask Matcher::mathExactI_flags_proj_mask() {
return INT_FLAGS_mask();
}
%}

View File

@ -247,6 +247,10 @@ inline intptr_t* frame::interpreter_frame_tos_address() const {
}
}
inline oop* frame::interpreter_frame_temp_oop_addr() const {
return (oop *)(fp() + interpreter_frame_oop_temp_offset);
}
#endif /* CC_INTERP */
inline int frame::pd_oop_map_offset_adjustment() const {

File diff suppressed because it is too large Load Diff

View File

@ -651,7 +651,12 @@ class MacroAssembler: public Assembler {
Label& done, Label* slow_case = NULL,
BiasedLockingCounters* counters = NULL);
void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done);
#ifdef COMPILER2
// Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file.
// See full desription in macroAssembler_x86.cpp.
void fast_lock(Register obj, Register box, Register tmp, Register scr, BiasedLockingCounters* counters);
void fast_unlock(Register obj, Register box, Register tmp);
#endif
Condition negate_condition(Condition cond);

View File

@ -1542,19 +1542,6 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return EBP_REG_mask();
}
const RegMask Matcher::mathExactI_result_proj_mask() {
return EAX_REG_mask();
}
const RegMask Matcher::mathExactL_result_proj_mask() {
ShouldNotReachHere();
return RegMask();
}
const RegMask Matcher::mathExactI_flags_proj_mask() {
return INT_FLAGS_mask();
}
// Returns true if the high 32 bits of the value is known to be zero.
bool is_operand_hi32_zero(Node* n) {
int opc = n->Opcode();
@ -2918,542 +2905,6 @@ encode %{
emit_d8 (cbuf,0 );
%}
// Because the transitions from emitted code to the runtime
// monitorenter/exit helper stubs are so slow it's critical that
// we inline both the stack-locking fast-path and the inflated fast path.
//
// See also: cmpFastLock and cmpFastUnlock.
//
// What follows is a specialized inline transliteration of the code
// in slow_enter() and slow_exit(). If we're concerned about I$ bloat
// another option would be to emit TrySlowEnter and TrySlowExit methods
// at startup-time. These methods would accept arguments as
// (rax,=Obj, rbx=Self, rcx=box, rdx=Scratch) and return success-failure
// indications in the icc.ZFlag. Fast_Lock and Fast_Unlock would simply
// marshal the arguments and emit calls to TrySlowEnter and TrySlowExit.
// In practice, however, the # of lock sites is bounded and is usually small.
// Besides the call overhead, TrySlowEnter and TrySlowExit might suffer
// if the processor uses simple bimodal branch predictors keyed by EIP
// Since the helper routines would be called from multiple synchronization
// sites.
//
// An even better approach would be write "MonitorEnter()" and "MonitorExit()"
// in java - using j.u.c and unsafe - and just bind the lock and unlock sites
// to those specialized methods. That'd give us a mostly platform-independent
// implementation that the JITs could optimize and inline at their pleasure.
// Done correctly, the only time we'd need to cross to native could would be
// to park() or unpark() threads. We'd also need a few more unsafe operators
// to (a) prevent compiler-JIT reordering of non-volatile accesses, and
// (b) explicit barriers or fence operations.
//
// TODO:
//
// * Arrange for C2 to pass "Self" into Fast_Lock and Fast_Unlock in one of the registers (scr).
// This avoids manifesting the Self pointer in the Fast_Lock and Fast_Unlock terminals.
// Given TLAB allocation, Self is usually manifested in a register, so passing it into
// the lock operators would typically be faster than reifying Self.
//
// * Ideally I'd define the primitives as:
// fast_lock (nax Obj, nax box, EAX tmp, nax scr) where box, tmp and scr are KILLED.
// fast_unlock (nax Obj, EAX box, nax tmp) where box and tmp are KILLED
// Unfortunately ADLC bugs prevent us from expressing the ideal form.
// Instead, we're stuck with a rather awkward and brittle register assignments below.
// Furthermore the register assignments are overconstrained, possibly resulting in
// sub-optimal code near the synchronization site.
//
// * Eliminate the sp-proximity tests and just use "== Self" tests instead.
// Alternately, use a better sp-proximity test.
//
// * Currently ObjectMonitor._Owner can hold either an sp value or a (THREAD *) value.
// Either one is sufficient to uniquely identify a thread.
// TODO: eliminate use of sp in _owner and use get_thread(tr) instead.
//
// * Intrinsify notify() and notifyAll() for the common cases where the
// object is locked by the calling thread but the waitlist is empty.
// avoid the expensive JNI call to JVM_Notify() and JVM_NotifyAll().
//
// * use jccb and jmpb instead of jcc and jmp to improve code density.
// But beware of excessive branch density on AMD Opterons.
//
// * Both Fast_Lock and Fast_Unlock set the ICC.ZF to indicate success
// or failure of the fast-path. If the fast-path fails then we pass
// control to the slow-path, typically in C. In Fast_Lock and
// Fast_Unlock we often branch to DONE_LABEL, just to find that C2
// will emit a conditional branch immediately after the node.
// So we have branches to branches and lots of ICC.ZF games.
// Instead, it might be better to have C2 pass a "FailureLabel"
// into Fast_Lock and Fast_Unlock. In the case of success, control
// will drop through the node. ICC.ZF is undefined at exit.
// In the case of failure, the node will branch directly to the
// FailureLabel
// obj: object to lock
// box: on-stack box address (displaced header location) - KILLED
// rax,: tmp -- KILLED
// scr: tmp -- KILLED
enc_class Fast_Lock( eRegP obj, eRegP box, eAXRegI tmp, eRegP scr ) %{
Register objReg = as_Register($obj$$reg);
Register boxReg = as_Register($box$$reg);
Register tmpReg = as_Register($tmp$$reg);
Register scrReg = as_Register($scr$$reg);
// Ensure the register assignents are disjoint
guarantee (objReg != boxReg, "") ;
guarantee (objReg != tmpReg, "") ;
guarantee (objReg != scrReg, "") ;
guarantee (boxReg != tmpReg, "") ;
guarantee (boxReg != scrReg, "") ;
guarantee (tmpReg == as_Register(EAX_enc), "") ;
MacroAssembler masm(&cbuf);
if (_counters != NULL) {
masm.atomic_incl(ExternalAddress((address) _counters->total_entry_count_addr()));
}
if (EmitSync & 1) {
// set box->dhw = unused_mark (3)
// Force all sync thru slow-path: slow_enter() and slow_exit()
masm.movptr (Address(boxReg, 0), int32_t(markOopDesc::unused_mark())) ;
masm.cmpptr (rsp, (int32_t)0) ;
} else
if (EmitSync & 2) {
Label DONE_LABEL ;
if (UseBiasedLocking) {
// Note: tmpReg maps to the swap_reg argument and scrReg to the tmp_reg argument.
masm.biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, _counters);
}
masm.movptr(tmpReg, Address(objReg, 0)) ; // fetch markword
masm.orptr (tmpReg, 0x1);
masm.movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(boxReg, Address(objReg, 0)); // Updates tmpReg
masm.jcc(Assembler::equal, DONE_LABEL);
// Recursive locking
masm.subptr(tmpReg, rsp);
masm.andptr(tmpReg, (int32_t) 0xFFFFF003 );
masm.movptr(Address(boxReg, 0), tmpReg);
masm.bind(DONE_LABEL) ;
} else {
// Possible cases that we'll encounter in fast_lock
// ------------------------------------------------
// * Inflated
// -- unlocked
// -- Locked
// = by self
// = by other
// * biased
// -- by Self
// -- by other
// * neutral
// * stack-locked
// -- by self
// = sp-proximity test hits
// = sp-proximity test generates false-negative
// -- by other
//
Label IsInflated, DONE_LABEL, PopDone ;
// TODO: optimize away redundant LDs of obj->mark and improve the markword triage
// order to reduce the number of conditional branches in the most common cases.
// Beware -- there's a subtle invariant that fetch of the markword
// at [FETCH], below, will never observe a biased encoding (*101b).
// If this invariant is not held we risk exclusion (safety) failure.
if (UseBiasedLocking && !UseOptoBiasInlining) {
masm.biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, _counters);
}
masm.movptr(tmpReg, Address(objReg, 0)) ; // [FETCH]
masm.testptr(tmpReg, 0x02) ; // Inflated v (Stack-locked or neutral)
masm.jccb (Assembler::notZero, IsInflated) ;
// Attempt stack-locking ...
masm.orptr (tmpReg, 0x1);
masm.movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(boxReg, Address(objReg, 0)); // Updates tmpReg
if (_counters != NULL) {
masm.cond_inc32(Assembler::equal,
ExternalAddress((address)_counters->fast_path_entry_count_addr()));
}
masm.jccb (Assembler::equal, DONE_LABEL);
// Recursive locking
masm.subptr(tmpReg, rsp);
masm.andptr(tmpReg, 0xFFFFF003 );
masm.movptr(Address(boxReg, 0), tmpReg);
if (_counters != NULL) {
masm.cond_inc32(Assembler::equal,
ExternalAddress((address)_counters->fast_path_entry_count_addr()));
}
masm.jmp (DONE_LABEL) ;
masm.bind (IsInflated) ;
// The object is inflated.
//
// TODO-FIXME: eliminate the ugly use of manifest constants:
// Use markOopDesc::monitor_value instead of "2".
// use markOop::unused_mark() instead of "3".
// The tmpReg value is an objectMonitor reference ORed with
// markOopDesc::monitor_value (2). We can either convert tmpReg to an
// objectmonitor pointer by masking off the "2" bit or we can just
// use tmpReg as an objectmonitor pointer but bias the objectmonitor
// field offsets with "-2" to compensate for and annul the low-order tag bit.
//
// I use the latter as it avoids AGI stalls.
// As such, we write "mov r, [tmpReg+OFFSETOF(Owner)-2]"
// instead of "mov r, [tmpReg+OFFSETOF(Owner)]".
//
#define OFFSET_SKEWED(f) ((ObjectMonitor::f ## _offset_in_bytes())-2)
// boxReg refers to the on-stack BasicLock in the current frame.
// We'd like to write:
// set box->_displaced_header = markOop::unused_mark(). Any non-0 value suffices.
// This is convenient but results a ST-before-CAS penalty. The following CAS suffers
// additional latency as we have another ST in the store buffer that must drain.
if (EmitSync & 8192) {
masm.movptr(Address(boxReg, 0), 3) ; // results in ST-before-CAS penalty
masm.get_thread (scrReg) ;
masm.movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2]
masm.movptr(tmpReg, NULL_WORD); // consider: xor vs mov
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(scrReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
} else
if ((EmitSync & 128) == 0) { // avoid ST-before-CAS
masm.movptr(scrReg, boxReg) ;
masm.movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2]
// Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes
if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) {
// prefetchw [eax + Offset(_owner)-2]
masm.prefetchw(Address(rax, ObjectMonitor::owner_offset_in_bytes()-2));
}
if ((EmitSync & 64) == 0) {
// Optimistic form: consider XORL tmpReg,tmpReg
masm.movptr(tmpReg, NULL_WORD) ;
} else {
// Can suffer RTS->RTO upgrades on shared or cold $ lines
// Test-And-CAS instead of CAS
masm.movptr(tmpReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; // rax, = m->_owner
masm.testptr(tmpReg, tmpReg) ; // Locked ?
masm.jccb (Assembler::notZero, DONE_LABEL) ;
}
// Appears unlocked - try to swing _owner from null to non-null.
// Ideally, I'd manifest "Self" with get_thread and then attempt
// to CAS the register containing Self into m->Owner.
// But we don't have enough registers, so instead we can either try to CAS
// rsp or the address of the box (in scr) into &m->owner. If the CAS succeeds
// we later store "Self" into m->Owner. Transiently storing a stack address
// (rsp or the address of the box) into m->owner is harmless.
// Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(scrReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
masm.movptr(Address(scrReg, 0), 3) ; // box->_displaced_header = 3
masm.jccb (Assembler::notZero, DONE_LABEL) ;
masm.get_thread (scrReg) ; // beware: clobbers ICCs
masm.movptr(Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2), scrReg) ;
masm.xorptr(boxReg, boxReg) ; // set icc.ZFlag = 1 to indicate success
// If the CAS fails we can either retry or pass control to the slow-path.
// We use the latter tactic.
// Pass the CAS result in the icc.ZFlag into DONE_LABEL
// If the CAS was successful ...
// Self has acquired the lock
// Invariant: m->_recursions should already be 0, so we don't need to explicitly set it.
// Intentional fall-through into DONE_LABEL ...
} else {
masm.movptr(Address(boxReg, 0), 3) ; // results in ST-before-CAS penalty
masm.movptr(boxReg, tmpReg) ;
// Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes
if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) {
// prefetchw [eax + Offset(_owner)-2]
masm.prefetchw(Address(rax, ObjectMonitor::owner_offset_in_bytes()-2));
}
if ((EmitSync & 64) == 0) {
// Optimistic form
masm.xorptr (tmpReg, tmpReg) ;
} else {
// Can suffer RTS->RTO upgrades on shared or cold $ lines
masm.movptr(tmpReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ; // rax, = m->_owner
masm.testptr(tmpReg, tmpReg) ; // Locked ?
masm.jccb (Assembler::notZero, DONE_LABEL) ;
}
// Appears unlocked - try to swing _owner from null to non-null.
// Use either "Self" (in scr) or rsp as thread identity in _owner.
// Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
masm.get_thread (scrReg) ;
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(scrReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
// If the CAS fails we can either retry or pass control to the slow-path.
// We use the latter tactic.
// Pass the CAS result in the icc.ZFlag into DONE_LABEL
// If the CAS was successful ...
// Self has acquired the lock
// Invariant: m->_recursions should already be 0, so we don't need to explicitly set it.
// Intentional fall-through into DONE_LABEL ...
}
// DONE_LABEL is a hot target - we'd really like to place it at the
// start of cache line by padding with NOPs.
// See the AMD and Intel software optimization manuals for the
// most efficient "long" NOP encodings.
// Unfortunately none of our alignment mechanisms suffice.
masm.bind(DONE_LABEL);
// Avoid branch-to-branch on AMD processors
// This appears to be superstition.
if (EmitSync & 32) masm.nop() ;
// At DONE_LABEL the icc ZFlag is set as follows ...
// Fast_Unlock uses the same protocol.
// ZFlag == 1 -> Success
// ZFlag == 0 -> Failure - force control through the slow-path
}
%}
// obj: object to unlock
// box: box address (displaced header location), killed. Must be EAX.
// rbx,: killed tmp; cannot be obj nor box.
//
// Some commentary on balanced locking:
//
// Fast_Lock and Fast_Unlock are emitted only for provably balanced lock sites.
// Methods that don't have provably balanced locking are forced to run in the
// interpreter - such methods won't be compiled to use fast_lock and fast_unlock.
// The interpreter provides two properties:
// I1: At return-time the interpreter automatically and quietly unlocks any
// objects acquired the current activation (frame). Recall that the
// interpreter maintains an on-stack list of locks currently held by
// a frame.
// I2: If a method attempts to unlock an object that is not held by the
// the frame the interpreter throws IMSX.
//
// Lets say A(), which has provably balanced locking, acquires O and then calls B().
// B() doesn't have provably balanced locking so it runs in the interpreter.
// Control returns to A() and A() unlocks O. By I1 and I2, above, we know that O
// is still locked by A().
//
// The only other source of unbalanced locking would be JNI. The "Java Native Interface:
// Programmer's Guide and Specification" claims that an object locked by jni_monitorenter
// should not be unlocked by "normal" java-level locking and vice-versa. The specification
// doesn't specify what will occur if a program engages in such mixed-mode locking, however.
enc_class Fast_Unlock( nabxRegP obj, eAXRegP box, eRegP tmp) %{
Register objReg = as_Register($obj$$reg);
Register boxReg = as_Register($box$$reg);
Register tmpReg = as_Register($tmp$$reg);
guarantee (objReg != boxReg, "") ;
guarantee (objReg != tmpReg, "") ;
guarantee (boxReg != tmpReg, "") ;
guarantee (boxReg == as_Register(EAX_enc), "") ;
MacroAssembler masm(&cbuf);
if (EmitSync & 4) {
// Disable - inhibit all inlining. Force control through the slow-path
masm.cmpptr (rsp, 0) ;
} else
if (EmitSync & 8) {
Label DONE_LABEL ;
if (UseBiasedLocking) {
masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL);
}
// classic stack-locking code ...
masm.movptr(tmpReg, Address(boxReg, 0)) ;
masm.testptr(tmpReg, tmpReg) ;
masm.jcc (Assembler::zero, DONE_LABEL) ;
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses EAX which is box
masm.bind(DONE_LABEL);
} else {
Label DONE_LABEL, Stacked, CheckSucc, Inflated ;
// Critically, the biased locking test must have precedence over
// and appear before the (box->dhw == 0) recursive stack-lock test.
if (UseBiasedLocking && !UseOptoBiasInlining) {
masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL);
}
masm.cmpptr(Address(boxReg, 0), 0) ; // Examine the displaced header
masm.movptr(tmpReg, Address(objReg, 0)) ; // Examine the object's markword
masm.jccb (Assembler::zero, DONE_LABEL) ; // 0 indicates recursive stack-lock
masm.testptr(tmpReg, 0x02) ; // Inflated?
masm.jccb (Assembler::zero, Stacked) ;
masm.bind (Inflated) ;
// It's inflated.
// Despite our balanced locking property we still check that m->_owner == Self
// as java routines or native JNI code called by this thread might
// have released the lock.
// Refer to the comments in synchronizer.cpp for how we might encode extra
// state in _succ so we can avoid fetching EntryList|cxq.
//
// I'd like to add more cases in fast_lock() and fast_unlock() --
// such as recursive enter and exit -- but we have to be wary of
// I$ bloat, T$ effects and BP$ effects.
//
// If there's no contention try a 1-0 exit. That is, exit without
// a costly MEMBAR or CAS. See synchronizer.cpp for details on how
// we detect and recover from the race that the 1-0 exit admits.
//
// Conceptually Fast_Unlock() must execute a STST|LDST "release" barrier
// before it STs null into _owner, releasing the lock. Updates
// to data protected by the critical section must be visible before
// we drop the lock (and thus before any other thread could acquire
// the lock and observe the fields protected by the lock).
// IA32's memory-model is SPO, so STs are ordered with respect to
// each other and there's no need for an explicit barrier (fence).
// See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
masm.get_thread (boxReg) ;
if ((EmitSync & 4096) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) {
// prefetchw [ebx + Offset(_owner)-2]
masm.prefetchw(Address(rbx, ObjectMonitor::owner_offset_in_bytes()-2));
}
// Note that we could employ various encoding schemes to reduce
// the number of loads below (currently 4) to just 2 or 3.
// Refer to the comments in synchronizer.cpp.
// In practice the chain of fetches doesn't seem to impact performance, however.
if ((EmitSync & 65536) == 0 && (EmitSync & 256)) {
// Attempt to reduce branch density - AMD's branch predictor.
masm.xorptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
masm.orptr(boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ;
masm.orptr(boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ;
masm.orptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ;
masm.jccb (Assembler::notZero, DONE_LABEL) ;
masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), NULL_WORD) ;
masm.jmpb (DONE_LABEL) ;
} else {
masm.xorptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
masm.orptr(boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ;
masm.jccb (Assembler::notZero, DONE_LABEL) ;
masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ;
masm.orptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ;
masm.jccb (Assembler::notZero, CheckSucc) ;
masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), NULL_WORD) ;
masm.jmpb (DONE_LABEL) ;
}
// The Following code fragment (EmitSync & 65536) improves the performance of
// contended applications and contended synchronization microbenchmarks.
// Unfortunately the emission of the code - even though not executed - causes regressions
// in scimark and jetstream, evidently because of $ effects. Replacing the code
// with an equal number of never-executed NOPs results in the same regression.
// We leave it off by default.
if ((EmitSync & 65536) != 0) {
Label LSuccess, LGoSlowPath ;
masm.bind (CheckSucc) ;
// Optional pre-test ... it's safe to elide this
if ((EmitSync & 16) == 0) {
masm.cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), 0) ;
masm.jccb (Assembler::zero, LGoSlowPath) ;
}
// We have a classic Dekker-style idiom:
// ST m->_owner = 0 ; MEMBAR; LD m->_succ
// There are a number of ways to implement the barrier:
// (1) lock:andl &m->_owner, 0
// is fast, but mask doesn't currently support the "ANDL M,IMM32" form.
// LOCK: ANDL [ebx+Offset(_Owner)-2], 0
// Encodes as 81 31 OFF32 IMM32 or 83 63 OFF8 IMM8
// (2) If supported, an explicit MFENCE is appealing.
// In older IA32 processors MFENCE is slower than lock:add or xchg
// particularly if the write-buffer is full as might be the case if
// if stores closely precede the fence or fence-equivalent instruction.
// In more modern implementations MFENCE appears faster, however.
// (3) In lieu of an explicit fence, use lock:addl to the top-of-stack
// The $lines underlying the top-of-stack should be in M-state.
// The locked add instruction is serializing, of course.
// (4) Use xchg, which is serializing
// mov boxReg, 0; xchgl boxReg, [tmpReg + Offset(_owner)-2] also works
// (5) ST m->_owner = 0 and then execute lock:orl &m->_succ, 0.
// The integer condition codes will tell us if succ was 0.
// Since _succ and _owner should reside in the same $line and
// we just stored into _owner, it's likely that the $line
// remains in M-state for the lock:orl.
//
// We currently use (3), although it's likely that switching to (2)
// is correct for the future.
masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), NULL_WORD) ;
if (os::is_MP()) {
if (VM_Version::supports_sse2() && 1 == FenceInstruction) {
masm.mfence();
} else {
masm.lock () ; masm.addptr(Address(rsp, 0), 0) ;
}
}
// Ratify _succ remains non-null
masm.cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), 0) ;
masm.jccb (Assembler::notZero, LSuccess) ;
masm.xorptr(boxReg, boxReg) ; // box is really EAX
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(rsp, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2));
masm.jccb (Assembler::notEqual, LSuccess) ;
// Since we're low on registers we installed rsp as a placeholding in _owner.
// Now install Self over rsp. This is safe as we're transitioning from
// non-null to non=null
masm.get_thread (boxReg) ;
masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), boxReg) ;
// Intentional fall-through into LGoSlowPath ...
masm.bind (LGoSlowPath) ;
masm.orptr(boxReg, 1) ; // set ICC.ZF=0 to indicate failure
masm.jmpb (DONE_LABEL) ;
masm.bind (LSuccess) ;
masm.xorptr(boxReg, boxReg) ; // set ICC.ZF=1 to indicate success
masm.jmpb (DONE_LABEL) ;
}
masm.bind (Stacked) ;
// It's not inflated and it's not recursively stack-locked and it's not biased.
// It must be stack-locked.
// Try to reset the header to displaced header.
// The "box" value on the stack is stable, so we can reload
// and be assured we observe the same value as above.
masm.movptr(tmpReg, Address(boxReg, 0)) ;
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses EAX which is box
// Intention fall-thru into DONE_LABEL
// DONE_LABEL is a hot target - we'd really like to place it at the
// start of cache line by padding with NOPs.
// See the AMD and Intel software optimization manuals for the
// most efficient "long" NOP encodings.
// Unfortunately none of our alignment mechanisms suffice.
if ((EmitSync & 65536) == 0) {
masm.bind (CheckSucc) ;
}
masm.bind(DONE_LABEL);
// Avoid branch to branch on AMD processors
if (EmitSync & 32768) { masm.nop() ; }
}
%}
enc_class enc_pop_rdx() %{
emit_opcode(cbuf,0x5A);
%}
@ -7545,44 +6996,6 @@ instruct cmovL_regUCF(cmpOpUCF cop, eFlagsRegUCF cr, eRegL dst, eRegL src) %{
//----------Arithmetic Instructions--------------------------------------------
//----------Addition Instructions----------------------------------------------
instruct addExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr)
%{
match(AddExactI dst src);
effect(DEF cr);
format %{ "ADD $dst, $src\t# addExact int" %}
ins_encode %{
__ addl($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addExactI_eReg_imm(eAXRegI dst, immI src, eFlagsReg cr)
%{
match(AddExactI dst src);
effect(DEF cr);
format %{ "ADD $dst, $src\t# addExact int" %}
ins_encode %{
__ addl($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr)
%{
match(AddExactI dst (LoadI src));
effect(DEF cr);
ins_cost(125);
format %{ "ADD $dst,$src\t# addExact int" %}
ins_encode %{
__ addl($dst$$Register, $src$$Address);
%}
ins_pipe( ialu_reg_mem );
%}
// Integer Addition Instructions
instruct addI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{
match(Set dst (AddI dst src));
@ -7892,43 +7305,6 @@ instruct xchgP( memory mem, pRegP newval) %{
//----------Subtraction Instructions-------------------------------------------
instruct subExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr)
%{
match(SubExactI dst src);
effect(DEF cr);
format %{ "SUB $dst, $src\t# subExact int" %}
ins_encode %{
__ subl($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subExactI_eReg_imm(eAXRegI dst, immI src, eFlagsReg cr)
%{
match(SubExactI dst src);
effect(DEF cr);
format %{ "SUB $dst, $src\t# subExact int" %}
ins_encode %{
__ subl($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr)
%{
match(SubExactI dst (LoadI src));
effect(DEF cr);
ins_cost(125);
format %{ "SUB $dst,$src\t# subExact int" %}
ins_encode %{
__ subl($dst$$Register, $src$$Address);
%}
ins_pipe( ialu_reg_mem );
%}
// Integer Subtraction Instructions
instruct subI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{
match(Set dst (SubI dst src));
@ -7997,17 +7373,6 @@ instruct negI_eReg(rRegI dst, immI0 zero, eFlagsReg cr) %{
ins_pipe( ialu_reg );
%}
instruct negExactI_eReg(eAXRegI dst, eFlagsReg cr) %{
match(NegExactI dst);
effect(DEF cr);
format %{ "NEG $dst\t# negExact int"%}
ins_encode %{
__ negl($dst$$Register);
%}
ins_pipe(ialu_reg);
%}
//----------Multiplication/Division Instructions-------------------------------
// Integer Multiplication Instructions
// Multiply Register
@ -8219,46 +7584,6 @@ instruct mulL_eReg_con(eADXRegL dst, immL_127 src, rRegI tmp, eFlagsReg cr) %{
ins_pipe( pipe_slow );
%}
instruct mulExactI_eReg(eAXRegI dst, rRegI src, eFlagsReg cr)
%{
match(MulExactI dst src);
effect(DEF cr);
ins_cost(300);
format %{ "IMUL $dst, $src\t# mulExact int" %}
ins_encode %{
__ imull($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactI_eReg_imm(eAXRegI dst, rRegI src, immI imm, eFlagsReg cr)
%{
match(MulExactI src imm);
effect(DEF cr);
ins_cost(300);
format %{ "IMUL $dst, $src, $imm\t# mulExact int" %}
ins_encode %{
__ imull($dst$$Register, $src$$Register, $imm$$constant);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactI_eReg_mem(eAXRegI dst, memory src, eFlagsReg cr)
%{
match(MulExactI dst (LoadI src));
effect(DEF cr);
ins_cost(350);
format %{ "IMUL $dst, $src\t# mulExact int" %}
ins_encode %{
__ imull($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem_alu0);
%}
// Integer DIV with Register
instruct divI_eReg(eAXRegI rax, eDXRegI rdx, eCXRegI div, eFlagsReg cr) %{
match(Set rax (DivI rax div));
@ -9124,6 +8449,91 @@ instruct and_cmpLTMask(rRegI p, rRegI q, rRegI y, eFlagsReg cr) %{
instruct cadd_cmpLTMask_mem(ncxRegI p, ncxRegI q, memory y, eCXRegI tmp, eFlagsReg cr) %{
match(Set p (AddI (AndI (CmpLTMask p q) (LoadI y)) (SubI p q)));
*/
//----------Overflow Math Instructions-----------------------------------------
instruct overflowAddI_eReg(eFlagsReg cr, eAXRegI op1, rRegI op2)
%{
match(Set cr (OverflowAddI op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "ADD $op1, $op2\t# overflow check int" %}
ins_encode %{
__ addl($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowAddI_rReg_imm(eFlagsReg cr, eAXRegI op1, immI op2)
%{
match(Set cr (OverflowAddI op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "ADD $op1, $op2\t# overflow check int" %}
ins_encode %{
__ addl($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowSubI_rReg(eFlagsReg cr, rRegI op1, rRegI op2)
%{
match(Set cr (OverflowSubI op1 op2));
format %{ "CMP $op1, $op2\t# overflow check int" %}
ins_encode %{
__ cmpl($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowSubI_rReg_imm(eFlagsReg cr, rRegI op1, immI op2)
%{
match(Set cr (OverflowSubI op1 op2));
format %{ "CMP $op1, $op2\t# overflow check int" %}
ins_encode %{
__ cmpl($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowNegI_rReg(eFlagsReg cr, immI0 zero, eAXRegI op2)
%{
match(Set cr (OverflowSubI zero op2));
effect(DEF cr, USE_KILL op2);
format %{ "NEG $op2\t# overflow check int" %}
ins_encode %{
__ negl($op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowMulI_rReg(eFlagsReg cr, eAXRegI op1, rRegI op2)
%{
match(Set cr (OverflowMulI op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "IMUL $op1, $op2\t# overflow check int" %}
ins_encode %{
__ imull($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct overflowMulI_rReg_imm(eFlagsReg cr, rRegI op1, immI op2, rRegI tmp)
%{
match(Set cr (OverflowMulI op1 op2));
effect(DEF cr, TEMP tmp, USE op1, USE op2);
format %{ "IMUL $tmp, $op1, $op2\t# overflow check int" %}
ins_encode %{
__ imull($tmp$$Register, $op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
//----------Long Instructions------------------------------------------------
// Add Long Register with Register
@ -13157,23 +12567,26 @@ instruct RethrowException()
// inlined locking and unlocking
instruct cmpFastLock( eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eRegP scr) %{
match( Set cr (FastLock object box) );
effect( TEMP tmp, TEMP scr, USE_KILL box );
instruct cmpFastLock(eFlagsReg cr, eRegP object, eBXRegP box, eAXRegI tmp, eRegP scr) %{
match(Set cr (FastLock object box));
effect(TEMP tmp, TEMP scr, USE_KILL box);
ins_cost(300);
format %{ "FASTLOCK $object,$box\t! kills $box,$tmp,$scr" %}
ins_encode( Fast_Lock(object,box,tmp,scr) );
ins_pipe( pipe_slow );
ins_encode %{
__ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $scr$$Register, _counters);
%}
ins_pipe(pipe_slow);
%}
instruct cmpFastUnlock( eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{
match( Set cr (FastUnlock object box) );
effect( TEMP tmp, USE_KILL box );
instruct cmpFastUnlock(eFlagsReg cr, eRegP object, eAXRegP box, eRegP tmp ) %{
match(Set cr (FastUnlock object box));
effect(TEMP tmp, USE_KILL box);
ins_cost(300);
format %{ "FASTUNLOCK $object,$box\t! kills $box,$tmp" %}
ins_encode( Fast_Unlock(object,box,tmp) );
ins_pipe( pipe_slow );
ins_encode %{
__ fast_unlock($object$$Register, $box$$Register, $tmp$$Register);
%}
ins_pipe(pipe_slow);
%}

View File

@ -1657,18 +1657,6 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() {
return PTR_RBP_REG_mask();
}
const RegMask Matcher::mathExactI_result_proj_mask() {
return INT_RAX_REG_mask();
}
const RegMask Matcher::mathExactL_result_proj_mask() {
return LONG_RAX_REG_mask();
}
const RegMask Matcher::mathExactI_flags_proj_mask() {
return INT_FLAGS_mask();
}
%}
//----------ENCODING BLOCK-----------------------------------------------------
@ -2599,231 +2587,6 @@ encode %{
%}
// obj: object to lock
// box: box address (header location) -- killed
// tmp: rax -- killed
// scr: rbx -- killed
//
// What follows is a direct transliteration of fast_lock() and fast_unlock()
// from i486.ad. See that file for comments.
// TODO: where possible switch from movq (r, 0) to movl(r,0) and
// use the shorter encoding. (Movl clears the high-order 32-bits).
enc_class Fast_Lock(rRegP obj, rRegP box, rax_RegI tmp, rRegP scr)
%{
Register objReg = as_Register((int)$obj$$reg);
Register boxReg = as_Register((int)$box$$reg);
Register tmpReg = as_Register($tmp$$reg);
Register scrReg = as_Register($scr$$reg);
MacroAssembler masm(&cbuf);
// Verify uniqueness of register assignments -- necessary but not sufficient
assert (objReg != boxReg && objReg != tmpReg &&
objReg != scrReg && tmpReg != scrReg, "invariant") ;
if (_counters != NULL) {
masm.atomic_incl(ExternalAddress((address) _counters->total_entry_count_addr()));
}
if (EmitSync & 1) {
// Without cast to int32_t a movptr will destroy r10 which is typically obj
masm.movptr (Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ;
masm.cmpptr(rsp, (int32_t)NULL_WORD) ;
} else
if (EmitSync & 2) {
Label DONE_LABEL;
if (UseBiasedLocking) {
// Note: tmpReg maps to the swap_reg argument and scrReg to the tmp_reg argument.
masm.biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, _counters);
}
// QQQ was movl...
masm.movptr(tmpReg, 0x1);
masm.orptr(tmpReg, Address(objReg, 0));
masm.movptr(Address(boxReg, 0), tmpReg);
if (os::is_MP()) {
masm.lock();
}
masm.cmpxchgptr(boxReg, Address(objReg, 0)); // Updates tmpReg
masm.jcc(Assembler::equal, DONE_LABEL);
// Recursive locking
masm.subptr(tmpReg, rsp);
masm.andptr(tmpReg, 7 - os::vm_page_size());
masm.movptr(Address(boxReg, 0), tmpReg);
masm.bind(DONE_LABEL);
masm.nop(); // avoid branch to branch
} else {
Label DONE_LABEL, IsInflated, Egress;
masm.movptr(tmpReg, Address(objReg, 0)) ;
masm.testl (tmpReg, 0x02) ; // inflated vs stack-locked|neutral|biased
masm.jcc (Assembler::notZero, IsInflated) ;
// it's stack-locked, biased or neutral
// TODO: optimize markword triage order to reduce the number of
// conditional branches in the most common cases.
// Beware -- there's a subtle invariant that fetch of the markword
// at [FETCH], below, will never observe a biased encoding (*101b).
// If this invariant is not held we'll suffer exclusion (safety) failure.
if (UseBiasedLocking && !UseOptoBiasInlining) {
masm.biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, _counters);
masm.movptr(tmpReg, Address(objReg, 0)) ; // [FETCH]
}
// was q will it destroy high?
masm.orl (tmpReg, 1) ;
masm.movptr(Address(boxReg, 0), tmpReg) ;
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(boxReg, Address(objReg, 0)); // Updates tmpReg
if (_counters != NULL) {
masm.cond_inc32(Assembler::equal,
ExternalAddress((address) _counters->fast_path_entry_count_addr()));
}
masm.jcc (Assembler::equal, DONE_LABEL);
// Recursive locking
masm.subptr(tmpReg, rsp);
masm.andptr(tmpReg, 7 - os::vm_page_size());
masm.movptr(Address(boxReg, 0), tmpReg);
if (_counters != NULL) {
masm.cond_inc32(Assembler::equal,
ExternalAddress((address) _counters->fast_path_entry_count_addr()));
}
masm.jmp (DONE_LABEL) ;
masm.bind (IsInflated) ;
// It's inflated
// TODO: someday avoid the ST-before-CAS penalty by
// relocating (deferring) the following ST.
// We should also think about trying a CAS without having
// fetched _owner. If the CAS is successful we may
// avoid an RTO->RTS upgrade on the $line.
// Without cast to int32_t a movptr will destroy r10 which is typically obj
masm.movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())) ;
masm.mov (boxReg, tmpReg) ;
masm.movptr (tmpReg, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
masm.testptr(tmpReg, tmpReg) ;
masm.jcc (Assembler::notZero, DONE_LABEL) ;
// It's inflated and appears unlocked
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
// Intentional fall-through into DONE_LABEL ...
masm.bind (DONE_LABEL) ;
masm.nop () ; // avoid jmp to jmp
}
%}
// obj: object to unlock
// box: box address (displaced header location), killed
// RBX: killed tmp; cannot be obj nor box
enc_class Fast_Unlock(rRegP obj, rax_RegP box, rRegP tmp)
%{
Register objReg = as_Register($obj$$reg);
Register boxReg = as_Register($box$$reg);
Register tmpReg = as_Register($tmp$$reg);
MacroAssembler masm(&cbuf);
if (EmitSync & 4) {
masm.cmpptr(rsp, 0) ;
} else
if (EmitSync & 8) {
Label DONE_LABEL;
if (UseBiasedLocking) {
masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL);
}
// Check whether the displaced header is 0
//(=> recursive unlock)
masm.movptr(tmpReg, Address(boxReg, 0));
masm.testptr(tmpReg, tmpReg);
masm.jcc(Assembler::zero, DONE_LABEL);
// If not recursive lock, reset the header to displaced header
if (os::is_MP()) {
masm.lock();
}
masm.cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses RAX which is box
masm.bind(DONE_LABEL);
masm.nop(); // avoid branch to branch
} else {
Label DONE_LABEL, Stacked, CheckSucc ;
if (UseBiasedLocking && !UseOptoBiasInlining) {
masm.biased_locking_exit(objReg, tmpReg, DONE_LABEL);
}
masm.movptr(tmpReg, Address(objReg, 0)) ;
masm.cmpptr(Address(boxReg, 0), (int32_t)NULL_WORD) ;
masm.jcc (Assembler::zero, DONE_LABEL) ;
masm.testl (tmpReg, 0x02) ;
masm.jcc (Assembler::zero, Stacked) ;
// It's inflated
masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)) ;
masm.xorptr(boxReg, r15_thread) ;
masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)) ;
masm.jcc (Assembler::notZero, DONE_LABEL) ;
masm.movptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)) ;
masm.orptr (boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)) ;
masm.jcc (Assembler::notZero, CheckSucc) ;
masm.movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD) ;
masm.jmp (DONE_LABEL) ;
if ((EmitSync & 65536) == 0) {
Label LSuccess, LGoSlowPath ;
masm.bind (CheckSucc) ;
masm.cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD) ;
masm.jcc (Assembler::zero, LGoSlowPath) ;
// I'd much rather use lock:andl m->_owner, 0 as it's faster than the
// the explicit ST;MEMBAR combination, but masm doesn't currently support
// "ANDQ M,IMM". Don't use MFENCE here. lock:add to TOS, xchg, etc
// are all faster when the write buffer is populated.
masm.movptr (Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD) ;
if (os::is_MP()) {
masm.lock () ; masm.addl (Address(rsp, 0), 0) ;
}
masm.cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD) ;
masm.jcc (Assembler::notZero, LSuccess) ;
masm.movptr (boxReg, (int32_t)NULL_WORD) ; // box is really EAX
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(r15_thread, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2));
masm.jcc (Assembler::notEqual, LSuccess) ;
// Intentional fall-through into slow-path
masm.bind (LGoSlowPath) ;
masm.orl (boxReg, 1) ; // set ICC.ZF=0 to indicate failure
masm.jmp (DONE_LABEL) ;
masm.bind (LSuccess) ;
masm.testl (boxReg, 0) ; // set ICC.ZF=1 to indicate success
masm.jmp (DONE_LABEL) ;
}
masm.bind (Stacked) ;
masm.movptr(tmpReg, Address (boxReg, 0)) ; // re-fetch
if (os::is_MP()) { masm.lock(); }
masm.cmpxchgptr(tmpReg, Address(objReg, 0)); // Uses RAX which is box
if (EmitSync & 65536) {
masm.bind (CheckSucc) ;
}
masm.bind(DONE_LABEL);
if (EmitSync & 32768) {
masm.nop(); // avoid branch to branch
}
}
%}
enc_class enc_rethrow()
%{
cbuf.set_insts_mark();
@ -6963,82 +6726,6 @@ instruct cmovD_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, regD dst, regD src) %{
//----------Arithmetic Instructions--------------------------------------------
//----------Addition Instructions----------------------------------------------
instruct addExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr)
%{
match(AddExactI dst src);
effect(DEF cr);
format %{ "addl $dst, $src\t# addExact int" %}
ins_encode %{
__ addl($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr)
%{
match(AddExactI dst src);
effect(DEF cr);
format %{ "addl $dst, $src\t# addExact int" %}
ins_encode %{
__ addl($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
%{
match(AddExactI dst (LoadI src));
effect(DEF cr);
ins_cost(125); // XXX
format %{ "addl $dst, $src\t# addExact int" %}
ins_encode %{
__ addl($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
instruct addExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr)
%{
match(AddExactL dst src);
effect(DEF cr);
format %{ "addq $dst, $src\t# addExact long" %}
ins_encode %{
__ addq($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addExactL_rReg_imm(rax_RegL dst, immL32 src, rFlagsReg cr)
%{
match(AddExactL dst src);
effect(DEF cr);
format %{ "addq $dst, $src\t# addExact long" %}
ins_encode %{
__ addq($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct addExactL_rReg_mem(rax_RegL dst, memory src, rFlagsReg cr)
%{
match(AddExactL dst (LoadL src));
effect(DEF cr);
ins_cost(125); // XXX
format %{ "addq $dst, $src\t# addExact long" %}
ins_encode %{
__ addq($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr)
%{
match(Set dst (AddI dst src));
@ -7651,80 +7338,6 @@ instruct subI_mem_imm(memory dst, immI src, rFlagsReg cr)
ins_pipe(ialu_mem_imm);
%}
instruct subExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr)
%{
match(SubExactI dst src);
effect(DEF cr);
format %{ "subl $dst, $src\t# subExact int" %}
ins_encode %{
__ subl($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subExactI_rReg_imm(rax_RegI dst, immI src, rFlagsReg cr)
%{
match(SubExactI dst src);
effect(DEF cr);
format %{ "subl $dst, $src\t# subExact int" %}
ins_encode %{
__ subl($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
%{
match(SubExactI dst (LoadI src));
effect(DEF cr);
ins_cost(125);
format %{ "subl $dst, $src\t# subExact int" %}
ins_encode %{
__ subl($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
instruct subExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr)
%{
match(SubExactL dst src);
effect(DEF cr);
format %{ "subq $dst, $src\t# subExact long" %}
ins_encode %{
__ subq($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subExactL_rReg_imm(rax_RegL dst, immL32 src, rFlagsReg cr)
%{
match(SubExactL dst (LoadL src));
effect(DEF cr);
format %{ "subq $dst, $src\t# subExact long" %}
ins_encode %{
__ subq($dst$$Register, $src$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct subExactL_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
%{
match(SubExactI dst src);
effect(DEF cr);
ins_cost(125);
format %{ "subq $dst, $src\t# subExact long" %}
ins_encode %{
__ subq($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem);
%}
instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr)
%{
match(Set dst (SubL dst src));
@ -7841,31 +7454,6 @@ instruct negL_mem(memory dst, immL0 zero, rFlagsReg cr)
ins_pipe(ialu_reg);
%}
instruct negExactI_rReg(rax_RegI dst, rFlagsReg cr)
%{
match(NegExactI dst);
effect(KILL cr);
format %{ "negl $dst\t# negExact int" %}
ins_encode %{
__ negl($dst$$Register);
%}
ins_pipe(ialu_reg);
%}
instruct negExactL_rReg(rax_RegL dst, rFlagsReg cr)
%{
match(NegExactL dst);
effect(KILL cr);
format %{ "negq $dst\t# negExact long" %}
ins_encode %{
__ negq($dst$$Register);
%}
ins_pipe(ialu_reg);
%}
//----------Multiplication/Division Instructions-------------------------------
// Integer Multiplication Instructions
// Multiply Register
@ -7982,86 +7570,6 @@ instruct mulHiL_rReg(rdx_RegL dst, no_rax_RegL src, rax_RegL rax, rFlagsReg cr)
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactI_rReg(rax_RegI dst, rRegI src, rFlagsReg cr)
%{
match(MulExactI dst src);
effect(DEF cr);
ins_cost(300);
format %{ "imull $dst, $src\t# mulExact int" %}
ins_encode %{
__ imull($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactI_rReg_imm(rax_RegI dst, rRegI src, immI imm, rFlagsReg cr)
%{
match(MulExactI src imm);
effect(DEF cr);
ins_cost(300);
format %{ "imull $dst, $src, $imm\t# mulExact int" %}
ins_encode %{
__ imull($dst$$Register, $src$$Register, $imm$$constant);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactI_rReg_mem(rax_RegI dst, memory src, rFlagsReg cr)
%{
match(MulExactI dst (LoadI src));
effect(DEF cr);
ins_cost(350);
format %{ "imull $dst, $src\t# mulExact int" %}
ins_encode %{
__ imull($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem_alu0);
%}
instruct mulExactL_rReg(rax_RegL dst, rRegL src, rFlagsReg cr)
%{
match(MulExactL dst src);
effect(DEF cr);
ins_cost(300);
format %{ "imulq $dst, $src\t# mulExact long" %}
ins_encode %{
__ imulq($dst$$Register, $src$$Register);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactL_rReg_imm(rax_RegL dst, rRegL src, immL32 imm, rFlagsReg cr)
%{
match(MulExactL src imm);
effect(DEF cr);
ins_cost(300);
format %{ "imulq $dst, $src, $imm\t# mulExact long" %}
ins_encode %{
__ imulq($dst$$Register, $src$$Register, $imm$$constant);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct mulExactL_rReg_mem(rax_RegL dst, memory src, rFlagsReg cr)
%{
match(MulExactL dst (LoadL src));
effect(DEF cr);
ins_cost(350);
format %{ "imulq $dst, $src\t# mulExact long" %}
ins_encode %{
__ imulq($dst$$Register, $src$$Address);
%}
ins_pipe(ialu_reg_mem_alu0);
%}
instruct divI_rReg(rax_RegI rax, rdx_RegI rdx, no_rax_rdx_RegI div,
rFlagsReg cr)
%{
@ -10670,6 +10178,174 @@ instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len,
ins_pipe( pipe_slow );
%}
//----------Overflow Math Instructions-----------------------------------------
instruct overflowAddI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2)
%{
match(Set cr (OverflowAddI op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "addl $op1, $op2\t# overflow check int" %}
ins_encode %{
__ addl($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowAddI_rReg_imm(rFlagsReg cr, rax_RegI op1, immI op2)
%{
match(Set cr (OverflowAddI op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "addl $op1, $op2\t# overflow check int" %}
ins_encode %{
__ addl($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowAddL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2)
%{
match(Set cr (OverflowAddL op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "addq $op1, $op2\t# overflow check long" %}
ins_encode %{
__ addq($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowAddL_rReg_imm(rFlagsReg cr, rax_RegL op1, immL32 op2)
%{
match(Set cr (OverflowAddL op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "addq $op1, $op2\t# overflow check long" %}
ins_encode %{
__ addq($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowSubI_rReg(rFlagsReg cr, rRegI op1, rRegI op2)
%{
match(Set cr (OverflowSubI op1 op2));
format %{ "cmpl $op1, $op2\t# overflow check int" %}
ins_encode %{
__ cmpl($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowSubI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2)
%{
match(Set cr (OverflowSubI op1 op2));
format %{ "cmpl $op1, $op2\t# overflow check int" %}
ins_encode %{
__ cmpl($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowSubL_rReg(rFlagsReg cr, rRegL op1, rRegL op2)
%{
match(Set cr (OverflowSubL op1 op2));
format %{ "cmpq $op1, $op2\t# overflow check long" %}
ins_encode %{
__ cmpq($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowSubL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2)
%{
match(Set cr (OverflowSubL op1 op2));
format %{ "cmpq $op1, $op2\t# overflow check long" %}
ins_encode %{
__ cmpq($op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowNegI_rReg(rFlagsReg cr, immI0 zero, rax_RegI op2)
%{
match(Set cr (OverflowSubI zero op2));
effect(DEF cr, USE_KILL op2);
format %{ "negl $op2\t# overflow check int" %}
ins_encode %{
__ negl($op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowNegL_rReg(rFlagsReg cr, immL0 zero, rax_RegL op2)
%{
match(Set cr (OverflowSubL zero op2));
effect(DEF cr, USE_KILL op2);
format %{ "negq $op2\t# overflow check long" %}
ins_encode %{
__ negq($op2$$Register);
%}
ins_pipe(ialu_reg_reg);
%}
instruct overflowMulI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2)
%{
match(Set cr (OverflowMulI op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "imull $op1, $op2\t# overflow check int" %}
ins_encode %{
__ imull($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct overflowMulI_rReg_imm(rFlagsReg cr, rRegI op1, immI op2, rRegI tmp)
%{
match(Set cr (OverflowMulI op1 op2));
effect(DEF cr, TEMP tmp, USE op1, USE op2);
format %{ "imull $tmp, $op1, $op2\t# overflow check int" %}
ins_encode %{
__ imull($tmp$$Register, $op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct overflowMulL_rReg(rFlagsReg cr, rax_RegL op1, rRegL op2)
%{
match(Set cr (OverflowMulL op1 op2));
effect(DEF cr, USE_KILL op1, USE op2);
format %{ "imulq $op1, $op2\t# overflow check long" %}
ins_encode %{
__ imulq($op1$$Register, $op2$$Register);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
instruct overflowMulL_rReg_imm(rFlagsReg cr, rRegL op1, immL32 op2, rRegL tmp)
%{
match(Set cr (OverflowMulL op1 op2));
effect(DEF cr, TEMP tmp, USE op1, USE op2);
format %{ "imulq $tmp, $op1, $op2\t# overflow check long" %}
ins_encode %{
__ imulq($tmp$$Register, $op1$$Register, $op2$$constant);
%}
ins_pipe(ialu_reg_reg_alu0);
%}
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
@ -11453,27 +11129,25 @@ instruct jmpConUCF2_short(cmpOpUCF2 cop, rFlagsRegUCF cmp, label labl) %{
// ============================================================================
// inlined locking and unlocking
instruct cmpFastLock(rFlagsReg cr,
rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr)
%{
instruct cmpFastLock(rFlagsReg cr, rRegP object, rbx_RegP box, rax_RegI tmp, rRegP scr) %{
match(Set cr (FastLock object box));
effect(TEMP tmp, TEMP scr, USE_KILL box);
ins_cost(300);
format %{ "fastlock $object,$box\t! kills $box,$tmp,$scr" %}
ins_encode(Fast_Lock(object, box, tmp, scr));
ins_encode %{
__ fast_lock($object$$Register, $box$$Register, $tmp$$Register, $scr$$Register, _counters);
%}
ins_pipe(pipe_slow);
%}
instruct cmpFastUnlock(rFlagsReg cr,
rRegP object, rax_RegP box, rRegP tmp)
%{
instruct cmpFastUnlock(rFlagsReg cr, rRegP object, rax_RegP box, rRegP tmp) %{
match(Set cr (FastUnlock object box));
effect(TEMP tmp, USE_KILL box);
ins_cost(300);
format %{ "fastunlock $object,$box\t! kills $box,$tmp" %}
ins_encode(Fast_Unlock(object, box, tmp));
ins_encode %{
__ fast_unlock($object$$Register, $box$$Register, $tmp$$Register);
%}
ins_pipe(pipe_slow);
%}

View File

@ -1167,15 +1167,12 @@ void ArchDesc::buildMustCloneMap(FILE *fp_hpp, FILE *fp_cpp) {
|| strcmp(idealName,"CmpF") == 0
|| strcmp(idealName,"FastLock") == 0
|| strcmp(idealName,"FastUnlock") == 0
|| strcmp(idealName,"AddExactI") == 0
|| strcmp(idealName,"AddExactL") == 0
|| strcmp(idealName,"SubExactI") == 0
|| strcmp(idealName,"SubExactL") == 0
|| strcmp(idealName,"MulExactI") == 0
|| strcmp(idealName,"MulExactL") == 0
|| strcmp(idealName,"NegExactI") == 0
|| strcmp(idealName,"NegExactL") == 0
|| strcmp(idealName,"FlagsProj") == 0
|| strcmp(idealName,"OverflowAddI") == 0
|| strcmp(idealName,"OverflowAddL") == 0
|| strcmp(idealName,"OverflowSubI") == 0
|| strcmp(idealName,"OverflowSubL") == 0
|| strcmp(idealName,"OverflowMulI") == 0
|| strcmp(idealName,"OverflowMulL") == 0
|| strcmp(idealName,"Bool") == 0
|| strcmp(idealName,"Binary") == 0 ) {
// Removed ConI from the must_clone list. CPUs that cannot use

View File

@ -103,6 +103,7 @@ friend class ciMethodHandle; \
friend class ciMethodType; \
friend class ciReceiverTypeData; \
friend class ciTypeEntries; \
friend class ciSpeculativeTrapData; \
friend class ciSymbol; \
friend class ciArray; \
friend class ciObjArray; \

View File

@ -78,6 +78,35 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
_parameters = NULL;
}
void ciMethodData::load_extra_data() {
MethodData* mdo = get_MethodData();
// speculative trap entries also hold a pointer to a Method so need to be translated
DataLayout* dp_src = mdo->extra_data_base();
DataLayout* end_src = mdo->extra_data_limit();
DataLayout* dp_dst = extra_data_base();
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
assert(dp_src < end_src, "moved past end of extra data");
assert(dp_src->tag() == dp_dst->tag(), err_msg("should be same tags %d != %d", dp_src->tag(), dp_dst->tag()));
switch(dp_src->tag()) {
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
data_dst->translate_from(data_src);
break;
}
case DataLayout::bit_data_tag:
break;
case DataLayout::no_tag:
case DataLayout::arg_info_data_tag:
// An empty slot or ArgInfoData entry marks the end of the trap data
return;
default:
fatal(err_msg("bad tag = %d", dp_src->tag()));
}
}
}
void ciMethodData::load_data() {
MethodData* mdo = get_MethodData();
if (mdo == NULL) {
@ -116,6 +145,8 @@ void ciMethodData::load_data() {
parameters->translate_from(mdo->parameters_type_data());
}
load_extra_data();
// Note: Extra data are all BitData, and do not need translation.
_current_mileage = MethodData::mileage_of(mdo->method());
_invocation_counter = mdo->invocation_count();
@ -156,6 +187,12 @@ void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) {
set_type(translate_klass(k));
}
void ciSpeculativeTrapData::translate_from(const ProfileData* data) {
Method* m = data->as_SpeculativeTrapData()->method();
ciMethod* ci_m = CURRENT_ENV->get_method(m);
set_method(ci_m);
}
// Get the data at an arbitrary (sort of) data index.
ciProfileData* ciMethodData::data_at(int data_index) {
if (out_of_bounds(data_index)) {
@ -203,33 +240,65 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) {
return next;
}
// Translate a bci to its corresponding data, or NULL.
ciProfileData* ciMethodData::bci_to_data(int bci) {
ciProfileData* data = data_before(bci);
for ( ; is_valid(data); data = next_data(data)) {
if (data->bci() == bci) {
set_hint_di(dp_to_di(data->dp()));
return data;
} else if (data->bci() > bci) {
break;
}
}
ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) {
// bci_to_extra_data(bci) ...
DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size());
for (; dp < end; dp = MethodData::next_extra(dp)) {
if (dp->tag() == DataLayout::no_tag) {
two_free_slots = false;
for (;dp < end; dp = MethodData::next_extra(dp)) {
switch(dp->tag()) {
case DataLayout::no_tag:
_saw_free_extra_data = true; // observed an empty slot (common case)
two_free_slots = (MethodData::next_extra(dp)->tag() == DataLayout::no_tag);
return NULL;
case DataLayout::arg_info_data_tag:
return NULL; // ArgInfoData is at the end of extra data section.
case DataLayout::bit_data_tag:
if (m == NULL && dp->bci() == bci) {
return new ciBitData(dp);
}
break;
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data = new ciSpeculativeTrapData(dp);
// data->method() might be null if the MDO is snapshotted
// concurrently with a trap
if (m != NULL && data->method() == m && dp->bci() == bci) {
return data;
}
break;
}
if (dp->tag() == DataLayout::arg_info_data_tag) {
break; // ArgInfoData is at the end of extra data section.
default:
fatal(err_msg("bad tag = %d", dp->tag()));
}
if (dp->bci() == bci) {
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
return new ciBitData(dp);
}
return NULL;
}
// Translate a bci to its corresponding data, or NULL.
ciProfileData* ciMethodData::bci_to_data(int bci, ciMethod* m) {
// If m is not NULL we look for a SpeculativeTrapData entry
if (m == NULL) {
ciProfileData* data = data_before(bci);
for ( ; is_valid(data); data = next_data(data)) {
if (data->bci() == bci) {
set_hint_di(dp_to_di(data->dp()));
return data;
} else if (data->bci() > bci) {
break;
}
}
}
bool two_free_slots = false;
ciProfileData* result = bci_to_extra_data(bci, m, two_free_slots);
if (result != NULL) {
return result;
}
if (m != NULL && !two_free_slots) {
// We were looking for a SpeculativeTrapData entry we didn't
// find. Room is not available for more SpeculativeTrapData
// entries, look in the non SpeculativeTrapData entries.
return bci_to_data(bci, NULL);
}
return NULL;
}
@ -525,18 +594,25 @@ void ciMethodData::print_data_on(outputStream* st) {
st->print_cr("--- Extra data:");
DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size());
for (; dp < end; dp = MethodData::next_extra(dp)) {
if (dp->tag() == DataLayout::no_tag) continue;
if (dp->tag() == DataLayout::bit_data_tag) {
for (;; dp = MethodData::next_extra(dp)) {
assert(dp < end, "moved past end of extra data");
switch (dp->tag()) {
case DataLayout::no_tag:
continue;
case DataLayout::bit_data_tag:
data = new BitData(dp);
} else {
assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo");
break;
case DataLayout::arg_info_data_tag:
data = new ciArgInfoData(dp);
dp = end; // ArgInfoData is at the end of extra data section.
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
st->print("%d", dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
if (dp >= end) return;
}
}
@ -569,8 +645,8 @@ void ciReturnTypeEntry::print_data_on(outputStream* st) const {
st->cr();
}
void ciCallTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ciCallTypeData");
void ciCallTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciCallTypeData", extra);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
@ -599,18 +675,18 @@ void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const {
}
}
void ciReceiverTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ciReceiverTypeData");
void ciReceiverTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciReceiverTypeData", extra);
print_receiver_data_on(st);
}
void ciVirtualCallData::print_data_on(outputStream* st) const {
print_shared(st, "ciVirtualCallData");
void ciVirtualCallData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciVirtualCallData", extra);
rtd_super()->print_receiver_data_on(st);
}
void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ciVirtualCallTypeData");
void ciVirtualCallTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciVirtualCallTypeData", extra);
rtd_super()->print_receiver_data_on(st);
if (has_arguments()) {
tab(st, true);
@ -624,8 +700,15 @@ void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
}
}
void ciParametersTypeData::print_data_on(outputStream* st) const {
st->print_cr("Parametertypes");
void ciParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
st->print_cr("ciParametersTypeData");
parameters()->print_data_on(st);
}
void ciSpeculativeTrapData::print_data_on(outputStream* st, const char* extra) const {
st->print_cr("ciSpeculativeTrapData");
tab(st);
method()->print_short_name(st);
st->cr();
}
#endif

View File

@ -31,6 +31,7 @@
#include "ci/ciUtilities.hpp"
#include "oops/methodData.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/deoptimization.hpp"
class ciBitData;
class ciCounterData;
@ -44,6 +45,7 @@ class ciArgInfoData;
class ciCallTypeData;
class ciVirtualCallTypeData;
class ciParametersTypeData;
class ciSpeculativeTrapData;;
typedef ProfileData ciProfileData;
@ -173,7 +175,7 @@ public:
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
@ -200,7 +202,7 @@ public:
}
void translate_receiver_data_from(const ProfileData* data);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra) const;
void print_receiver_data_on(outputStream* st) const;
#endif
};
@ -225,7 +227,7 @@ public:
rtd_super()->translate_receiver_data_from(data);
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
@ -287,7 +289,7 @@ public:
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
@ -336,7 +338,26 @@ public:
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciSpeculativeTrapData : public SpeculativeTrapData {
public:
ciSpeculativeTrapData(DataLayout* layout) : SpeculativeTrapData(layout) {}
virtual void translate_from(const ProfileData* data);
ciMethod* method() const {
return (ciMethod*)intptr_at(method_offset);
}
void set_method(ciMethod* m) {
set_intptr_at(method_offset, (intptr_t)m);
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
@ -436,6 +457,16 @@ private:
ciArgInfoData *arg_info() const;
address data_base() const {
return (address) _data;
}
DataLayout* limit_data_position() const {
return (DataLayout*)((address)data_base() + _data_size);
}
void load_extra_data();
ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
public:
bool is_method_data() const { return true; }
@ -475,9 +506,11 @@ public:
ciProfileData* next_data(ciProfileData* current);
bool is_valid(ciProfileData* current) { return current != NULL; }
// Get the data at an arbitrary bci, or NULL if there is none.
ciProfileData* bci_to_data(int bci);
ciProfileData* bci_to_extra_data(int bci, bool create_if_missing);
DataLayout* extra_data_base() const { return limit_data_position(); }
// Get the data at an arbitrary bci, or NULL if there is none. If m
// is not NULL look for a SpeculativeTrapData if any first.
ciProfileData* bci_to_data(int bci, ciMethod* m = NULL);
uint overflow_trap_count() const {
return _orig.overflow_trap_count();
@ -496,12 +529,13 @@ public:
// Helpful query functions that decode trap_state.
int has_trap_at(ciProfileData* data, int reason);
int has_trap_at(int bci, int reason) {
return has_trap_at(bci_to_data(bci), reason);
int has_trap_at(int bci, ciMethod* m, int reason) {
assert((m != NULL) == Deoptimization::reason_is_speculate(reason), "inconsistent method/reason");
return has_trap_at(bci_to_data(bci, m), reason);
}
int trap_recompiled_at(ciProfileData* data);
int trap_recompiled_at(int bci) {
return trap_recompiled_at(bci_to_data(bci));
int trap_recompiled_at(int bci, ciMethod* m) {
return trap_recompiled_at(bci_to_data(bci, m));
}
void clear_escape_info();

View File

@ -595,11 +595,8 @@ void CodeCache::clear_inline_caches() {
}
}
#ifndef PRODUCT
// Keeps track of time spent for checking dependencies
static elapsedTimer dependentCheckTime;
#endif
NOT_PRODUCT(static elapsedTimer dependentCheckTime;)
int CodeCache::mark_for_deoptimization(DepChange& changes) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);

View File

@ -725,56 +725,19 @@ Klass* Dependencies::DepStream::context_type() {
}
// ----------------- DependencySignature --------------------------------------
bool DependencySignature::equals(const DependencySignature& sig) const {
if (type() != sig.type()) {
bool DependencySignature::equals(DependencySignature* sig) const {
if ((type() != sig->type()) || (args_count() != sig->args_count())) {
return false;
}
if (args_count() != sig.args_count()) {
return false;
}
for (int i = 0; i < sig.args_count(); i++) {
if (arg(i) != sig.arg(i)) {
for (int i = 0; i < sig->args_count(); i++) {
if (arg(i) != sig->arg(i)) {
return false;
}
}
return true;
}
// ----------------- DependencySignatureBuffer --------------------------------------
DependencySignatureBuffer::DependencySignatureBuffer() {
_signatures = NEW_RESOURCE_ARRAY(GrowableArray<DependencySignature*>*, Dependencies::TYPE_LIMIT);
memset(_signatures, 0, sizeof(DependencySignature*) * Dependencies::TYPE_LIMIT);
}
/* Check if arguments are identical. Two dependency signatures are considered
* identical, if the type as well as all argument identifiers are identical.
* If the dependency has not already been checked, the dependency signature is
* added to the checked dependencies of the same type. The function returns
* false, which causes the dependency to be checked in the caller.
*/
bool DependencySignatureBuffer::add_if_missing(const DependencySignature& sig) {
const int index = sig.type();
GrowableArray<DependencySignature*>* buffer = _signatures[index];
if (buffer == NULL) {
buffer = new GrowableArray<DependencySignature*>();
_signatures[index] = buffer;
}
// Check if we have already checked the dependency
for (int i = 0; i < buffer->length(); i++) {
DependencySignature* checked_signature = buffer->at(i);
if (checked_signature->equals(sig)) {
return true;
}
}
buffer->append((DependencySignature*)&sig);
return false;
}
/// Checking dependencies:
// This hierarchy walker inspects subtypes of a given type,

View File

@ -32,6 +32,7 @@
#include "code/compressedStream.hpp"
#include "code/nmethod.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.hpp"
//** Dependencies represent assertions (approximate invariants) within
// the runtime system, e.g. class hierarchy changes. An example is an
@ -526,13 +527,12 @@ class Dependencies: public ResourceObj {
};
class DependencySignature : public ResourceObj {
class DependencySignature : public GenericHashtableEntry<DependencySignature, ResourceObj> {
private:
int _args_count;
uintptr_t _argument_hash[Dependencies::max_arg_count];
Dependencies::DepType _type;
public:
DependencySignature(Dependencies::DepStream& dep) {
_args_count = dep.argument_count();
@ -542,21 +542,14 @@ class DependencySignature : public ResourceObj {
}
}
bool equals(const DependencySignature& sig) const;
bool equals(DependencySignature* sig) const;
uintptr_t key() const { return _argument_hash[0] >> 2; }
int args_count() const { return _args_count; }
uintptr_t arg(int idx) const { return _argument_hash[idx]; }
Dependencies::DepType type() const { return _type; }
};
class DependencySignatureBuffer : public StackObj {
private:
GrowableArray<DependencySignature*>** _signatures;
public:
DependencySignatureBuffer();
bool add_if_missing(const DependencySignature& sig);
};
// Every particular DepChange is a sub-class of this class.
class DepChange : public StackObj {

View File

@ -2135,25 +2135,21 @@ void nmethod::check_all_dependencies(DepChange& changes) {
// Turn off dependency tracing while actually testing dependencies.
NOT_PRODUCT( FlagSetting fs(TraceDependencies, false) );
// 'dep_signature_buffers' caches already checked dependencies.
DependencySignatureBuffer dep_signature_buffers;
GenericHashtable<DependencySignature, ResourceObj>* table = new GenericHashtable<DependencySignature, ResourceObj>(11027);
// Iterate over live nmethods and check dependencies of all nmethods that are not
// marked for deoptimization. A particular dependency is only checked once.
for(nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); nm != NULL; nm = CodeCache::alive_nmethod(CodeCache::next(nm))) {
if (!nm->is_marked_for_deoptimization()) {
for (Dependencies::DepStream deps(nm); deps.next(); ) {
// Construct abstraction of a dependency.
const DependencySignature* current_sig = new DependencySignature(deps);
// Determine if 'deps' is already checked. If it is not checked,
// 'add_if_missing()' adds the dependency signature and returns
// false.
if (!dep_signature_buffers.add_if_missing(*current_sig)) {
DependencySignature* current_sig = new DependencySignature(deps);
// Determine if 'deps' is already checked. table->add() returns
// 'true' if the dependency was added (i.e., was not in the hashtable).
if (table->add(current_sig)) {
if (deps.check_dependency() != NULL) {
// Dependency checking failed. Print out information about the failed
// dependency and finally fail with an assert. We can fail here, since
// dependency checking is never done in a product build.
ResourceMark rm;
changes.print();
nm->print();
nm->print_dependencies();

View File

@ -596,7 +596,7 @@ void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) {
if (data != NULL) {
st->print(" %d", mdo->dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
data->print_data_on(st, mdo);
}
}
}

View File

@ -2199,15 +2199,7 @@ void InstanceKlass::clean_method_data(BoolObjectClosure* is_alive) {
for (int m = 0; m < methods()->length(); m++) {
MethodData* mdo = methods()->at(m)->method_data();
if (mdo != NULL) {
for (ProfileData* data = mdo->first_data();
mdo->is_valid(data);
data = mdo->next_data(data)) {
data->clean_weak_klass_links(is_alive);
}
ParametersTypeData* parameters = mdo->parameters_type_data();
if (parameters != NULL) {
parameters->clean_weak_klass_links(is_alive);
}
mdo->clean_method_data(is_alive);
}
}
}
@ -2726,7 +2718,7 @@ void InstanceKlass::remove_osr_nmethod(nmethod* n) {
Method* m = n->method();
// Search for match
while(cur != NULL && cur != n) {
if (TieredCompilation) {
if (TieredCompilation && m == cur->method()) {
// Find max level before n
max_level = MAX2(max_level, cur->comp_level());
}
@ -2748,7 +2740,9 @@ void InstanceKlass::remove_osr_nmethod(nmethod* n) {
cur = next;
while (cur != NULL) {
// Find max level after n
max_level = MAX2(max_level, cur->comp_level());
if (m == cur->method()) {
max_level = MAX2(max_level, cur->comp_level());
}
cur = cur->osr_link();
}
m->set_highest_osr_comp_level(max_level);

View File

@ -306,7 +306,7 @@ class InstanceKlass: public Klass {
// three cases:
// NULL: no implementor.
// A Klass* that's not itself: one implementor.
// Itsef: more than one implementors.
// Itself: more than one implementors.
// embedded host klass follows here
// The embedded host klass only exists in an anonymous class for
// dynamic language support (JSR 292 enabled). The host class grants

View File

@ -80,8 +80,42 @@ ProfileData::ProfileData() {
_data = NULL;
}
char* ProfileData::print_data_on_helper(const MethodData* md) const {
DataLayout* dp = md->extra_data_base();
DataLayout* end = md->extra_data_limit();
stringStream ss;
for (;; dp = MethodData::next_extra(dp)) {
assert(dp < end, "moved past end of extra data");
switch(dp->tag()) {
case DataLayout::speculative_trap_data_tag:
if (dp->bci() == bci()) {
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
int trap = data->trap_state();
char buf[100];
ss.print("trap/");
data->method()->print_short_name(&ss);
ss.print("(%s) ", Deoptimization::format_trap_state(buf, sizeof(buf), trap));
}
break;
case DataLayout::bit_data_tag:
break;
case DataLayout::no_tag:
case DataLayout::arg_info_data_tag:
return ss.as_string();
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
}
return NULL;
}
void ProfileData::print_data_on(outputStream* st, const MethodData* md) const {
print_data_on(st, print_data_on_helper(md));
}
#ifndef PRODUCT
void ProfileData::print_shared(outputStream* st, const char* name) const {
void ProfileData::print_shared(outputStream* st, const char* name, const char* extra) const {
st->print("bci: %d", bci());
st->fill_to(tab_width_one);
st->print("%s", name);
@ -91,9 +125,13 @@ void ProfileData::print_shared(outputStream* st, const char* name) const {
char buf[100];
st->print("trap(%s) ", Deoptimization::format_trap_state(buf, sizeof(buf), trap));
}
if (extra != NULL) {
st->print(extra);
}
int flags = data()->flags();
if (flags != 0)
if (flags != 0) {
st->print("flags(%d) ", flags);
}
}
void ProfileData::tab(outputStream* st, bool first) const {
@ -109,8 +147,8 @@ void ProfileData::tab(outputStream* st, bool first) const {
#ifndef PRODUCT
void BitData::print_data_on(outputStream* st) const {
print_shared(st, "BitData");
void BitData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "BitData", extra);
}
#endif // !PRODUCT
@ -120,8 +158,8 @@ void BitData::print_data_on(outputStream* st) const {
// A CounterData corresponds to a simple counter.
#ifndef PRODUCT
void CounterData::print_data_on(outputStream* st) const {
print_shared(st, "CounterData");
void CounterData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "CounterData", extra);
st->print_cr("count(%u)", count());
}
#endif // !PRODUCT
@ -150,8 +188,8 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
}
#ifndef PRODUCT
void JumpData::print_data_on(outputStream* st) const {
print_shared(st, "JumpData");
void JumpData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "JumpData", extra);
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
}
#endif // !PRODUCT
@ -332,8 +370,8 @@ void ReturnTypeEntry::print_data_on(outputStream* st) const {
st->cr();
}
void CallTypeData::print_data_on(outputStream* st) const {
CounterData::print_data_on(st);
void CallTypeData::print_data_on(outputStream* st, const char* extra) const {
CounterData::print_data_on(st, extra);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
@ -346,8 +384,8 @@ void CallTypeData::print_data_on(outputStream* st) const {
}
}
void VirtualCallTypeData::print_data_on(outputStream* st) const {
VirtualCallData::print_data_on(st);
void VirtualCallTypeData::print_data_on(outputStream* st, const char* extra) const {
VirtualCallData::print_data_on(st, extra);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
@ -400,12 +438,12 @@ void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
}
}
}
void ReceiverTypeData::print_data_on(outputStream* st) const {
print_shared(st, "ReceiverTypeData");
void ReceiverTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ReceiverTypeData", extra);
print_receiver_data_on(st);
}
void VirtualCallData::print_data_on(outputStream* st) const {
print_shared(st, "VirtualCallData");
void VirtualCallData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "VirtualCallData", extra);
print_receiver_data_on(st);
}
#endif // !PRODUCT
@ -461,8 +499,8 @@ DataLayout* RetData::advance(MethodData *md, int bci) {
#endif // CC_INTERP
#ifndef PRODUCT
void RetData::print_data_on(outputStream* st) const {
print_shared(st, "RetData");
void RetData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "RetData", extra);
uint row;
int entries = 0;
for (row = 0; row < row_limit(); row++) {
@ -496,8 +534,8 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
}
#ifndef PRODUCT
void BranchData::print_data_on(outputStream* st) const {
print_shared(st, "BranchData");
void BranchData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "BranchData", extra);
st->print_cr("taken(%u) displacement(%d)",
taken(), displacement());
tab(st);
@ -570,8 +608,8 @@ void MultiBranchData::post_initialize(BytecodeStream* stream,
}
#ifndef PRODUCT
void MultiBranchData::print_data_on(outputStream* st) const {
print_shared(st, "MultiBranchData");
void MultiBranchData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "MultiBranchData", extra);
st->print_cr("default_count(%u) displacement(%d)",
default_count(), default_displacement());
int cases = number_of_cases();
@ -584,8 +622,8 @@ void MultiBranchData::print_data_on(outputStream* st) const {
#endif
#ifndef PRODUCT
void ArgInfoData::print_data_on(outputStream* st) const {
print_shared(st, "ArgInfoData");
void ArgInfoData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ArgInfoData", extra);
int nargs = number_of_args();
for (int i = 0; i < nargs; i++) {
st->print(" 0x%x", arg_modified(i));
@ -616,10 +654,17 @@ bool ParametersTypeData::profiling_enabled() {
}
#ifndef PRODUCT
void ParametersTypeData::print_data_on(outputStream* st) const {
st->print("parameter types");
void ParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
st->print("parameter types", extra);
_parameters.print_data_on(st);
}
void SpeculativeTrapData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "SpeculativeTrapData", extra);
tab(st);
method()->print_short_name(st);
st->cr();
}
#endif
// ==================================================================
@ -745,7 +790,27 @@ int MethodData::compute_data_size(BytecodeStream* stream) {
return DataLayout::compute_size_in_bytes(cell_count);
}
int MethodData::compute_extra_data_count(int data_size, int empty_bc_count) {
bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) {
// Bytecodes for which we may use speculation
switch (code) {
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
case Bytecodes::_aastore:
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
case Bytecodes::_invokestatic:
#ifdef COMPILER2
return UseTypeSpeculation;
#endif
default:
return false;
}
return false;
}
int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) {
if (ProfileTraps) {
// Assume that up to 3% of BCIs with no MDP will need to allocate one.
int extra_data_count = (uint)(empty_bc_count * 3) / 128 + 1;
@ -756,7 +821,18 @@ int MethodData::compute_extra_data_count(int data_size, int empty_bc_count) {
extra_data_count = one_percent_of_data;
if (extra_data_count > empty_bc_count)
extra_data_count = empty_bc_count; // no need for more
return extra_data_count;
// Make sure we have a minimum number of extra data slots to
// allocate SpeculativeTrapData entries. We would want to have one
// entry per compilation that inlines this method and for which
// some type speculation assumption fails. So the room we need for
// the SpeculativeTrapData entries doesn't directly depend on the
// size of the method. Because it's hard to estimate, we reserve
// space for an arbitrary number of entries.
int spec_data_count = (needs_speculative_traps ? SpecTrapLimitExtraEntries : 0) *
(SpeculativeTrapData::static_cell_count() + DataLayout::header_size_in_cells());
return MAX2(extra_data_count, spec_data_count);
} else {
return 0;
}
@ -769,15 +845,17 @@ int MethodData::compute_allocation_size_in_bytes(methodHandle method) {
BytecodeStream stream(method);
Bytecodes::Code c;
int empty_bc_count = 0; // number of bytecodes lacking data
bool needs_speculative_traps = false;
while ((c = stream.next()) >= 0) {
int size_in_bytes = compute_data_size(&stream);
data_size += size_in_bytes;
if (size_in_bytes == 0) empty_bc_count += 1;
needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c);
}
int object_size = in_bytes(data_offset()) + data_size;
// Add some extra DataLayout cells (at least one) to track stray traps.
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count, needs_speculative_traps);
object_size += extra_data_count * DataLayout::compute_size_in_bytes(0);
// Add a cell to record information about modified arguments.
@ -1009,18 +1087,23 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
_data[0] = 0; // apparently not set below.
BytecodeStream stream(method);
Bytecodes::Code c;
bool needs_speculative_traps = false;
while ((c = stream.next()) >= 0) {
int size_in_bytes = initialize_data(&stream, data_size);
data_size += size_in_bytes;
if (size_in_bytes == 0) empty_bc_count += 1;
needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c);
}
_data_size = data_size;
int object_size = in_bytes(data_offset()) + data_size;
// Add some extra DataLayout cells (at least one) to track stray traps.
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count, needs_speculative_traps);
int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0);
// Let's zero the space for the extra data
Copy::zero_to_bytes(((address)_data) + data_size, extra_size);
// Add a cell to record information about modified arguments.
// Set up _args_modified array after traps cells so that
// the code for traps cells works.
@ -1032,17 +1115,17 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) {
int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1);
object_size += extra_size + arg_data_size;
int args_cell = ParametersTypeData::compute_cell_count(method());
int parms_cell = ParametersTypeData::compute_cell_count(method());
// If we are profiling parameters, we reserver an area near the end
// of the MDO after the slots for bytecodes (because there's no bci
// for method entry so they don't fit with the framework for the
// profiling of bytecodes). We store the offset within the MDO of
// this area (or -1 if no parameter is profiled)
if (args_cell > 0) {
object_size += DataLayout::compute_size_in_bytes(args_cell);
if (parms_cell > 0) {
object_size += DataLayout::compute_size_in_bytes(parms_cell);
_parameters_type_data_di = data_size + extra_size + arg_data_size;
DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size);
dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell);
dp->initialize(DataLayout::parameters_type_data_tag, 0, parms_cell);
} else {
_parameters_type_data_di = -1;
}
@ -1133,39 +1216,113 @@ ProfileData* MethodData::bci_to_data(int bci) {
break;
}
}
return bci_to_extra_data(bci, false);
return bci_to_extra_data(bci, NULL, false);
}
// Translate a bci to its corresponding extra data, or NULL.
ProfileData* MethodData::bci_to_extra_data(int bci, bool create_if_missing) {
DataLayout* dp = extra_data_base();
DataLayout* end = extra_data_limit();
DataLayout* avail = NULL;
for (; dp < end; dp = next_extra(dp)) {
DataLayout* MethodData::next_extra(DataLayout* dp) {
int nb_cells = 0;
switch(dp->tag()) {
case DataLayout::bit_data_tag:
case DataLayout::no_tag:
nb_cells = BitData::static_cell_count();
break;
case DataLayout::speculative_trap_data_tag:
nb_cells = SpeculativeTrapData::static_cell_count();
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells));
}
ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp) {
DataLayout* end = extra_data_limit();
for (;; dp = next_extra(dp)) {
assert(dp < end, "moved past end of extra data");
// No need for "OrderAccess::load_acquire" ops,
// since the data structure is monotonic.
if (dp->tag() == DataLayout::no_tag) break;
if (dp->tag() == DataLayout::arg_info_data_tag) {
dp = end; // ArgInfoData is at the end of extra data section.
switch(dp->tag()) {
case DataLayout::no_tag:
return NULL;
case DataLayout::arg_info_data_tag:
dp = end;
return NULL; // ArgInfoData is at the end of extra data section.
case DataLayout::bit_data_tag:
if (m == NULL && dp->bci() == bci) {
return new BitData(dp);
}
break;
}
if (dp->bci() == bci) {
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
return new BitData(dp);
case DataLayout::speculative_trap_data_tag:
if (m != NULL) {
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
// data->method() may be null in case of a concurrent
// allocation. Assume it's for the same method and use that
// entry in that case.
if (dp->bci() == bci) {
if (data->method() == NULL) {
return NULL;
} else if (data->method() == m) {
return data;
}
}
}
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
}
if (create_if_missing && dp < end) {
// Allocate this one. There is no mutual exclusion,
// so two threads could allocate different BCIs to the
// same data layout. This means these extra data
// records, like most other MDO contents, must not be
// trusted too much.
DataLayout temp;
temp.initialize(DataLayout::bit_data_tag, bci, 0);
dp->release_set_header(temp.header());
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
//NO: assert(dp->bci() == bci, "no concurrent allocation");
return new BitData(dp);
return NULL;
}
// Translate a bci to its corresponding extra data, or NULL.
ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_missing) {
// This code assumes an entry for a SpeculativeTrapData is 2 cells
assert(2*DataLayout::compute_size_in_bytes(BitData::static_cell_count()) ==
DataLayout::compute_size_in_bytes(SpeculativeTrapData::static_cell_count()),
"code needs to be adjusted");
DataLayout* dp = extra_data_base();
DataLayout* end = extra_data_limit();
// Allocation in the extra data space has to be atomic because not
// all entries have the same size and non atomic concurrent
// allocation would result in a corrupted extra data space.
while (true) {
ProfileData* result = bci_to_extra_data_helper(bci, m, dp);
if (result != NULL) {
return result;
}
if (create_if_missing && dp < end) {
assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free");
assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info");
u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag;
// SpeculativeTrapData is 2 slots. Make sure we have room.
if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) {
return NULL;
}
DataLayout temp;
temp.initialize(tag, bci, 0);
// May have been set concurrently
if (dp->header() != temp.header() && !dp->atomic_set_header(temp.header())) {
// Allocation failure because of concurrent allocation. Try
// again.
continue;
}
assert(dp->tag() == tag, "sane");
assert(dp->bci() == bci, "no concurrent allocation");
if (tag == DataLayout::bit_data_tag) {
return new BitData(dp);
} else {
// If being allocated concurrently, one trap may be lost
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
data->set_method(m);
return data;
}
}
return NULL;
}
return NULL;
}
@ -1210,25 +1367,35 @@ void MethodData::print_data_on(outputStream* st) const {
for ( ; is_valid(data); data = next_data(data)) {
st->print("%d", dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
data->print_data_on(st, this);
}
st->print_cr("--- Extra data:");
DataLayout* dp = extra_data_base();
DataLayout* end = extra_data_limit();
for (; dp < end; dp = next_extra(dp)) {
for (;; dp = next_extra(dp)) {
assert(dp < end, "moved past end of extra data");
// No need for "OrderAccess::load_acquire" ops,
// since the data structure is monotonic.
if (dp->tag() == DataLayout::no_tag) continue;
if (dp->tag() == DataLayout::bit_data_tag) {
switch(dp->tag()) {
case DataLayout::no_tag:
continue;
case DataLayout::bit_data_tag:
data = new BitData(dp);
} else {
assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo");
break;
case DataLayout::speculative_trap_data_tag:
data = new SpeculativeTrapData(dp);
break;
case DataLayout::arg_info_data_tag:
data = new ArgInfoData(dp);
dp = end; // ArgInfoData is at the end of extra data section.
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
st->print("%d", dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
if (dp >= end) return;
}
}
#endif
@ -1351,3 +1518,110 @@ bool MethodData::profile_parameters_for_method(methodHandle m) {
assert(profile_parameters_jsr292_only(), "inconsistent");
return m->is_compiled_lambda_form();
}
void MethodData::clean_extra_data_helper(DataLayout* dp, int shift, bool reset) {
if (shift == 0) {
return;
}
if (!reset) {
// Move all cells of trap entry at dp left by "shift" cells
intptr_t* start = (intptr_t*)dp;
intptr_t* end = (intptr_t*)next_extra(dp);
for (intptr_t* ptr = start; ptr < end; ptr++) {
*(ptr-shift) = *ptr;
}
} else {
// Reset "shift" cells stopping at dp
intptr_t* start = ((intptr_t*)dp) - shift;
intptr_t* end = (intptr_t*)dp;
for (intptr_t* ptr = start; ptr < end; ptr++) {
*ptr = 0;
}
}
}
// Remove SpeculativeTrapData entries that reference an unloaded
// method
void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
DataLayout* dp = extra_data_base();
DataLayout* end = extra_data_limit();
int shift = 0;
for (; dp < end; dp = next_extra(dp)) {
switch(dp->tag()) {
case DataLayout::speculative_trap_data_tag: {
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
Method* m = data->method();
assert(m != NULL, "should have a method");
if (!m->method_holder()->is_loader_alive(is_alive)) {
// "shift" accumulates the number of cells for dead
// SpeculativeTrapData entries that have been seen so
// far. Following entries must be shifted left by that many
// cells to remove the dead SpeculativeTrapData entries.
shift += (int)((intptr_t*)next_extra(dp) - (intptr_t*)dp);
} else {
// Shift this entry left if it follows dead
// SpeculativeTrapData entries
clean_extra_data_helper(dp, shift);
}
break;
}
case DataLayout::bit_data_tag:
// Shift this entry left if it follows dead SpeculativeTrapData
// entries
clean_extra_data_helper(dp, shift);
continue;
case DataLayout::no_tag:
case DataLayout::arg_info_data_tag:
// We are at end of the live trap entries. The previous "shift"
// cells contain entries that are either dead or were shifted
// left. They need to be reset to no_tag
clean_extra_data_helper(dp, shift, true);
return;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
}
}
// Verify there's no unloaded method referenced by a
// SpeculativeTrapData entry
void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
#ifdef ASSERT
DataLayout* dp = extra_data_base();
DataLayout* end = extra_data_limit();
for (; dp < end; dp = next_extra(dp)) {
switch(dp->tag()) {
case DataLayout::speculative_trap_data_tag: {
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
Method* m = data->method();
assert(m != NULL && m->method_holder()->is_loader_alive(is_alive), "Method should exist");
break;
}
case DataLayout::bit_data_tag:
continue;
case DataLayout::no_tag:
case DataLayout::arg_info_data_tag:
return;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
}
#endif
}
void MethodData::clean_method_data(BoolObjectClosure* is_alive) {
for (ProfileData* data = first_data();
is_valid(data);
data = next_data(data)) {
data->clean_weak_klass_links(is_alive);
}
ParametersTypeData* parameters = parameters_type_data();
if (parameters != NULL) {
parameters->clean_weak_klass_links(is_alive);
}
clean_extra_data(is_alive);
verify_extra_data_clean(is_alive);
}

View File

@ -120,7 +120,8 @@ public:
arg_info_data_tag,
call_type_data_tag,
virtual_call_type_data_tag,
parameters_type_data_tag
parameters_type_data_tag,
speculative_trap_data_tag
};
enum {
@ -189,8 +190,11 @@ public:
void set_header(intptr_t value) {
_header._bits = value;
}
void release_set_header(intptr_t value) {
OrderAccess::release_store_ptr(&_header._bits, value);
bool atomic_set_header(intptr_t value) {
if (Atomic::cmpxchg_ptr(value, (volatile intptr_t*)&_header._bits, 0) == 0) {
return true;
}
return false;
}
intptr_t header() {
return _header._bits;
@ -271,6 +275,7 @@ class ArrayData;
class MultiBranchData;
class ArgInfoData;
class ParametersTypeData;
class SpeculativeTrapData;
// ProfileData
//
@ -291,6 +296,8 @@ private:
// This is a pointer to a section of profiling data.
DataLayout* _data;
char* print_data_on_helper(const MethodData* md) const;
protected:
DataLayout* data() { return _data; }
const DataLayout* data() const { return _data; }
@ -440,6 +447,7 @@ public:
virtual bool is_CallTypeData() const { return false; }
virtual bool is_VirtualCallTypeData()const { return false; }
virtual bool is_ParametersTypeData() const { return false; }
virtual bool is_SpeculativeTrapData()const { return false; }
BitData* as_BitData() const {
@ -494,6 +502,10 @@ public:
assert(is_ParametersTypeData(), "wrong type");
return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL;
}
SpeculativeTrapData* as_SpeculativeTrapData() const {
assert(is_SpeculativeTrapData(), "wrong type");
return is_SpeculativeTrapData() ? (SpeculativeTrapData*)this : NULL;
}
// Subclass specific initialization
@ -509,12 +521,14 @@ public:
// translation here, and the required translators are in the ci subclasses.
virtual void translate_from(const ProfileData* data) {}
virtual void print_data_on(outputStream* st) const {
virtual void print_data_on(outputStream* st, const char* extra = NULL) const {
ShouldNotReachHere();
}
void print_data_on(outputStream* st, const MethodData* md) const;
#ifndef PRODUCT
void print_shared(outputStream* st, const char* name) const;
void print_shared(outputStream* st, const char* name, const char* extra) const;
void tab(outputStream* st, bool first = false) const;
#endif
};
@ -576,7 +590,7 @@ public:
#endif // CC_INTERP
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -639,7 +653,7 @@ public:
#endif // CC_INTERP
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -726,7 +740,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1137,7 +1151,7 @@ public:
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1282,7 +1296,7 @@ public:
#ifndef PRODUCT
void print_receiver_data_on(outputStream* st) const;
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1325,7 +1339,7 @@ public:
#endif // CC_INTERP
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1451,7 +1465,7 @@ public:
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1554,7 +1568,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1632,7 +1646,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1825,7 +1839,7 @@ public:
void post_initialize(BytecodeStream* stream, MethodData* mdo);
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1852,7 +1866,7 @@ public:
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
@ -1913,7 +1927,7 @@ public:
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st) const;
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
static ByteSize stack_slot_offset(int i) {
@ -1925,6 +1939,54 @@ public:
}
};
// SpeculativeTrapData
//
// A SpeculativeTrapData is used to record traps due to type
// speculation. It records the root of the compilation: that type
// speculation is wrong in the context of one compilation (for
// method1) doesn't mean it's wrong in the context of another one (for
// method2). Type speculation could have more/different data in the
// context of the compilation of method2 and it's worthwhile to try an
// optimization that failed for compilation of method1 in the context
// of compilation of method2.
// Space for SpeculativeTrapData entries is allocated from the extra
// data space in the MDO. If we run out of space, the trap data for
// the ProfileData at that bci is updated.
class SpeculativeTrapData : public ProfileData {
protected:
enum {
method_offset,
speculative_trap_cell_count
};
public:
SpeculativeTrapData(DataLayout* layout) : ProfileData(layout) {
assert(layout->tag() == DataLayout::speculative_trap_data_tag, "wrong type");
}
virtual bool is_SpeculativeTrapData() const { return true; }
static int static_cell_count() {
return speculative_trap_cell_count;
}
virtual int cell_count() const {
return static_cell_count();
}
// Direct accessor
Method* method() const {
return (Method*)intptr_at(method_offset);
}
void set_method(Method* m) {
set_intptr_at(method_offset, (intptr_t)m);
}
#ifndef PRODUCT
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
#endif
};
// MethodData*
//
// A MethodData* holds information which has been collected about
@ -1994,7 +2056,7 @@ public:
// Whole-method sticky bits and flags
enum {
_trap_hist_limit = 17, // decoupled from Deoptimization::Reason_LIMIT
_trap_hist_limit = 18, // decoupled from Deoptimization::Reason_LIMIT
_trap_hist_mask = max_jubyte,
_extra_data_count = 4 // extra DataLayout headers, for trap history
}; // Public flag values
@ -2049,6 +2111,7 @@ private:
// Helper for size computation
static int compute_data_size(BytecodeStream* stream);
static int bytecode_cell_count(Bytecodes::Code code);
static bool is_speculative_trap_bytecode(Bytecodes::Code code);
enum { no_profile_data = -1, variable_cell_count = -2 };
// Helper for initialization
@ -2092,8 +2155,9 @@ private:
// What is the index of the first data entry?
int first_di() const { return 0; }
ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp);
// Find or create an extra ProfileData:
ProfileData* bci_to_extra_data(int bci, bool create_if_missing);
ProfileData* bci_to_extra_data(int bci, Method* m, bool create_if_missing);
// return the argument info cell
ArgInfoData *arg_info();
@ -2116,6 +2180,10 @@ private:
static bool profile_parameters_jsr292_only();
static bool profile_all_parameters();
void clean_extra_data(BoolObjectClosure* is_alive);
void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
void verify_extra_data_clean(BoolObjectClosure* is_alive);
public:
static int header_size() {
return sizeof(MethodData)/wordSize;
@ -2124,7 +2192,7 @@ public:
// Compute the size of a MethodData* before it is created.
static int compute_allocation_size_in_bytes(methodHandle method);
static int compute_allocation_size_in_words(methodHandle method);
static int compute_extra_data_count(int data_size, int empty_bc_count);
static int compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps);
// Determine if a given bytecode can have profile information.
static bool bytecode_has_profile(Bytecodes::Code code) {
@ -2265,9 +2333,26 @@ public:
ProfileData* bci_to_data(int bci);
// Same, but try to create an extra_data record if one is needed:
ProfileData* allocate_bci_to_data(int bci) {
ProfileData* data = bci_to_data(bci);
return (data != NULL) ? data : bci_to_extra_data(bci, true);
ProfileData* allocate_bci_to_data(int bci, Method* m) {
ProfileData* data = NULL;
// If m not NULL, try to allocate a SpeculativeTrapData entry
if (m == NULL) {
data = bci_to_data(bci);
}
if (data != NULL) {
return data;
}
data = bci_to_extra_data(bci, m, true);
if (data != NULL) {
return data;
}
// If SpeculativeTrapData allocation fails try to allocate a
// regular entry
data = bci_to_data(bci);
if (data != NULL) {
return data;
}
return bci_to_extra_data(bci, NULL, true);
}
// Add a handful of extra data records, for trap tracking.
@ -2275,7 +2360,7 @@ public:
DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); }
int extra_data_size() const { return (address)extra_data_limit()
- (address)extra_data_base(); }
static DataLayout* next_extra(DataLayout* dp) { return (DataLayout*)((address)dp + in_bytes(DataLayout::cell_offset(0))); }
static DataLayout* next_extra(DataLayout* dp);
// Return (uint)-1 for overflow.
uint trap_count(int reason) const {
@ -2375,6 +2460,8 @@ public:
static bool profile_return();
static bool profile_parameters();
static bool profile_return_jsr292_only();
void clean_method_data(BoolObjectClosure* is_alive);
};
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP

View File

@ -90,9 +90,9 @@ public:
class CFGElement : public ResourceObj {
friend class VMStructs;
public:
float _freq; // Execution frequency (estimate)
double _freq; // Execution frequency (estimate)
CFGElement() : _freq(0.0f) {}
CFGElement() : _freq(0.0) {}
virtual bool is_block() { return false; }
virtual bool is_loop() { return false; }
Block* as_Block() { assert(is_block(), "must be block"); return (Block*)this; }
@ -202,7 +202,7 @@ public:
// BLOCK_FREQUENCY is a sentinel to mark uses of constant block frequencies.
// It is currently also used to scale such frequencies relative to
// FreqCountInvocations relative to the old value of 1500.
#define BLOCK_FREQUENCY(f) ((f * (float) 1500) / FreqCountInvocations)
#define BLOCK_FREQUENCY(f) ((f * (double) 1500) / FreqCountInvocations)
// Register Pressure (estimate) for Splitting heuristic
uint _reg_pressure;
@ -393,7 +393,7 @@ class PhaseCFG : public Phase {
CFGLoop* _root_loop;
// Outmost loop frequency
float _outer_loop_frequency;
double _outer_loop_frequency;
// Per node latency estimation, valid only during GCM
GrowableArray<uint>* _node_latency;
@ -508,7 +508,7 @@ class PhaseCFG : public Phase {
}
// Get the outer most frequency
float get_outer_loop_frequency() const {
double get_outer_loop_frequency() const {
return _outer_loop_frequency;
}
@ -656,13 +656,13 @@ public:
class BlockProbPair VALUE_OBJ_CLASS_SPEC {
protected:
Block* _target; // block target
float _prob; // probability of edge to block
double _prob; // probability of edge to block
public:
BlockProbPair() : _target(NULL), _prob(0.0) {}
BlockProbPair(Block* b, float p) : _target(b), _prob(p) {}
BlockProbPair(Block* b, double p) : _target(b), _prob(p) {}
Block* get_target() const { return _target; }
float get_prob() const { return _prob; }
double get_prob() const { return _prob; }
};
//------------------------------CFGLoop-------------------------------------------
@ -675,8 +675,8 @@ class CFGLoop : public CFGElement {
CFGLoop *_child; // first child, use child's sibling to visit all immediately nested loops
GrowableArray<CFGElement*> _members; // list of members of loop
GrowableArray<BlockProbPair> _exits; // list of successor blocks and their probabilities
float _exit_prob; // probability any loop exit is taken on a single loop iteration
void update_succ_freq(Block* b, float freq);
double _exit_prob; // probability any loop exit is taken on a single loop iteration
void update_succ_freq(Block* b, double freq);
public:
CFGLoop(int id) :
@ -702,9 +702,9 @@ class CFGLoop : public CFGElement {
void compute_loop_depth(int depth);
void compute_freq(); // compute frequency with loop assuming head freq 1.0f
void scale_freq(); // scale frequency by loop trip count (including outer loops)
float outer_loop_freq() const; // frequency of outer loop
double outer_loop_freq() const; // frequency of outer loop
bool in_loop_nest(Block* b);
float trip_count() const { return 1.0f / _exit_prob; }
double trip_count() const { return 1.0 / _exit_prob; }
virtual bool is_loop() { return true; }
int id() { return _id; }
@ -723,7 +723,7 @@ class CFGEdge : public ResourceObj {
private:
Block * _from; // Source basic block
Block * _to; // Destination basic block
float _freq; // Execution frequency (estimate)
double _freq; // Execution frequency (estimate)
int _state;
bool _infrequent;
int _from_pct;
@ -742,13 +742,13 @@ class CFGEdge : public ResourceObj {
interior // edge is interior to trace (could be backedge)
};
CFGEdge(Block *from, Block *to, float freq, int from_pct, int to_pct) :
CFGEdge(Block *from, Block *to, double freq, int from_pct, int to_pct) :
_from(from), _to(to), _freq(freq),
_from_pct(from_pct), _to_pct(to_pct), _state(open) {
_infrequent = from_infrequent() || to_infrequent();
}
float freq() const { return _freq; }
double freq() const { return _freq; }
Block* from() const { return _from; }
Block* to () const { return _to; }
int infrequent() const { return _infrequent; }

View File

@ -644,7 +644,7 @@
diagnostic(bool, OptimizeExpensiveOps, true, \
"Find best control for expensive operations") \
\
experimental(bool, UseMathExactIntrinsics, false, \
product(bool, UseMathExactIntrinsics, true, \
"Enables intrinsification of various java.lang.Math functions") \
\
experimental(bool, ReplaceInParentMaps, false, \
@ -653,6 +653,10 @@
experimental(bool, UseTypeSpeculation, false, \
"Speculatively propagate types from profiles") \
\
diagnostic(bool, UseInlineDepthForSpeculativeTypes, true, \
"Carry inline depth of profile point with speculative type " \
"and give priority to profiling from lower inline depth") \
\
product_pd(bool, TrapBasedRangeChecks, \
"Generate code for range checks that uses a cmp and trap " \
"instruction raising SIGTRAP. Used on PPC64.") \

View File

@ -210,7 +210,7 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher)
{
NOT_PRODUCT( Compile::TracePhase t3("ctorChaitin", &_t_ctorChaitin, TimeCompiler); )
_high_frequency_lrg = MIN2(float(OPTO_LRG_HIGH_FREQ), _cfg.get_outer_loop_frequency());
_high_frequency_lrg = MIN2(double(OPTO_LRG_HIGH_FREQ), _cfg.get_outer_loop_frequency());
// Build a list of basic blocks, sorted by frequency
_blks = NEW_RESOURCE_ARRAY(Block *, _cfg.number_of_blocks());
@ -1799,7 +1799,7 @@ bool PhaseChaitin::stretch_base_pointer_live_ranges(ResourceArea *a) {
Block *phi_block = _cfg.get_block_for_node(phi);
if (_cfg.get_block_for_node(phi_block->pred(2)) == block) {
const RegMask *mask = C->matcher()->idealreg2spillmask[Op_RegI];
Node *spill = new (C) MachSpillCopyNode( phi, *mask, *mask );
Node *spill = new (C) MachSpillCopyNode(MachSpillCopyNode::LoopPhiInput, phi, *mask, *mask);
insert_proj( phi_block, 1, spill, maxlrg++ );
n->set_req(1,spill);
must_recompute_live = true;

View File

@ -34,10 +34,9 @@
#include "opto/phase.hpp"
#include "opto/regalloc.hpp"
#include "opto/regmask.hpp"
#include "opto/machnode.hpp"
class LoopTree;
class MachCallNode;
class MachSafePointNode;
class Matcher;
class PhaseCFG;
class PhaseLive;
@ -424,8 +423,8 @@ class PhaseChaitin : public PhaseRegAlloc {
uint _simplified; // Linked list head of simplified LRGs
// Helper functions for Split()
uint split_DEF( Node *def, Block *b, int loc, uint max, Node **Reachblock, Node **debug_defs, GrowableArray<uint> splits, int slidx );
uint split_USE( Node *def, Block *b, Node *use, uint useidx, uint max, bool def_down, bool cisc_sp, GrowableArray<uint> splits, int slidx );
uint split_DEF(Node *def, Block *b, int loc, uint max, Node **Reachblock, Node **debug_defs, GrowableArray<uint> splits, int slidx );
uint split_USE(MachSpillCopyNode::SpillType spill_type, Node *def, Block *b, Node *use, uint useidx, uint max, bool def_down, bool cisc_sp, GrowableArray<uint> splits, int slidx );
//------------------------------clone_projs------------------------------------
// After cloning some rematerialized instruction, clone any MachProj's that
@ -447,7 +446,7 @@ class PhaseChaitin : public PhaseRegAlloc {
int slidx, uint *lrg2reach, Node **Reachblock, bool walkThru);
// True if lidx is used before any real register is def'd in the block
bool prompt_use( Block *b, uint lidx );
Node *get_spillcopy_wide( Node *def, Node *use, uint uidx );
Node *get_spillcopy_wide(MachSpillCopyNode::SpillType spill_type, Node *def, Node *use, uint uidx );
// Insert the spill at chosen location. Skip over any intervening Proj's or
// Phis. Skip over a CatchNode and projs, inserting in the fall-through block
// instead. Update high-pressure indices. Create a new live range.
@ -501,8 +500,9 @@ private:
// Used for aggressive coalescing.
void build_ifg_virtual( );
// used when computing the register pressure for each block in the CFG. This
// is done during IFG creation.
class Pressure {
public:
// keeps track of the register pressure at the current
// instruction (used when stepping backwards in the block)
uint _current_pressure;
@ -518,6 +518,7 @@ private:
// number of live ranges that constitute high register pressure
const uint _high_pressure_limit;
public:
// lower the register pressure and look for a low to high pressure
// transition
@ -525,9 +526,6 @@ private:
_current_pressure -= lrg.reg_pressure();
if (_current_pressure == _high_pressure_limit) {
_high_pressure_index = location;
if (_current_pressure > _final_pressure) {
_final_pressure = _current_pressure + 1;
}
}
}
@ -540,6 +538,45 @@ private:
}
}
uint high_pressure_index() const {
return _high_pressure_index;
}
uint final_pressure() const {
return _final_pressure;
}
uint current_pressure() const {
return _current_pressure;
}
uint high_pressure_limit() const {
return _high_pressure_limit;
}
void lower_high_pressure_index() {
_high_pressure_index--;
}
void set_high_pressure_index_to_block_start() {
_high_pressure_index = 0;
}
void check_pressure_at_fatproj(uint fatproj_location, RegMask& fatproj_mask) {
// this pressure is only valid at this instruction, i.e. we don't need to lower
// the register pressure since the fat proj was never live before (going backwards)
uint new_pressure = current_pressure() + fatproj_mask.Size();
if (new_pressure > final_pressure()) {
_final_pressure = new_pressure;
}
// if we were at a low pressure and now and the fat proj is at high pressure, record the fat proj location
// as coming from a low to high (to low again)
if (current_pressure() <= high_pressure_limit() && new_pressure > high_pressure_limit()) {
_high_pressure_index = fatproj_location;
}
}
Pressure(uint high_pressure_index, uint high_pressure_limit)
: _current_pressure(0)
, _high_pressure_index(high_pressure_index)

View File

@ -29,8 +29,6 @@ macro(AbsD)
macro(AbsF)
macro(AbsI)
macro(AddD)
macro(AddExactI)
macro(AddExactL)
macro(AddF)
macro(AddI)
macro(AddL)
@ -135,7 +133,6 @@ macro(EncodePKlass)
macro(ExpD)
macro(FastLock)
macro(FastUnlock)
macro(FlagsProj)
macro(Goto)
macro(Halt)
macro(If)
@ -170,9 +167,6 @@ macro(Loop)
macro(LoopLimit)
macro(Mach)
macro(MachProj)
macro(MathExact)
macro(MathExactI)
macro(MathExactL)
macro(MaxI)
macro(MemBarAcquire)
macro(LoadFence)
@ -194,22 +188,24 @@ macro(MoveF2I)
macro(MoveL2D)
macro(MoveD2L)
macro(MulD)
macro(MulExactI)
macro(MulExactL)
macro(MulF)
macro(MulHiL)
macro(MulI)
macro(MulL)
macro(Multi)
macro(NegD)
macro(NegExactI)
macro(NegExactL)
macro(NegF)
macro(NeverBranch)
macro(Opaque1)
macro(Opaque2)
macro(OrI)
macro(OrL)
macro(OverflowAddI)
macro(OverflowSubI)
macro(OverflowMulI)
macro(OverflowAddL)
macro(OverflowSubL)
macro(OverflowMulL)
macro(PCTable)
macro(Parm)
macro(PartialSubtypeCheck)
@ -253,8 +249,6 @@ macro(StrComp)
macro(StrEquals)
macro(StrIndexOf)
macro(SubD)
macro(SubExactI)
macro(SubExactL)
macro(SubF)
macro(SubI)
macro(SubL)

View File

@ -291,7 +291,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
_phc.clone_projs(pred, pred->end_idx(), m, copy, _phc._lrg_map);
} else {
const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
copy = new (C) MachSpillCopyNode(m, *rm, *rm);
copy = new (C) MachSpillCopyNode(MachSpillCopyNode::PhiInput, m, *rm, *rm);
// Find a good place to insert. Kinda tricky, use a subroutine
insert_copy_with_overlap(pred,copy,phi_name,src_name);
}
@ -325,7 +325,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
l += _phc.clone_projs(b, l, m, copy, _phc._lrg_map);
} else {
const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()];
copy = new (C) MachSpillCopyNode(m, *rm, *rm);
copy = new (C) MachSpillCopyNode(MachSpillCopyNode::TwoAddress, m, *rm, *rm);
// Insert the copy in the basic block, just before us
b->insert_node(copy, l++);
}
@ -372,7 +372,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) {
continue; // Live out; do not pre-split
// Split the lrg at this use
const RegMask *rm = C->matcher()->idealreg2spillmask[inp->ideal_reg()];
Node *copy = new (C) MachSpillCopyNode( inp, *rm, *rm );
Node* copy = new (C) MachSpillCopyNode(MachSpillCopyNode::DebugUse, inp, *rm, *rm);
// Insert the copy in the use-def chain
n->set_req(inpidx, copy );
// Insert the copy in the basic block, just before us

View File

@ -3028,42 +3028,6 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) {
n->set_req(MemBarNode::Precedent, top());
}
break;
// Must set a control edge on all nodes that produce a FlagsProj
// so they can't escape the block that consumes the flags.
// Must also set the non throwing branch as the control
// for all nodes that depends on the result. Unless the node
// already have a control that isn't the control of the
// flag producer
case Op_FlagsProj:
{
MathExactNode* math = (MathExactNode*) n->in(0);
Node* ctrl = math->control_node();
Node* non_throwing = math->non_throwing_branch();
math->set_req(0, ctrl);
Node* result = math->result_node();
if (result != NULL) {
for (DUIterator_Fast jmax, j = result->fast_outs(jmax); j < jmax; j++) {
Node* out = result->fast_out(j);
// Phi nodes shouldn't be moved. They would only match below if they
// had the same control as the MathExactNode. The only time that
// would happen is if the Phi is also an input to the MathExact
//
// Cmp nodes shouldn't have control set at all.
if (out->is_Phi() ||
out->is_Cmp()) {
continue;
}
if (out->in(0) == NULL) {
out->set_req(0, non_throwing);
} else if (out->in(0) == ctrl) {
out->set_req(0, non_throwing);
}
}
}
}
break;
default:
assert( !n->is_Call(), "" );
assert( !n->is_Mem(), "" );
@ -3285,7 +3249,8 @@ bool Compile::too_many_traps(ciMethod* method,
// because of a transient condition during start-up in the interpreter.
return false;
}
if (md->has_trap_at(bci, reason) != 0) {
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? this->method() : NULL;
if (md->has_trap_at(bci, m, reason) != 0) {
// Assume PerBytecodeTrapLimit==0, for a more conservative heuristic.
// Also, if there are multiple reasons, or if there is no per-BCI record,
// assume the worst.
@ -3303,7 +3268,7 @@ bool Compile::too_many_traps(ciMethod* method,
// Less-accurate variant which does not require a method and bci.
bool Compile::too_many_traps(Deoptimization::DeoptReason reason,
ciMethodData* logmd) {
if (trap_count(reason) >= (uint)PerMethodTrapLimit) {
if (trap_count(reason) >= Deoptimization::per_method_trap_limit(reason)) {
// Too many traps globally.
// Note that we use cumulative trap_count, not just md->trap_count.
if (log()) {
@ -3338,10 +3303,11 @@ bool Compile::too_many_recompiles(ciMethod* method,
uint m_cutoff = (uint) PerMethodRecompilationCutoff / 2 + 1; // not zero
Deoptimization::DeoptReason per_bc_reason
= Deoptimization::reason_recorded_per_bytecode_if_any(reason);
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? this->method() : NULL;
if ((per_bc_reason == Deoptimization::Reason_none
|| md->has_trap_at(bci, reason) != 0)
|| md->has_trap_at(bci, m, reason) != 0)
// The trap frequency measure we care about is the recompile count:
&& md->trap_recompiled_at(bci)
&& md->trap_recompiled_at(bci, m)
&& md->overflow_recompile_count() >= bc_cutoff) {
// Do not emit a trap here if it has already caused recompilations.
// Also, if there are multiple reasons, or if there is no per-BCI record,

View File

@ -250,7 +250,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
CallGenerator* miss_cg;
Deoptimization::DeoptReason reason = morphism == 2 ?
Deoptimization::Reason_bimorphic :
Deoptimization::Reason_class_check;
(speculative_receiver_type == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check);
if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) &&
!too_many_traps(jvms->method(), jvms->bci(), reason)
) {

View File

@ -1661,10 +1661,10 @@ void CFGLoop::compute_freq() {
}
assert (_members.length() > 0, "no empty loops");
Block* hd = head();
hd->_freq = 1.0f;
hd->_freq = 1.0;
for (int i = 0; i < _members.length(); i++) {
CFGElement* s = _members.at(i);
float freq = s->_freq;
double freq = s->_freq;
if (s->is_block()) {
Block* b = s->as_Block();
for (uint j = 0; j < b->_num_succs; j++) {
@ -1676,7 +1676,7 @@ void CFGLoop::compute_freq() {
assert(lp->_parent == this, "immediate child");
for (int k = 0; k < lp->_exits.length(); k++) {
Block* eb = lp->_exits.at(k).get_target();
float prob = lp->_exits.at(k).get_prob();
double prob = lp->_exits.at(k).get_prob();
update_succ_freq(eb, freq * prob);
}
}
@ -1688,7 +1688,7 @@ void CFGLoop::compute_freq() {
// inner blocks do not get erroneously scaled.
if (_depth != 0) {
// Total the exit probabilities for this loop.
float exits_sum = 0.0f;
double exits_sum = 0.0f;
for (int i = 0; i < _exits.length(); i++) {
exits_sum += _exits.at(i).get_prob();
}
@ -1935,7 +1935,7 @@ void Block::update_uncommon_branch(Block* ub) {
//------------------------------update_succ_freq-------------------------------
// Update the appropriate frequency associated with block 'b', a successor of
// a block in this loop.
void CFGLoop::update_succ_freq(Block* b, float freq) {
void CFGLoop::update_succ_freq(Block* b, double freq) {
if (b->_loop == this) {
if (b == head()) {
// back branch within the loop
@ -1976,11 +1976,11 @@ bool CFGLoop::in_loop_nest(Block* b) {
// Scale frequency of loops and blocks by trip counts from outer loops
// Do a top down traversal of loop tree (visit outer loops first.)
void CFGLoop::scale_freq() {
float loop_freq = _freq * trip_count();
double loop_freq = _freq * trip_count();
_freq = loop_freq;
for (int i = 0; i < _members.length(); i++) {
CFGElement* s = _members.at(i);
float block_freq = s->_freq * loop_freq;
double block_freq = s->_freq * loop_freq;
if (g_isnan(block_freq) || block_freq < MIN_BLOCK_FREQUENCY)
block_freq = MIN_BLOCK_FREQUENCY;
s->_freq = block_freq;
@ -1993,7 +1993,7 @@ void CFGLoop::scale_freq() {
}
// Frequency of outer loop
float CFGLoop::outer_loop_freq() const {
double CFGLoop::outer_loop_freq() const {
if (_child != NULL) {
return _child->_freq;
}
@ -2042,7 +2042,7 @@ void CFGLoop::dump() const {
k = 0;
}
Block *blk = _exits.at(i).get_target();
float prob = _exits.at(i).get_prob();
double prob = _exits.at(i).get_prob();
tty->print(" ->%d@%d%%", blk->_pre_order, (int)(prob*100));
}
tty->print("\n");

View File

@ -612,9 +612,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
// Usual case: Bail to interpreter.
// Reserve the right to recompile if we haven't seen anything yet.
assert(!Deoptimization::reason_is_speculate(reason), "unsupported");
Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile;
if (treat_throw_as_hot
&& (method()->method_data()->trap_recompiled_at(bci())
&& (method()->method_data()->trap_recompiled_at(bci(), NULL)
|| C->too_many_traps(reason))) {
// We cannot afford to take more traps here. Suffer in the interpreter.
if (C->log() != NULL)
@ -2112,30 +2113,33 @@ void GraphKit::round_double_arguments(ciMethod* dest_method) {
* @return node with improved type
*/
Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) {
const TypeOopPtr* current_type = _gvn.type(n)->isa_oopptr();
const Type* current_type = _gvn.type(n);
assert(UseTypeSpeculation, "type speculation must be on");
if (exact_kls != NULL &&
// nothing to improve if type is already exact
(current_type == NULL ||
(!current_type->klass_is_exact() &&
(current_type->speculative() == NULL ||
!current_type->speculative()->klass_is_exact())))) {
const TypeOopPtr* speculative = current_type->speculative();
if (current_type->would_improve_type(exact_kls, jvms()->depth())) {
const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
const TypeOopPtr* xtype = tklass->as_instance_type();
assert(xtype->klass_is_exact(), "Should be exact");
// record the new speculative type's depth
speculative = xtype->with_inline_depth(jvms()->depth());
}
if (speculative != current_type->speculative()) {
// Build a type with a speculative type (what we think we know
// about the type but will need a guard when we use it)
const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, xtype);
// We're changing the type, we need a new cast node to carry the
// new type. The new type depends on the control: what profiling
// tells us is only valid from here as far as we can tell.
Node* cast = new(C) CastPPNode(n, spec_type);
cast->init_req(0, control());
const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, speculative);
// We're changing the type, we need a new CheckCast node to carry
// the new type. The new type depends on the control: what
// profiling tells us is only valid from here as far as we can
// tell.
Node* cast = new(C) CheckCastPPNode(control(), n, current_type->remove_speculative()->join_speculative(spec_type));
cast = _gvn.transform(cast);
replace_in_map(n, cast);
n = cast;
}
return n;
}
@ -2145,7 +2149,7 @@ Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) {
*
* @param n receiver node
*
* @return node with improved type
* @return node with improved type
*/
Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
if (!UseTypeSpeculation) {
@ -2739,12 +2743,14 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
// Subsequent type checks will always fold up.
Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
ciKlass* require_klass,
ciKlass* spec_klass,
ciKlass* spec_klass,
bool safe_for_replace) {
if (!UseTypeProfile || !TypeProfileCasts) return NULL;
Deoptimization::DeoptReason reason = spec_klass == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check;
// Make sure we haven't already deoptimized from this tactic.
if (too_many_traps(Deoptimization::Reason_class_check))
if (too_many_traps(reason))
return NULL;
// (No, this isn't a call, but it's enough like a virtual call
@ -2766,7 +2772,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
&exact_obj);
{ PreserveJVMState pjvms(this);
set_control(slow_ctl);
uncommon_trap(Deoptimization::Reason_class_check,
uncommon_trap(reason,
Deoptimization::Action_maybe_recompile);
}
if (safe_for_replace) {
@ -2793,8 +2799,10 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
bool not_null) {
// type == NULL if profiling tells us this object is always null
if (type != NULL) {
if (!too_many_traps(Deoptimization::Reason_null_check) &&
!too_many_traps(Deoptimization::Reason_class_check)) {
Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check;
if (!too_many_traps(null_reason) &&
!too_many_traps(class_reason)) {
Node* not_null_obj = NULL;
// not_null is true if we know the object is not null and
// there's no need for a null check
@ -2813,7 +2821,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
{
PreserveJVMState pjvms(this);
set_control(slow_ctl);
uncommon_trap(Deoptimization::Reason_class_check,
uncommon_trap(class_reason,
Deoptimization::Action_maybe_recompile);
}
replace_in_map(not_null_obj, exact_obj);
@ -2882,7 +2890,7 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
}
if (known_statically && UseTypeSpeculation) {
// If we know the type check always succeed then we don't use the
// If we know the type check always succeeds then we don't use the
// profiling data at this bytecode. Don't lose it, feed it to the
// type system as a speculative type.
not_null_obj = record_profiled_receiver_for_speculation(not_null_obj);

View File

@ -406,7 +406,7 @@ class GraphKit : public Phase {
// Use the type profile to narrow an object type.
Node* maybe_cast_profiled_receiver(Node* not_null_obj,
ciKlass* require_klass,
ciKlass* spec,
ciKlass* spec,
bool safe_for_replace);
// Cast obj to type and emit guard unless we had too many traps here already

View File

@ -439,8 +439,8 @@ void PhaseChaitin::lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* l
}
}
}
assert(int_pressure._current_pressure == count_int_pressure(liveout), "the int pressure is incorrect");
assert(float_pressure._current_pressure == count_float_pressure(liveout), "the float pressure is incorrect");
assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect");
assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect");
}
/* Go to the first non-phi index in a block */
@ -513,8 +513,8 @@ void PhaseChaitin::compute_initial_block_pressure(Block* b, IndexSet* liveout, P
raise_pressure(b, lrg, int_pressure, float_pressure);
lid = elements.next();
}
assert(int_pressure._current_pressure == count_int_pressure(liveout), "the int pressure is incorrect");
assert(float_pressure._current_pressure == count_float_pressure(liveout), "the float pressure is incorrect");
assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect");
assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect");
}
/*
@ -548,17 +548,7 @@ bool PhaseChaitin::remove_node_if_not_used(Block* b, uint location, Node* n, uin
void PhaseChaitin::check_for_high_pressure_transition_at_fatproj(uint& block_reg_pressure, uint location, LRG& lrg, Pressure& pressure, const int op_regtype) {
RegMask mask_tmp = lrg.mask();
mask_tmp.AND(*Matcher::idealreg2regmask[op_regtype]);
// this pressure is only valid at this instruction, i.e. we don't need to lower
// the register pressure since the fat proj was never live before (going backwards)
uint new_pressure = pressure._current_pressure + mask_tmp.Size();
if (new_pressure > pressure._final_pressure) {
pressure._final_pressure = new_pressure;
}
// if we were at a low pressure and now at the fat proj is at high pressure, record the fat proj location
// as coming from a low to high (to low again)
if (pressure._current_pressure <= pressure._high_pressure_limit && new_pressure > pressure._high_pressure_limit) {
pressure._high_pressure_index = location;
}
pressure.check_pressure_at_fatproj(location, mask_tmp);
}
/*
@ -700,23 +690,23 @@ void PhaseChaitin::add_input_to_liveout(Block* b, Node* n, IndexSet* liveout, do
// Newly live things assumed live from here to top of block
lrg._area += cost;
raise_pressure(b, lrg, int_pressure, float_pressure);
assert(int_pressure._current_pressure == count_int_pressure(liveout), "the int pressure is incorrect");
assert(float_pressure._current_pressure == count_float_pressure(liveout), "the float pressure is incorrect");
assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect");
assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect");
}
assert(!(lrg._area < 0.0), "negative spill area" );
assert(lrg._area >= 0.0, "negative spill area" );
}
}
/*
* If we run off the top of the block with high pressure just record that the
* whole block is high pressure. (Even though we might have a transition
* lower down in the block)
* later down in the block)
*/
void PhaseChaitin::check_for_high_pressure_block(Pressure& pressure) {
// current pressure now means the pressure before the first instruction in the block
// (since we have stepped through all instructions backwards)
if (pressure._current_pressure > pressure._high_pressure_limit) {
pressure._high_pressure_index = 0;
if (pressure.current_pressure() > pressure.high_pressure_limit()) {
pressure.set_high_pressure_index_to_block_start();
}
}
@ -725,7 +715,7 @@ void PhaseChaitin::check_for_high_pressure_block(Pressure& pressure) {
* and set the high pressure index for the block
*/
void PhaseChaitin::adjust_high_pressure_index(Block* b, uint& block_hrp_index, Pressure& pressure) {
uint i = pressure._high_pressure_index;
uint i = pressure.high_pressure_index();
if (i < b->number_of_nodes() && i < b->end_idx() + 1) {
Node* cur = b->get_node(i);
while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) {
@ -772,7 +762,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
int inst_count = last_inst - first_inst;
double cost = (inst_count <= 0) ? 0.0 : block->_freq * double(inst_count);
assert(!(cost < 0.0), "negative spill cost" );
assert(cost >= 0.0, "negative spill cost" );
compute_initial_block_pressure(block, &liveout, int_pressure, float_pressure, cost);
@ -789,8 +779,8 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
if (!liveout.member(lid) && n->Opcode() != Op_SafePoint) {
if (remove_node_if_not_used(block, location, n, lid, &liveout)) {
float_pressure._high_pressure_index--;
int_pressure._high_pressure_index--;
float_pressure.lower_high_pressure_index();
int_pressure.lower_high_pressure_index();
continue;
}
if (lrg._fat_proj) {
@ -799,7 +789,11 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
}
} else {
// A live range ends at its definition, remove the remaining area.
lrg._area -= cost;
// If the cost is +Inf (which might happen in extreme cases), the lrg area will also be +Inf,
// and +Inf - +Inf = NaN. So let's not do that subtraction.
if (g_isfinite(cost)) {
lrg._area -= cost;
}
assert(lrg._area >= 0.0, "negative spill area" );
assign_high_score_to_immediate_copies(block, n, lrg, location + 1, last_inst);
@ -837,13 +831,13 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
adjust_high_pressure_index(block, block->_ihrp_index, int_pressure);
adjust_high_pressure_index(block, block->_fhrp_index, float_pressure);
// set the final_pressure as the register pressure for the block
block->_reg_pressure = int_pressure._final_pressure;
block->_freg_pressure = float_pressure._final_pressure;
block->_reg_pressure = int_pressure.final_pressure();
block->_freg_pressure = float_pressure.final_pressure();
#ifndef PRODUCT
// Gather Register Pressure Statistics
if (PrintOptoStatistics) {
if (block->_reg_pressure > int_pressure._high_pressure_limit || block->_freg_pressure > float_pressure._high_pressure_limit) {
if (block->_reg_pressure > int_pressure.high_pressure_limit() || block->_freg_pressure > float_pressure.high_pressure_limit()) {
_high_pressure++;
} else {
_low_pressure++;

View File

@ -76,7 +76,6 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
if( !i1->is_Bool() ) return NULL;
BoolNode *b = i1->as_Bool();
Node *cmp = b->in(1);
if( cmp->is_FlagsProj() ) return NULL;
if( !cmp->is_Cmp() ) return NULL;
i1 = cmp->in(1);
if( i1 == NULL || !i1->is_Phi() ) return NULL;

View File

@ -520,13 +520,6 @@ Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray<int> &re
break;
}
// For nodes that produce a FlagsProj, make the node adjacent to the
// use of the FlagsProj
if (use->is_FlagsProj() && get_block_for_node(use) == block) {
found_machif = true;
break;
}
// More than this instruction pending for successor to be ready,
// don't choose this if other opportunities are ready
if (ready_cnt.at(use->_idx) > 1)

View File

@ -203,7 +203,9 @@ class LibraryCallKit : public GraphKit {
bool inline_math_native(vmIntrinsics::ID id);
bool inline_trig(vmIntrinsics::ID id);
bool inline_math(vmIntrinsics::ID id);
void inline_math_mathExact(Node* math);
template <typename OverflowOp>
bool inline_math_overflow(Node* arg1, Node* arg2);
void inline_math_mathExact(Node* math, Node* test);
bool inline_math_addExactI(bool is_increment);
bool inline_math_addExactL(bool is_increment);
bool inline_math_multiplyExactI();
@ -517,31 +519,31 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
case vmIntrinsics::_incrementExactI:
case vmIntrinsics::_addExactI:
if (!Matcher::match_rule_supported(Op_AddExactI) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowAddI) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_incrementExactL:
case vmIntrinsics::_addExactL:
if (!Matcher::match_rule_supported(Op_AddExactL) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowAddL) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_decrementExactI:
case vmIntrinsics::_subtractExactI:
if (!Matcher::match_rule_supported(Op_SubExactI) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowSubI) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_decrementExactL:
case vmIntrinsics::_subtractExactL:
if (!Matcher::match_rule_supported(Op_SubExactL) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowSubL) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_negateExactI:
if (!Matcher::match_rule_supported(Op_NegExactI) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowSubI) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_negateExactL:
if (!Matcher::match_rule_supported(Op_NegExactL) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowSubL) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_multiplyExactI:
if (!Matcher::match_rule_supported(Op_MulExactI) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowMulI) || !UseMathExactIntrinsics) return NULL;
break;
case vmIntrinsics::_multiplyExactL:
if (!Matcher::match_rule_supported(Op_MulExactL) || !UseMathExactIntrinsics) return NULL;
if (!Matcher::match_rule_supported(Op_OverflowMulL) || !UseMathExactIntrinsics) return NULL;
break;
default:
@ -1970,18 +1972,8 @@ bool LibraryCallKit::inline_min_max(vmIntrinsics::ID id) {
return true;
}
void LibraryCallKit::inline_math_mathExact(Node* math) {
// If we didn't get the expected opcode it means we have optimized
// the node to something else and don't need the exception edge.
if (!math->is_MathExact()) {
set_result(math);
return;
}
Node* result = _gvn.transform( new(C) ProjNode(math, MathExactNode::result_proj_node));
Node* flags = _gvn.transform( new(C) FlagsProjNode(math, MathExactNode::flags_proj_node));
Node* bol = _gvn.transform( new (C) BoolNode(flags, BoolTest::overflow) );
void LibraryCallKit::inline_math_mathExact(Node* math, Node *test) {
Node* bol = _gvn.transform( new (C) BoolNode(test, BoolTest::overflow) );
IfNode* check = create_and_map_if(control(), bol, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN);
Node* fast_path = _gvn.transform( new (C) IfFalseNode(check));
Node* slow_path = _gvn.transform( new (C) IfTrueNode(check) );
@ -1999,108 +1991,50 @@ void LibraryCallKit::inline_math_mathExact(Node* math) {
}
set_control(fast_path);
set_result(result);
set_result(math);
}
template <typename OverflowOp>
bool LibraryCallKit::inline_math_overflow(Node* arg1, Node* arg2) {
typedef typename OverflowOp::MathOp MathOp;
MathOp* mathOp = new(C) MathOp(arg1, arg2);
Node* operation = _gvn.transform( mathOp );
Node* ofcheck = _gvn.transform( new(C) OverflowOp(arg1, arg2) );
inline_math_mathExact(operation, ofcheck);
return true;
}
bool LibraryCallKit::inline_math_addExactI(bool is_increment) {
Node* arg1 = argument(0);
Node* arg2 = NULL;
if (is_increment) {
arg2 = intcon(1);
} else {
arg2 = argument(1);
}
Node* add = _gvn.transform( new(C) AddExactINode(NULL, arg1, arg2) );
inline_math_mathExact(add);
return true;
return inline_math_overflow<OverflowAddINode>(argument(0), is_increment ? intcon(1) : argument(1));
}
bool LibraryCallKit::inline_math_addExactL(bool is_increment) {
Node* arg1 = argument(0); // type long
// argument(1) == TOP
Node* arg2 = NULL;
if (is_increment) {
arg2 = longcon(1);
} else {
arg2 = argument(2); // type long
// argument(3) == TOP
}
Node* add = _gvn.transform(new(C) AddExactLNode(NULL, arg1, arg2));
inline_math_mathExact(add);
return true;
return inline_math_overflow<OverflowAddLNode>(argument(0), is_increment ? longcon(1) : argument(2));
}
bool LibraryCallKit::inline_math_subtractExactI(bool is_decrement) {
Node* arg1 = argument(0);
Node* arg2 = NULL;
if (is_decrement) {
arg2 = intcon(1);
} else {
arg2 = argument(1);
}
Node* sub = _gvn.transform(new(C) SubExactINode(NULL, arg1, arg2));
inline_math_mathExact(sub);
return true;
return inline_math_overflow<OverflowSubINode>(argument(0), is_decrement ? intcon(1) : argument(1));
}
bool LibraryCallKit::inline_math_subtractExactL(bool is_decrement) {
Node* arg1 = argument(0); // type long
// argument(1) == TOP
Node* arg2 = NULL;
if (is_decrement) {
arg2 = longcon(1);
} else {
arg2 = argument(2); // type long
// argument(3) == TOP
}
Node* sub = _gvn.transform(new(C) SubExactLNode(NULL, arg1, arg2));
inline_math_mathExact(sub);
return true;
return inline_math_overflow<OverflowSubLNode>(argument(0), is_decrement ? longcon(1) : argument(2));
}
bool LibraryCallKit::inline_math_negateExactI() {
Node* arg1 = argument(0);
Node* neg = _gvn.transform(new(C) NegExactINode(NULL, arg1));
inline_math_mathExact(neg);
return true;
return inline_math_overflow<OverflowSubINode>(intcon(0), argument(0));
}
bool LibraryCallKit::inline_math_negateExactL() {
Node* arg1 = argument(0);
// argument(1) == TOP
Node* neg = _gvn.transform(new(C) NegExactLNode(NULL, arg1));
inline_math_mathExact(neg);
return true;
return inline_math_overflow<OverflowSubLNode>(longcon(0), argument(0));
}
bool LibraryCallKit::inline_math_multiplyExactI() {
Node* arg1 = argument(0);
Node* arg2 = argument(1);
Node* mul = _gvn.transform(new(C) MulExactINode(NULL, arg1, arg2));
inline_math_mathExact(mul);
return true;
return inline_math_overflow<OverflowMulINode>(argument(0), argument(1));
}
bool LibraryCallKit::inline_math_multiplyExactL() {
Node* arg1 = argument(0);
// argument(1) == TOP
Node* arg2 = argument(2);
// argument(3) == TOP
Node* mul = _gvn.transform(new(C) MulExactLNode(NULL, arg1, arg2));
inline_math_mathExact(mul);
return true;
return inline_math_overflow<OverflowMulLNode>(argument(0), argument(2));
}
Node*

View File

@ -713,10 +713,6 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const {
case Op_ModL: body_size += 30; break;
case Op_DivL: body_size += 30; break;
case Op_MulL: body_size += 10; break;
case Op_FlagsProj:
// Can't handle unrolling of loops containing
// nodes that generate a FlagsProj at the moment
return false;
case Op_StrComp:
case Op_StrEquals:
case Op_StrIndexOf:
@ -780,10 +776,6 @@ bool IdealLoopTree::policy_range_check( PhaseIdealLoop *phase ) const {
continue; // not RC
Node *cmp = bol->in(1);
if (cmp->is_FlagsProj()) {
continue;
}
Node *rc_exp = cmp->in(1);
Node *limit = cmp->in(2);

View File

@ -43,12 +43,6 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) {
return NULL;
}
if (n->is_MathExact()) {
// MathExact has projections that are not correctly handled in the code
// below.
return NULL;
}
int wins = 0;
assert(!n->is_CFG(), "");
assert(region->is_Region(), "");
@ -2362,8 +2356,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
opc == Op_Catch ||
opc == Op_CatchProj ||
opc == Op_Jump ||
opc == Op_JumpProj ||
opc == Op_FlagsProj) {
opc == Op_JumpProj) {
#if !defined(PRODUCT)
if (TracePartialPeeling) {
tty->print_cr("\nExit control too complex: lp: %d", head->_idx);

View File

@ -520,12 +520,33 @@ public:
// Machine SpillCopy Node. Copies 1 or 2 words from any location to any
// location (stack or register).
class MachSpillCopyNode : public MachIdealNode {
public:
enum SpillType {
TwoAddress, // Inserted when coalescing of a two-address-instruction node and its input fails
PhiInput, // Inserted when coalescing of a phi node and its input fails
DebugUse, // Inserted as debug info spills to safepoints in non-frequent blocks
LoopPhiInput, // Pre-split compares of loop-phis
Definition, // An lrg marked as spilled will be spilled to memory right after its definition,
// if in high pressure region or the lrg is bound
RegToReg, // A register to register move
RegToMem, // A register to memory move
MemToReg, // A memory to register move
PhiLocationDifferToInputLocation, // When coalescing phi nodes in PhaseChaitin::Split(), a move spill is inserted if
// the phi and its input resides at different locations (i.e. reg or mem)
BasePointerToMem, // Spill base pointer to memory at safepoint
InputToRematerialization, // When rematerializing a node we stretch the inputs live ranges, and they might be
// stretched beyond a new definition point, therefore we split out new copies instead
CallUse, // Spill use at a call
Bound // An lrg marked as spill that is bound and needs to be spilled at a use
};
private:
const RegMask *_in; // RegMask for input
const RegMask *_out; // RegMask for output
const Type *_type;
const SpillType _spill_type;
public:
MachSpillCopyNode( Node *n, const RegMask &in, const RegMask &out ) :
MachIdealNode(), _in(&in), _out(&out), _type(n->bottom_type()) {
MachSpillCopyNode(SpillType spill_type, Node *n, const RegMask &in, const RegMask &out ) :
MachIdealNode(), _spill_type(spill_type), _in(&in), _out(&out), _type(n->bottom_type()) {
init_class_id(Class_MachSpillCopy);
init_flags(Flag_is_Copy);
add_req(NULL);
@ -544,8 +565,42 @@ public:
virtual void emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const;
virtual uint size(PhaseRegAlloc *ra_) const;
#ifndef PRODUCT
virtual const char *Name() const { return "MachSpillCopy"; }
virtual const char *Name() const {
switch (_spill_type) {
case TwoAddress:
return "TwoAddressSpillCopy";
case PhiInput:
return "PhiInputSpillCopy";
case DebugUse:
return "DebugUseSpillCopy";
case LoopPhiInput:
return "LoopPhiInputSpillCopy";
case Definition:
return "DefinitionSpillCopy";
case RegToReg:
return "RegToRegSpillCopy";
case RegToMem:
return "RegToMemSpillCopy";
case MemToReg:
return "MemToRegSpillCopy";
case PhiLocationDifferToInputLocation:
return "PhiLocationDifferToInputLocationSpillCopy";
case BasePointerToMem:
return "BasePointerToMemSpillCopy";
case InputToRematerialization:
return "InputToRematerializationSpillCopy";
case CallUse:
return "CallUseSpillCopy";
case Bound:
return "BoundSpillCopy";
default:
assert(false, "Must have valid spill type");
return "MachSpillCopy";
}
}
virtual void format( PhaseRegAlloc *, outputStream *st ) const;
#endif
};

View File

@ -1998,7 +1998,6 @@ void Matcher::find_shared( Node *n ) {
case Op_Catch:
case Op_CatchProj:
case Op_CProj:
case Op_FlagsProj:
case Op_JumpProj:
case Op_JProj:
case Op_NeverBranch:

View File

@ -340,10 +340,6 @@ public:
// Register for MODL projection of divmodL
static RegMask modL_proj_mask();
static const RegMask mathExactI_result_proj_mask();
static const RegMask mathExactL_result_proj_mask();
static const RegMask mathExactI_flags_proj_mask();
// Use hardware DIV instruction when it is faster than
// a code which use multiply for division by constant.
static bool use_asm_for_ldiv_by_con( jlong divisor );

View File

@ -31,358 +31,93 @@
#include "opto/mathexactnode.hpp"
#include "opto/subnode.hpp"
MathExactNode::MathExactNode(Node* ctrl, Node* in1) : MultiNode(2) {
init_class_id(Class_MathExact);
init_req(0, ctrl);
init_req(1, in1);
}
template <typename OverflowOp>
class AddHelper {
public:
typedef typename OverflowOp::TypeClass TypeClass;
typedef typename TypeClass::NativeType NativeType;
MathExactNode::MathExactNode(Node* ctrl, Node* in1, Node* in2) : MultiNode(3) {
init_class_id(Class_MathExact);
init_req(0, ctrl);
init_req(1, in1);
init_req(2, in2);
}
BoolNode* MathExactNode::bool_node() const {
Node* flags = flags_node();
BoolNode* boolnode = flags->unique_out()->as_Bool();
assert(boolnode != NULL, "must have BoolNode");
return boolnode;
}
IfNode* MathExactNode::if_node() const {
BoolNode* boolnode = bool_node();
IfNode* ifnode = boolnode->unique_out()->as_If();
assert(ifnode != NULL, "must have IfNode");
return ifnode;
}
Node* MathExactNode::control_node() const {
IfNode* ifnode = if_node();
return ifnode->in(0);
}
Node* MathExactNode::non_throwing_branch() const {
IfNode* ifnode = if_node();
if (bool_node()->_test._test == BoolTest::overflow) {
return ifnode->proj_out(0);
}
return ifnode->proj_out(1);
}
// If the MathExactNode won't overflow we have to replace the
// FlagsProjNode and ProjNode that is generated by the MathExactNode
Node* MathExactNode::no_overflow(PhaseGVN* phase, Node* new_result) {
PhaseIterGVN* igvn = phase->is_IterGVN();
if (igvn) {
ProjNode* result = result_node();
ProjNode* flags = flags_node();
if (result != NULL) {
igvn->replace_node(result, new_result);
}
if (flags != NULL) {
BoolNode* boolnode = bool_node();
switch (boolnode->_test._test) {
case BoolTest::overflow:
// if the check is for overflow - never taken
igvn->replace_node(boolnode, phase->intcon(0));
break;
case BoolTest::no_overflow:
// if the check is for no overflow - always taken
igvn->replace_node(boolnode, phase->intcon(1));
break;
default:
fatal("Unexpected value of BoolTest");
break;
}
flags->del_req(0);
}
}
return new_result;
}
Node* MathExactINode::match(const ProjNode* proj, const Matcher* m) {
uint ideal_reg = proj->ideal_reg();
RegMask rm;
if (proj->_con == result_proj_node) {
rm = m->mathExactI_result_proj_mask();
} else {
assert(proj->_con == flags_proj_node, "must be result or flags");
assert(ideal_reg == Op_RegFlags, "sanity");
rm = m->mathExactI_flags_proj_mask();
}
return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg);
}
Node* MathExactLNode::match(const ProjNode* proj, const Matcher* m) {
uint ideal_reg = proj->ideal_reg();
RegMask rm;
if (proj->_con == result_proj_node) {
rm = m->mathExactL_result_proj_mask();
} else {
assert(proj->_con == flags_proj_node, "must be result or flags");
assert(ideal_reg == Op_RegFlags, "sanity");
rm = m->mathExactI_flags_proj_mask();
}
return new (m->C) MachProjNode(this, proj->_con, rm, ideal_reg);
}
Node* AddExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* arg1 = in(1);
Node* arg2 = in(2);
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
jint val1 = arg1->get_int();
jint val2 = arg2->get_int();
jint result = val1 + val2;
static bool will_overflow(NativeType value1, NativeType value2) {
NativeType result = value1 + value2;
// Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result
if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) {
Node* con_result = ConINode::make(phase->C, result);
return no_overflow(phase, con_result);
if (((value1 ^ result) & (value2 ^ result)) >= 0) {
return false;
}
return NULL;
return true;
}
if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) { // (Add 0 x) == x
Node* add_result = new (phase->C) AddINode(arg1, arg2);
return no_overflow(phase, add_result);
}
if (type2->singleton()) {
return NULL; // no change - keep constant on the right
}
if (type1->singleton()) {
// Make it x + Constant - move constant to the right
swap_edges(1, 2);
return this;
}
if (arg2->is_Load()) {
return NULL; // no change - keep load on the right
}
if (arg1->is_Load()) {
// Make it x + Load - move load to the right
swap_edges(1, 2);
return this;
}
if (arg1->_idx > arg2->_idx) {
// Sort the edges
swap_edges(1, 2);
return this;
}
return NULL;
}
Node* AddExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* arg1 = in(1);
Node* arg2 = in(2);
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
jlong val1 = arg1->get_long();
jlong val2 = arg2->get_long();
jlong result = val1 + val2;
// Hacker's Delight 2-12 Overflow if both arguments have the opposite sign of the result
if ( (((val1 ^ result) & (val2 ^ result)) >= 0)) {
Node* con_result = ConLNode::make(phase->C, result);
return no_overflow(phase, con_result);
static bool can_overflow(const Type* type1, const Type* type2) {
if (type1 == TypeClass::ZERO || type2 == TypeClass::ZERO) {
return false;
}
return NULL;
return true;
}
};
if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) { // (Add 0 x) == x
Node* add_result = new (phase->C) AddLNode(arg1, arg2);
return no_overflow(phase, add_result);
}
template <typename OverflowOp>
class SubHelper {
public:
typedef typename OverflowOp::TypeClass TypeClass;
typedef typename TypeClass::NativeType NativeType;
if (type2->singleton()) {
return NULL; // no change - keep constant on the right
}
if (type1->singleton()) {
// Make it x + Constant - move constant to the right
swap_edges(1, 2);
return this;
}
if (arg2->is_Load()) {
return NULL; // no change - keep load on the right
}
if (arg1->is_Load()) {
// Make it x + Load - move load to the right
swap_edges(1, 2);
return this;
}
if (arg1->_idx > arg2->_idx) {
// Sort the edges
swap_edges(1, 2);
return this;
}
return NULL;
}
Node* SubExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* arg1 = in(1);
Node* arg2 = in(2);
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
jint val1 = arg1->get_int();
jint val2 = arg2->get_int();
jint result = val1 - val2;
// Hacker's Delight 2-12 Overflow iff the arguments have different signs and
static bool will_overflow(NativeType value1, NativeType value2) {
NativeType result = value1 - value2;
// hacker's delight 2-12 overflow iff the arguments have different signs and
// the sign of the result is different than the sign of arg1
if (((val1 ^ val2) & (val1 ^ result)) >= 0) {
Node* con_result = ConINode::make(phase->C, result);
return no_overflow(phase, con_result);
if (((value1 ^ value2) & (value1 ^ result)) >= 0) {
return false;
}
return NULL;
return true;
}
if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) {
// Sub with zero is the same as add with zero
Node* add_result = new (phase->C) AddINode(arg1, arg2);
return no_overflow(phase, add_result);
static bool can_overflow(const Type* type1, const Type* type2) {
if (type2 == TypeClass::ZERO) {
return false;
}
return true;
}
};
return NULL;
template <typename OverflowOp>
class MulHelper {
public:
typedef typename OverflowOp::TypeClass TypeClass;
static bool can_overflow(const Type* type1, const Type* type2) {
if (type1 == TypeClass::ZERO || type2 == TypeClass::ZERO) {
return false;
} else if (type1 == TypeClass::ONE || type2 == TypeClass::ONE) {
return false;
}
return true;
}
};
bool OverflowAddINode::will_overflow(jint v1, jint v2) const {
return AddHelper<OverflowAddINode>::will_overflow(v1, v2);
}
Node* SubExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* arg1 = in(1);
Node* arg2 = in(2);
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
jlong val1 = arg1->get_long();
jlong val2 = arg2->get_long();
jlong result = val1 - val2;
// Hacker's Delight 2-12 Overflow iff the arguments have different signs and
// the sign of the result is different than the sign of arg1
if (((val1 ^ val2) & (val1 ^ result)) >= 0) {
Node* con_result = ConLNode::make(phase->C, result);
return no_overflow(phase, con_result);
}
return NULL;
}
if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) {
// Sub with zero is the same as add with zero
Node* add_result = new (phase->C) AddLNode(arg1, arg2);
return no_overflow(phase, add_result);
}
return NULL;
bool OverflowSubINode::will_overflow(jint v1, jint v2) const {
return SubHelper<OverflowSubINode>::will_overflow(v1, v2);
}
Node* NegExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node *arg = in(1);
const Type* type = phase->type(arg);
if (type != Type::TOP && type->singleton()) {
jint value = arg->get_int();
if (value != min_jint) {
Node* neg_result = ConINode::make(phase->C, -value);
return no_overflow(phase, neg_result);
}
}
return NULL;
}
Node* NegExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node *arg = in(1);
const Type* type = phase->type(arg);
if (type != Type::TOP && type->singleton()) {
jlong value = arg->get_long();
if (value != min_jlong) {
Node* neg_result = ConLNode::make(phase->C, -value);
return no_overflow(phase, neg_result);
}
}
return NULL;
}
Node* MulExactINode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* arg1 = in(1);
Node* arg2 = in(2);
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
jint val1 = arg1->get_int();
jint val2 = arg2->get_int();
jlong result = (jlong) val1 * (jlong) val2;
bool OverflowMulINode::will_overflow(jint v1, jint v2) const {
jlong result = (jlong) v1 * (jlong) v2;
if ((jint) result == result) {
// no overflow
Node* mul_result = ConINode::make(phase->C, result);
return no_overflow(phase, mul_result);
return false;
}
}
if (type1 == TypeInt::ZERO || type2 == TypeInt::ZERO) {
return no_overflow(phase, ConINode::make(phase->C, 0));
}
if (type1 == TypeInt::ONE) {
Node* mul_result = new (phase->C) AddINode(arg2, phase->intcon(0));
return no_overflow(phase, mul_result);
}
if (type2 == TypeInt::ONE) {
Node* mul_result = new (phase->C) AddINode(arg1, phase->intcon(0));
return no_overflow(phase, mul_result);
}
if (type1 == TypeInt::MINUS_1) {
return new (phase->C) NegExactINode(NULL, arg2);
}
if (type2 == TypeInt::MINUS_1) {
return new (phase->C) NegExactINode(NULL, arg1);
}
return NULL;
return true;
}
Node* MulExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* arg1 = in(1);
Node* arg2 = in(2);
bool OverflowAddLNode::will_overflow(jlong v1, jlong v2) const {
return AddHelper<OverflowAddLNode>::will_overflow(v1, v2);
}
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
jlong val1 = arg1->get_long();
jlong val2 = arg2->get_long();
bool OverflowSubLNode::will_overflow(jlong v1, jlong v2) const {
return SubHelper<OverflowSubLNode>::will_overflow(v1, v2);
}
bool OverflowMulLNode::will_overflow(jlong val1, jlong val2) const {
jlong result = val1 * val2;
jlong ax = (val1 < 0 ? -val1 : val1);
jlong ay = (val2 < 0 ? -val2 : val2);
@ -398,33 +133,125 @@ Node* MulExactLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
}
}
if (!overflow) {
Node* mul_result = ConLNode::make(phase->C, result);
return no_overflow(phase, mul_result);
}
}
if (type1 == TypeLong::ZERO || type2 == TypeLong::ZERO) {
return no_overflow(phase, ConLNode::make(phase->C, 0));
}
if (type1 == TypeLong::ONE) {
Node* mul_result = new (phase->C) AddLNode(arg2, phase->longcon(0));
return no_overflow(phase, mul_result);
}
if (type2 == TypeLong::ONE) {
Node* mul_result = new (phase->C) AddLNode(arg1, phase->longcon(0));
return no_overflow(phase, mul_result);
}
if (type1 == TypeLong::MINUS_1) {
return new (phase->C) NegExactLNode(NULL, arg2);
}
if (type2 == TypeLong::MINUS_1) {
return new (phase->C) NegExactLNode(NULL, arg1);
}
return NULL;
return overflow;
}
bool OverflowAddINode::can_overflow(const Type* t1, const Type* t2) const {
return AddHelper<OverflowAddINode>::can_overflow(t1, t2);
}
bool OverflowSubINode::can_overflow(const Type* t1, const Type* t2) const {
if (in(1) == in(2)) {
return false;
}
return SubHelper<OverflowSubINode>::can_overflow(t1, t2);
}
bool OverflowMulINode::can_overflow(const Type* t1, const Type* t2) const {
return MulHelper<OverflowMulINode>::can_overflow(t1, t2);
}
bool OverflowAddLNode::can_overflow(const Type* t1, const Type* t2) const {
return AddHelper<OverflowAddLNode>::can_overflow(t1, t2);
}
bool OverflowSubLNode::can_overflow(const Type* t1, const Type* t2) const {
if (in(1) == in(2)) {
return false;
}
return SubHelper<OverflowSubLNode>::can_overflow(t1, t2);
}
bool OverflowMulLNode::can_overflow(const Type* t1, const Type* t2) const {
return MulHelper<OverflowMulLNode>::can_overflow(t1, t2);
}
const Type* OverflowNode::sub(const Type* t1, const Type* t2) const {
fatal(err_msg_res("sub() should not be called for '%s'", NodeClassNames[this->Opcode()]));
return TypeInt::CC;
}
template <typename OverflowOp>
struct IdealHelper {
typedef typename OverflowOp::TypeClass TypeClass; // TypeInt, TypeLong
typedef typename TypeClass::NativeType NativeType;
static Node* Ideal(const OverflowOp* node, PhaseGVN* phase, bool can_reshape) {
Node* arg1 = node->in(1);
Node* arg2 = node->in(2);
const Type* type1 = phase->type(arg1);
const Type* type2 = phase->type(arg2);
if (type1 == NULL || type2 == NULL) {
return NULL;
}
if (type1 != Type::TOP && type1->singleton() &&
type2 != Type::TOP && type2->singleton()) {
NativeType val1 = TypeClass::as_self(type1)->get_con();
NativeType val2 = TypeClass::as_self(type2)->get_con();
if (node->will_overflow(val1, val2) == false) {
Node* con_result = ConINode::make(phase->C, 0);
return con_result;
}
return NULL;
}
return NULL;
}
static const Type* Value(const OverflowOp* node, PhaseTransform* phase) {
const Type *t1 = phase->type( node->in(1) );
const Type *t2 = phase->type( node->in(2) );
if( t1 == Type::TOP ) return Type::TOP;
if( t2 == Type::TOP ) return Type::TOP;
const TypeClass* i1 = TypeClass::as_self(t1);
const TypeClass* i2 = TypeClass::as_self(t2);
if (i1 == NULL || i2 == NULL) {
return TypeInt::CC;
}
if (t1->singleton() && t2->singleton()) {
NativeType val1 = i1->get_con();
NativeType val2 = i2->get_con();
if (node->will_overflow(val1, val2)) {
return TypeInt::CC;
}
return TypeInt::ZERO;
} else if (i1 != TypeClass::TYPE_DOMAIN && i2 != TypeClass::TYPE_DOMAIN) {
if (node->will_overflow(i1->_lo, i2->_lo)) {
return TypeInt::CC;
} else if (node->will_overflow(i1->_lo, i2->_hi)) {
return TypeInt::CC;
} else if (node->will_overflow(i1->_hi, i2->_lo)) {
return TypeInt::CC;
} else if (node->will_overflow(i1->_hi, i2->_hi)) {
return TypeInt::CC;
}
return TypeInt::ZERO;
}
if (!node->can_overflow(t1, t2)) {
return TypeInt::ZERO;
}
return TypeInt::CC;
}
};
Node* OverflowINode::Ideal(PhaseGVN* phase, bool can_reshape) {
return IdealHelper<OverflowINode>::Ideal(this, phase, can_reshape);
}
Node* OverflowLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
return IdealHelper<OverflowLNode>::Ideal(this, phase, can_reshape);
}
const Type* OverflowINode::Value(PhaseTransform* phase) const {
return IdealHelper<OverflowINode>::Value(this, phase);
}
const Type* OverflowLNode::Value(PhaseTransform* phase) const {
return IdealHelper<OverflowLNode>::Value(this, phase);
}

View File

@ -27,128 +27,111 @@
#include "opto/multnode.hpp"
#include "opto/node.hpp"
#include "opto/addnode.hpp"
#include "opto/subnode.hpp"
#include "opto/type.hpp"
class BoolNode;
class IfNode;
class Node;
class PhaseGVN;
class PhaseTransform;
class MathExactNode : public MultiNode {
class OverflowNode : public CmpNode {
public:
MathExactNode(Node* ctrl, Node* in1);
MathExactNode(Node* ctrl, Node* in1, Node* in2);
enum {
result_proj_node = 0,
flags_proj_node = 1
};
virtual int Opcode() const;
virtual Node* Identity(PhaseTransform* phase) { return this; }
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape) { return NULL; }
virtual const Type* Value(PhaseTransform* phase) const { return bottom_type(); }
virtual uint hash() const { return NO_HASH; }
virtual bool is_CFG() const { return false; }
virtual uint ideal_reg() const { return NotAMachineReg; }
OverflowNode(Node* in1, Node* in2) : CmpNode(in1, in2) {}
ProjNode* result_node() const { return proj_out(result_proj_node); }
ProjNode* flags_node() const { return proj_out(flags_proj_node); }
Node* control_node() const;
Node* non_throwing_branch() const;
protected:
IfNode* if_node() const;
BoolNode* bool_node() const;
Node* no_overflow(PhaseGVN *phase, Node* new_result);
};
class MathExactINode : public MathExactNode {
public:
MathExactINode(Node* ctrl, Node* in1) : MathExactNode(ctrl, in1) {}
MathExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* match(const ProjNode* proj, const Matcher* m);
virtual const Type* bottom_type() const { return TypeTuple::INT_CC_PAIR; }
};
class MathExactLNode : public MathExactNode {
public:
MathExactLNode(Node* ctrl, Node* in1) : MathExactNode(ctrl, in1) {}
MathExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactNode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* match(const ProjNode* proj, const Matcher* m);
virtual const Type* bottom_type() const { return TypeTuple::LONG_CC_PAIR; }
};
class AddExactINode : public MathExactINode {
public:
AddExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
};
class AddExactLNode : public MathExactLNode {
public:
AddExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class SubExactINode : public MathExactINode {
public:
SubExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class SubExactLNode : public MathExactLNode {
public:
SubExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class NegExactINode : public MathExactINode {
public:
NegExactINode(Node* ctrl, Node* in1) : MathExactINode(ctrl, in1) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class NegExactLNode : public MathExactLNode {
public:
NegExactLNode(Node* ctrl, Node* in1) : MathExactLNode(ctrl, in1) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class MulExactINode : public MathExactINode {
public:
MulExactINode(Node* ctrl, Node* in1, Node* in2) : MathExactINode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class MulExactLNode : public MathExactLNode {
public:
MulExactLNode(Node* ctrl, Node* in1, Node* in2) : MathExactLNode(ctrl, in1, in2) {}
virtual int Opcode() const;
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
};
class FlagsProjNode : public ProjNode {
public:
FlagsProjNode(Node* src, uint con) : ProjNode(src, con) {
init_class_id(Class_FlagsProj);
}
virtual int Opcode() const;
virtual bool is_CFG() const { return false; }
virtual const Type* bottom_type() const { return TypeInt::CC; }
virtual uint ideal_reg() const { return Op_RegFlags; }
virtual const Type* sub(const Type* t1, const Type* t2) const;
};
class OverflowINode : public OverflowNode {
public:
typedef TypeInt TypeClass;
OverflowINode(Node* in1, Node* in2) : OverflowNode(in1, in2) {}
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
virtual const Type* Value(PhaseTransform* phase) const;
virtual bool will_overflow(jint v1, jint v2) const = 0;
virtual bool can_overflow(const Type* t1, const Type* t2) const = 0;
};
class OverflowLNode : public OverflowNode {
public:
typedef TypeLong TypeClass;
OverflowLNode(Node* in1, Node* in2) : OverflowNode(in1, in2) {}
virtual Node* Ideal(PhaseGVN* phase, bool can_reshape);
virtual const Type* Value(PhaseTransform* phase) const;
virtual bool will_overflow(jlong v1, jlong v2) const = 0;
virtual bool can_overflow(const Type* t1, const Type* t2) const = 0;
};
class OverflowAddINode : public OverflowINode {
public:
typedef AddINode MathOp;
OverflowAddINode(Node* in1, Node* in2) : OverflowINode(in1, in2) {}
virtual int Opcode() const;
virtual bool will_overflow(jint v1, jint v2) const;
virtual bool can_overflow(const Type* t1, const Type* t2) const;
};
class OverflowSubINode : public OverflowINode {
public:
typedef SubINode MathOp;
OverflowSubINode(Node* in1, Node* in2) : OverflowINode(in1, in2) {}
virtual int Opcode() const;
virtual bool will_overflow(jint v1, jint v2) const;
virtual bool can_overflow(const Type* t1, const Type* t2) const;
};
class OverflowMulINode : public OverflowINode {
public:
typedef MulINode MathOp;
OverflowMulINode(Node* in1, Node* in2) : OverflowINode(in1, in2) {}
virtual int Opcode() const;
virtual bool will_overflow(jint v1, jint v2) const;
virtual bool can_overflow(const Type* t1, const Type* t2) const;
};
class OverflowAddLNode : public OverflowLNode {
public:
typedef AddLNode MathOp;
OverflowAddLNode(Node* in1, Node* in2) : OverflowLNode(in1, in2) {}
virtual int Opcode() const;
virtual bool will_overflow(jlong v1, jlong v2) const;
virtual bool can_overflow(const Type* t1, const Type* t2) const;
};
class OverflowSubLNode : public OverflowLNode {
public:
typedef SubLNode MathOp;
OverflowSubLNode(Node* in1, Node* in2) : OverflowLNode(in1, in2) {}
virtual int Opcode() const;
virtual bool will_overflow(jlong v1, jlong v2) const;
virtual bool can_overflow(const Type* t1, const Type* t2) const;
};
class OverflowMulLNode : public OverflowLNode {
public:
typedef MulLNode MathOp;
OverflowMulLNode(Node* in1, Node* in2) : OverflowLNode(in1, in2) {}
virtual int Opcode() const;
virtual bool will_overflow(jlong v1, jlong v2) const;
virtual bool can_overflow(const Type* t1, const Type* t2) const;
};
#endif

View File

@ -54,11 +54,6 @@ ProjNode* MultiNode::proj_out(uint which_proj) const {
assert(Opcode() != Op_If || proj->Opcode() == (which_proj?Op_IfTrue:Op_IfFalse), "bad if #2");
return proj;
}
} else if (p->is_FlagsProj()) {
FlagsProjNode *proj = p->as_FlagsProj();
if (proj->_con == which_proj) {
return proj;
}
} else {
assert(p == this && this->is_Start(), "else must be proj");
continue;

View File

@ -69,7 +69,6 @@ class EncodePNode;
class EncodePKlassNode;
class FastLockNode;
class FastUnlockNode;
class FlagsProjNode;
class IfNode;
class IfFalseNode;
class IfTrueNode;
@ -100,7 +99,6 @@ class MachSafePointNode;
class MachSpillCopyNode;
class MachTempNode;
class Matcher;
class MathExactNode;
class MemBarNode;
class MemBarStoreStoreNode;
class MemNode;
@ -575,7 +573,6 @@ public:
DEFINE_CLASS_ID(MemBar, Multi, 3)
DEFINE_CLASS_ID(Initialize, MemBar, 0)
DEFINE_CLASS_ID(MemBarStoreStore, MemBar, 1)
DEFINE_CLASS_ID(MathExact, Multi, 4)
DEFINE_CLASS_ID(Mach, Node, 1)
DEFINE_CLASS_ID(MachReturn, Mach, 0)
@ -632,7 +629,6 @@ public:
DEFINE_CLASS_ID(Cmp, Sub, 0)
DEFINE_CLASS_ID(FastLock, Cmp, 0)
DEFINE_CLASS_ID(FastUnlock, Cmp, 1)
DEFINE_CLASS_ID(FlagsProj, Cmp, 2)
DEFINE_CLASS_ID(MergeMem, Node, 7)
DEFINE_CLASS_ID(Bool, Node, 8)
@ -736,7 +732,6 @@ public:
DEFINE_CLASS_QUERY(EncodePKlass)
DEFINE_CLASS_QUERY(FastLock)
DEFINE_CLASS_QUERY(FastUnlock)
DEFINE_CLASS_QUERY(FlagsProj)
DEFINE_CLASS_QUERY(If)
DEFINE_CLASS_QUERY(IfFalse)
DEFINE_CLASS_QUERY(IfTrue)
@ -765,7 +760,6 @@ public:
DEFINE_CLASS_QUERY(MachSafePoint)
DEFINE_CLASS_QUERY(MachSpillCopy)
DEFINE_CLASS_QUERY(MachTemp)
DEFINE_CLASS_QUERY(MathExact)
DEFINE_CLASS_QUERY(Mem)
DEFINE_CLASS_QUERY(MemBar)
DEFINE_CLASS_QUERY(MemBarStoreStore)

View File

@ -344,6 +344,11 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
uint* jmp_offset = NEW_RESOURCE_ARRAY(uint,nblocks);
uint* jmp_size = NEW_RESOURCE_ARRAY(uint,nblocks);
int* jmp_nidx = NEW_RESOURCE_ARRAY(int ,nblocks);
// Collect worst case block paddings
int* block_worst_case_pad = NEW_RESOURCE_ARRAY(int, nblocks);
memset(block_worst_case_pad, 0, nblocks * sizeof(int));
DEBUG_ONLY( uint *jmp_target = NEW_RESOURCE_ARRAY(uint,nblocks); )
DEBUG_ONLY( uint *jmp_rule = NEW_RESOURCE_ARRAY(uint,nblocks); )
@ -460,6 +465,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
last_avoid_back_to_back_adr += max_loop_pad;
}
blk_size += max_loop_pad;
block_worst_case_pad[i + 1] = max_loop_pad;
}
}
@ -499,9 +505,16 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
if (bnum > i) { // adjust following block's offset
offset -= adjust_block_start;
}
// This block can be a loop header, account for the padding
// in the previous block.
int block_padding = block_worst_case_pad[i];
assert(i == 0 || block_padding == 0 || br_offs >= block_padding, "Should have at least a padding on top");
// In the following code a nop could be inserted before
// the branch which will increase the backward distance.
bool needs_padding = ((uint)br_offs == last_may_be_short_branch_adr);
bool needs_padding = ((uint)(br_offs - block_padding) == last_may_be_short_branch_adr);
assert(!needs_padding || jmp_offset[i] == 0, "padding only branches at the beginning of block");
if (needs_padding && offset <= 0)
offset -= nop_size;

View File

@ -55,7 +55,7 @@ static const char out_of_nodes[] = "out of nodes during split";
// Get a SpillCopy node with wide-enough masks. Use the 'wide-mask', the
// wide ideal-register spill-mask if possible. If the 'wide-mask' does
// not cover the input (or output), use the input (or output) mask instead.
Node *PhaseChaitin::get_spillcopy_wide( Node *def, Node *use, uint uidx ) {
Node *PhaseChaitin::get_spillcopy_wide(MachSpillCopyNode::SpillType spill_type, Node *def, Node *use, uint uidx ) {
// If ideal reg doesn't exist we've got a bad schedule happening
// that is forcing us to spill something that isn't spillable.
// Bail rather than abort
@ -93,7 +93,7 @@ Node *PhaseChaitin::get_spillcopy_wide( Node *def, Node *use, uint uidx ) {
// Here we assume a trip through memory is required.
w_i_mask = &C->FIRST_STACK_mask();
}
return new (C) MachSpillCopyNode( def, *w_i_mask, *w_o_mask );
return new (C) MachSpillCopyNode(spill_type, def, *w_i_mask, *w_o_mask );
}
//------------------------------insert_proj------------------------------------
@ -159,7 +159,7 @@ uint PhaseChaitin::split_DEF( Node *def, Block *b, int loc, uint maxlrg, Node **
assert( loc >= 0, "must insert past block head" );
// Get a def-side SpillCopy
Node *spill = get_spillcopy_wide(def,NULL,0);
Node *spill = get_spillcopy_wide(MachSpillCopyNode::Definition, def, NULL, 0);
// Did we fail to split?, then bail
if (!spill) {
return 0;
@ -180,7 +180,7 @@ uint PhaseChaitin::split_DEF( Node *def, Block *b, int loc, uint maxlrg, Node **
//------------------------------split_USE--------------------------------------
// Splits at uses can involve redeffing the LRG, so no CISC Spilling there.
// Debug uses want to know if def is already stack enabled.
uint PhaseChaitin::split_USE( Node *def, Block *b, Node *use, uint useidx, uint maxlrg, bool def_down, bool cisc_sp, GrowableArray<uint> splits, int slidx ) {
uint PhaseChaitin::split_USE(MachSpillCopyNode::SpillType spill_type, Node *def, Block *b, Node *use, uint useidx, uint maxlrg, bool def_down, bool cisc_sp, GrowableArray<uint> splits, int slidx ) {
#ifdef ASSERT
// Increment the counter for this lrg
splits.at_put(slidx, splits.at(slidx)+1);
@ -216,7 +216,7 @@ uint PhaseChaitin::split_USE( Node *def, Block *b, Node *use, uint useidx, uint
// DEF is UP, so must copy it DOWN and hook in USE
// Insert SpillCopy before the USE, which uses DEF as its input,
// and defs a new live range, which is used by this node.
Node *spill = get_spillcopy_wide(def,use,useidx);
Node *spill = get_spillcopy_wide(spill_type, def,use,useidx);
// did we fail to split?
if (!spill) {
// Bail
@ -268,7 +268,7 @@ uint PhaseChaitin::split_USE( Node *def, Block *b, Node *use, uint useidx, uint
bindex = b->find_node(use);
}
Node *spill = get_spillcopy_wide( def, use, useidx );
Node *spill = get_spillcopy_wide(spill_type, def, use, useidx );
if( !spill ) return 0; // Bailed out
// Insert SpillCopy before the USE, which uses the reaching DEF as
// its input, and defs a new live range, which is used by this node.
@ -327,7 +327,7 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint
Block *b_def = _cfg.get_block_for_node(def);
int idx_def = b_def->find_node(def);
Node *in_spill = get_spillcopy_wide( in, def, i );
Node *in_spill = get_spillcopy_wide(MachSpillCopyNode::InputToRematerialization, in, def, i );
if( !in_spill ) return 0; // Bailed out
insert_proj(b_def,idx_def,in_spill,maxlrg++);
if( b_def == b )
@ -935,7 +935,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
// This def has been rematerialized a couple of times without
// progress. It doesn't care if it lives UP or DOWN, so
// spill it down now.
maxlrg = split_USE(def,b,n,inpidx,maxlrg,false,false,splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::BasePointerToMem, def,b,n,inpidx,maxlrg,false,false,splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1015,7 +1015,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
!is_vect && umask.is_misaligned_pair())) {
// These need a Split regardless of overlap or pressure
// SPLIT - NO DEF - NO CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::Bound, def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1027,7 +1027,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
if (UseFPUForSpilling && n->is_MachCall() && !uup && !dup ) {
// The use at the call can force the def down so insert
// a split before the use to allow the def more freedom.
maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::CallUse, def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1063,7 +1063,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
else { // Both are either up or down, and there is no overlap
if( dup ) { // If UP, reg->reg copy
// COPY ACROSS HERE - NO DEF - NO CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,false,false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::RegToReg, def,b,n,inpidx,maxlrg,false,false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1075,10 +1075,10 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
// First Split-UP to move value into Register
uint def_ideal = def->ideal_reg();
const RegMask* tmp_rm = Matcher::idealreg2regmask[def_ideal];
Node *spill = new (C) MachSpillCopyNode(def, dmask, *tmp_rm);
Node *spill = new (C) MachSpillCopyNode(MachSpillCopyNode::MemToReg, def, dmask, *tmp_rm);
insert_proj( b, insidx, spill, maxlrg );
// Then Split-DOWN as if previous Split was DEF
maxlrg = split_USE(spill,b,n,inpidx,maxlrg,false,false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::RegToMem, spill,b,n,inpidx,maxlrg,false,false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1103,7 +1103,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
}
}
// COPY DOWN HERE - NO DEF - NO CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,false,false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::RegToMem, def,b,n,inpidx,maxlrg,false,false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1118,7 +1118,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
else { // DOWN, Split-UP and check register pressure
if( is_high_pressure( b, &lrgs(useidx), insidx ) ) {
// COPY UP HERE - NO DEF - CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,true,true, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::MemToReg, def,b,n,inpidx,maxlrg,true,true, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1126,7 +1126,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
insidx++; // Reset iterator to skip USE side split
} else { // LRP
// COPY UP HERE - WITH DEF - NO CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,true,false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::MemToReg, def,b,n,inpidx,maxlrg,true,false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
@ -1229,7 +1229,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
if (C->check_node_count(NodeLimitFudgeFactor, out_of_nodes)) { // Check when generating nodes
return 0;
}
Node *spill = new (C) MachSpillCopyNode(use,use_rm,def_rm);
Node *spill = new (C) MachSpillCopyNode(MachSpillCopyNode::MemToReg, use,use_rm,def_rm);
n->set_req(copyidx,spill);
n->as_MachSpillCopy()->set_in_RegMask(def_rm);
// Put the spill just before the copy
@ -1336,7 +1336,7 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) {
// Grab the UP/DOWN sense for the input
u1 = UP[pidx][slidx];
if( u1 != (phi_up != 0)) {
maxlrg = split_USE(def, b, phi, i, maxlrg, !u1, false, splits,slidx);
maxlrg = split_USE(MachSpillCopyNode::PhiLocationDifferToInputLocation, def, b, phi, i, maxlrg, !u1, false, splits,slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;

View File

@ -1126,11 +1126,15 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) {
Node *cmp = in(1);
if( !cmp->is_Sub() ) return NULL;
int cop = cmp->Opcode();
if( cop == Op_FastLock || cop == Op_FastUnlock || cop == Op_FlagsProj) return NULL;
if( cop == Op_FastLock || cop == Op_FastUnlock) return NULL;
Node *cmp1 = cmp->in(1);
Node *cmp2 = cmp->in(2);
if( !cmp1 ) return NULL;
if (_test._test == BoolTest::overflow || _test._test == BoolTest::no_overflow) {
return NULL;
}
// Constant on left?
Node *con = cmp1;
uint op2 = cmp2->Opcode();

View File

@ -441,6 +441,7 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
return true; // no induction variable
}
CountedLoopEndNode* pre_end = get_pre_loop_end(lp()->as_CountedLoop());
assert(pre_end != NULL, "we must have a correct pre-loop");
assert(pre_end->stride_is_con(), "pre loop stride is constant");
int preloop_stride = pre_end->stride_con();
@ -1981,7 +1982,7 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
CountedLoopNode *main_head = lp()->as_CountedLoop();
assert(main_head->is_main_loop(), "");
CountedLoopEndNode* pre_end = get_pre_loop_end(main_head);
assert(pre_end != NULL, "");
assert(pre_end != NULL, "we must have a correct pre-loop");
Node *pre_opaq1 = pre_end->limit();
assert(pre_opaq1->Opcode() == Op_Opaque1, "");
Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1;
@ -2145,7 +2146,8 @@ CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode *cl) {
if (!p_f->is_IfFalse()) return NULL;
if (!p_f->in(0)->is_CountedLoopEnd()) return NULL;
CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd();
if (!pre_end->loopnode()->is_pre_loop()) return NULL;
CountedLoopNode* loop_node = pre_end->loopnode();
if (loop_node == NULL || !loop_node->is_pre_loop()) return NULL;
return pre_end;
}

View File

@ -306,6 +306,7 @@ void Type::Initialize_shared(Compile* current) {
TypeInt::POS1 = TypeInt::make(1,max_jint, WidenMin); // Positive values
TypeInt::INT = TypeInt::make(min_jint,max_jint, WidenMax); // 32-bit integers
TypeInt::SYMINT = TypeInt::make(-max_jint,max_jint,WidenMin); // symmetric range
TypeInt::TYPE_DOMAIN = TypeInt::INT;
// CmpL is overloaded both as the bytecode computation returning
// a trinary (-1,0,+1) integer result AND as an efficient long
// compare returning optimizer ideal-type flags.
@ -322,6 +323,7 @@ void Type::Initialize_shared(Compile* current) {
TypeLong::LONG = TypeLong::make(min_jlong,max_jlong,WidenMax); // 64-bit integers
TypeLong::INT = TypeLong::make((jlong)min_jint,(jlong)max_jint,WidenMin);
TypeLong::UINT = TypeLong::make(0,(jlong)max_juint,WidenMin);
TypeLong::TYPE_DOMAIN = TypeLong::LONG;
const Type **fboth =(const Type**)shared_type_arena->Amalloc_4(2*sizeof(Type*));
fboth[0] = Type::CONTROL;
@ -1161,6 +1163,7 @@ const TypeInt *TypeInt::POS; // Positive 32-bit integers or zero
const TypeInt *TypeInt::POS1; // Positive 32-bit integers
const TypeInt *TypeInt::INT; // 32-bit integers
const TypeInt *TypeInt::SYMINT; // symmetric range [-max_jint..max_jint]
const TypeInt *TypeInt::TYPE_DOMAIN; // alias for TypeInt::INT
//------------------------------TypeInt----------------------------------------
TypeInt::TypeInt( jint lo, jint hi, int w ) : Type(Int), _lo(lo), _hi(hi), _widen(w) {
@ -1418,6 +1421,7 @@ const TypeLong *TypeLong::POS; // >=0
const TypeLong *TypeLong::LONG; // 64-bit integers
const TypeLong *TypeLong::INT; // 32-bit subrange
const TypeLong *TypeLong::UINT; // 32-bit unsigned subrange
const TypeLong *TypeLong::TYPE_DOMAIN; // alias for TypeLong::LONG
//------------------------------TypeLong---------------------------------------
TypeLong::TypeLong( jlong lo, jlong hi, int w ) : Type(Long), _lo(lo), _hi(hi), _widen(w) {
@ -2459,7 +2463,7 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
const TypeOopPtr *TypeOopPtr::BOTTOM;
//------------------------------TypeOopPtr-------------------------------------
TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative)
TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth)
: TypePtr(t, ptr, offset),
_const_oop(o), _klass(k),
_klass_is_exact(xk),
@ -2467,7 +2471,8 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o
_is_ptr_to_narrowklass(false),
_is_ptr_to_boxed_value(false),
_instance_id(instance_id),
_speculative(speculative) {
_speculative(speculative),
_inline_depth(inline_depth){
if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
(offset > 0) && xk && (k != 0) && k->is_instance_klass()) {
_is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
@ -2534,12 +2539,12 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o
//------------------------------make-------------------------------------------
const TypeOopPtr *TypeOopPtr::make(PTR ptr,
int offset, int instance_id, const TypeOopPtr* speculative) {
int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) {
assert(ptr != Constant, "no constant generic pointers");
ciKlass* k = Compile::current()->env()->Object_klass();
bool xk = false;
ciObject* o = NULL;
return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative))->hashcons();
return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative, inline_depth))->hashcons();
}
@ -2547,7 +2552,7 @@ const TypeOopPtr *TypeOopPtr::make(PTR ptr,
const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
assert(_base == OopPtr, "subclass must override cast_to_ptr_type");
if( ptr == _ptr ) return this;
return make(ptr, _offset, _instance_id, _speculative);
return make(ptr, _offset, _instance_id, _speculative, _inline_depth);
}
//-----------------------------cast_to_instance_id----------------------------
@ -2644,7 +2649,7 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
case AnyNull: {
int instance_id = meet_instance_id(InstanceTop);
const TypeOopPtr* speculative = _speculative;
return make(ptr, offset, instance_id, speculative);
return make(ptr, offset, instance_id, speculative, _inline_depth);
}
case BotPTR:
case NotNull:
@ -2657,7 +2662,8 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
const TypeOopPtr *tp = t->is_oopptr();
int instance_id = meet_instance_id(tp->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tp);
return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative);
int depth = meet_inline_depth(tp->inline_depth());
return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative, depth);
}
case InstPtr: // For these, flip the call around to cut down
@ -2674,7 +2680,7 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
const Type *TypeOopPtr::xdual() const {
assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here");
assert(const_oop() == NULL, "no constants here");
return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative());
return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
}
//--------------------------make_from_klass_common-----------------------------
@ -2765,7 +2771,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o,
} else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
}
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, NULL, is_autobox_cache);
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0, InstanceBot, NULL, InlineDepthBottom, is_autobox_cache);
return arr;
} else if (klass->is_type_array_klass()) {
// Element is an typeArray
@ -2854,7 +2860,8 @@ bool TypeOopPtr::eq( const Type *t ) const {
const TypeOopPtr *a = (const TypeOopPtr*)t;
if (_klass_is_exact != a->_klass_is_exact ||
_instance_id != a->_instance_id ||
!eq_speculative(a)) return false;
!eq_speculative(a) ||
_inline_depth != a->_inline_depth) return false;
ciObject* one = const_oop();
ciObject* two = a->const_oop();
if (one == NULL || two == NULL) {
@ -2872,6 +2879,7 @@ int TypeOopPtr::hash(void) const {
_klass_is_exact +
_instance_id +
hash_speculative() +
_inline_depth +
TypePtr::hash();
}
@ -2892,6 +2900,7 @@ void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
else if (_instance_id != InstanceBot)
st->print(",iid=%d",_instance_id);
dump_inline_depth(st);
dump_speculative(st);
}
@ -2905,6 +2914,16 @@ void TypeOopPtr::dump_speculative(outputStream *st) const {
st->print(")");
}
}
void TypeOopPtr::dump_inline_depth(outputStream *st) const {
if (_inline_depth != InlineDepthBottom) {
if (_inline_depth == InlineDepthTop) {
st->print(" (inline_depth=InlineDepthTop)");
} else {
st->print(" (inline_depth=%d)", _inline_depth);
}
}
}
#endif
//------------------------------singleton--------------------------------------
@ -2918,7 +2937,7 @@ bool TypeOopPtr::singleton(void) const {
//------------------------------add_offset-------------------------------------
const TypePtr *TypeOopPtr::add_offset(intptr_t offset) const {
return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset));
return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
}
/**
@ -2928,7 +2947,52 @@ const Type* TypeOopPtr::remove_speculative() const {
if (_speculative == NULL) {
return this;
}
return make(_ptr, _offset, _instance_id, NULL);
assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
return make(_ptr, _offset, _instance_id, NULL, _inline_depth);
}
/**
* Return same type but with a different inline depth (used for speculation)
*
* @param depth depth to meet with
*/
const TypeOopPtr* TypeOopPtr::with_inline_depth(int depth) const {
if (!UseInlineDepthForSpeculativeTypes) {
return this;
}
return make(_ptr, _offset, _instance_id, _speculative, depth);
}
/**
* Check whether new profiling would improve speculative type
*
* @param exact_kls class from profiling
* @param inline_depth inlining depth of profile point
*
* @return true if type profile is valuable
*/
bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const {
// no way to improve an already exact type
if (klass_is_exact()) {
return false;
}
// no profiling?
if (exact_kls == NULL) {
return false;
}
// no speculative type or non exact speculative type?
if (speculative_type() == NULL) {
return true;
}
// If the node already has an exact speculative type keep it,
// unless it was provided by profiling that is at a deeper
// inlining level. Profiling at a higher inlining depth is
// expected to be less accurate.
if (_speculative->inline_depth() == InlineDepthBottom) {
return false;
}
assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison");
return inline_depth < _speculative->inline_depth();
}
//------------------------------meet_instance_id--------------------------------
@ -3031,6 +3095,21 @@ int TypeOopPtr::hash_speculative() const {
return _speculative->hash();
}
/**
* dual of the inline depth for this type (used for speculation)
*/
int TypeOopPtr::dual_inline_depth() const {
return -inline_depth();
}
/**
* meet of 2 inline depth (used for speculation)
*
* @param depth depth to meet with
*/
int TypeOopPtr::meet_inline_depth(int depth) const {
return MAX2(inline_depth(), depth);
}
//=============================================================================
// Convenience common pre-built types.
@ -3041,8 +3120,8 @@ const TypeInstPtr *TypeInstPtr::MARK;
const TypeInstPtr *TypeInstPtr::KLASS;
//------------------------------TypeInstPtr-------------------------------------
TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative)
: TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative), _name(k->name()) {
TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative, int inline_depth)
: TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), _name(k->name()) {
assert(k != NULL &&
(k->is_loaded() || o == NULL),
"cannot have constants with non-loaded klass");
@ -3055,7 +3134,8 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
ciObject* o,
int offset,
int instance_id,
const TypeOopPtr* speculative) {
const TypeOopPtr* speculative,
int inline_depth) {
assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
// Either const_oop() is NULL or else ptr is Constant
assert( (!o && ptr != Constant) || (o && ptr == Constant),
@ -3076,7 +3156,7 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
// Now hash this baby
TypeInstPtr *result =
(TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative))->hashcons();
(TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative, inline_depth))->hashcons();
return result;
}
@ -3109,7 +3189,7 @@ const Type *TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
if( ptr == _ptr ) return this;
// Reconstruct _sig info here since not a problem with later lazy
// construction, _sig will show up on demand.
return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative);
return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, _inline_depth);
}
@ -3121,13 +3201,13 @@ const Type *TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
ciInstanceKlass* ik = _klass->as_instance_klass();
if( (ik->is_final() || _const_oop) ) return this; // cannot clear xk
if( ik->is_interface() ) return this; // cannot set xk
return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative);
return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative, _inline_depth);
}
//-----------------------------cast_to_instance_id----------------------------
const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
if( instance_id == _instance_id ) return this;
return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative);
return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative, _inline_depth);
}
//------------------------------xmeet_unloaded---------------------------------
@ -3138,6 +3218,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
PTR ptr = meet_ptr(tinst->ptr());
int instance_id = meet_instance_id(tinst->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tinst);
int depth = meet_inline_depth(tinst->inline_depth());
const TypeInstPtr *loaded = is_loaded() ? this : tinst;
const TypeInstPtr *unloaded = is_loaded() ? tinst : this;
@ -3158,7 +3239,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
assert(loaded->ptr() != TypePtr::Null, "insanity check");
//
if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative); }
else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative, depth); }
else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
if (unloaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
@ -3215,6 +3296,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
PTR ptr = meet_ptr(tp->ptr());
int instance_id = meet_instance_id(tp->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tp);
int depth = meet_inline_depth(tp->inline_depth());
switch (ptr) {
case TopPTR:
case AnyNull: // Fall 'down' to dual of object klass
@ -3222,12 +3304,12 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
// below the centerline when the superclass is exact. We need to
// do the same here.
if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative);
return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative, depth);
} else {
// cannot subclass, so the meet has to fall badly below the centerline
ptr = NotNull;
instance_id = InstanceBot;
return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative);
return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth);
}
case Constant:
case NotNull:
@ -3242,7 +3324,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
// that is, tp's array type is a subtype of my klass
return TypeAryPtr::make(ptr, (ptr == Constant ? tp->const_oop() : NULL),
tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative);
tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative, depth);
}
}
// The other case cannot happen, since I cannot be a subtype of an array.
@ -3250,7 +3332,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
if( ptr == Constant )
ptr = NotNull;
instance_id = InstanceBot;
return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative);
return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth);
default: typerr(t);
}
}
@ -3265,14 +3347,16 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
case AnyNull: {
int instance_id = meet_instance_id(InstanceTop);
const TypeOopPtr* speculative = xmeet_speculative(tp);
int depth = meet_inline_depth(tp->inline_depth());
return make(ptr, klass(), klass_is_exact(),
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative);
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
}
case NotNull:
case BotPTR: {
int instance_id = meet_instance_id(tp->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tp);
return TypeOopPtr::make(ptr, offset, instance_id, speculative);
int depth = meet_inline_depth(tp->inline_depth());
return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
}
default: typerr(t);
}
@ -3292,7 +3376,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
int instance_id = meet_instance_id(InstanceTop);
const TypeOopPtr* speculative = _speculative;
return make(ptr, klass(), klass_is_exact(),
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative);
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, _inline_depth);
}
case NotNull:
case BotPTR:
@ -3324,13 +3408,14 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
PTR ptr = meet_ptr( tinst->ptr() );
int instance_id = meet_instance_id(tinst->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tinst);
int depth = meet_inline_depth(tinst->inline_depth());
// Check for easy case; klasses are equal (and perhaps not loaded!)
// If we have constants, then we created oops so classes are loaded
// and we can handle the constants further down. This case handles
// both-not-loaded or both-loaded classes
if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact()) {
return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative);
return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative, depth);
}
// Classes require inspection in the Java klass hierarchy. Must be loaded.
@ -3394,7 +3479,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
// Find out which constant.
o = (this_klass == klass()) ? const_oop() : tinst->const_oop();
}
return make(ptr, k, xk, o, off, instance_id, speculative);
return make(ptr, k, xk, o, off, instance_id, speculative, depth);
}
// Either oop vs oop or interface vs interface or interface vs Object
@ -3471,7 +3556,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
else
ptr = NotNull;
}
return make(ptr, this_klass, this_xk, o, off, instance_id, speculative);
return make(ptr, this_klass, this_xk, o, off, instance_id, speculative, depth);
} // Else classes are not equal
// Since klasses are different, we require a LCA in the Java
@ -3482,7 +3567,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
// Now we find the LCA of Java classes
ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
return make(ptr, k, false, NULL, off, instance_id, speculative);
return make(ptr, k, false, NULL, off, instance_id, speculative, depth);
} // End of case InstPtr
} // End of switch
@ -3506,7 +3591,7 @@ ciType* TypeInstPtr::java_mirror_type() const {
// Dual: do NOT dual on klasses. This means I do NOT understand the Java
// inheritance mechanism.
const Type *TypeInstPtr::xdual() const {
return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative());
return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
}
//------------------------------eq---------------------------------------------
@ -3563,6 +3648,7 @@ void TypeInstPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
else if (_instance_id != InstanceBot)
st->print(",iid=%d",_instance_id);
dump_inline_depth(st);
dump_speculative(st);
}
#endif
@ -3576,7 +3662,15 @@ const Type *TypeInstPtr::remove_speculative() const {
if (_speculative == NULL) {
return this;
}
return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL);
assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL, _inline_depth);
}
const TypeOopPtr *TypeInstPtr::with_inline_depth(int depth) const {
if (!UseInlineDepthForSpeculativeTypes) {
return this;
}
return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth);
}
//=============================================================================
@ -3593,30 +3687,30 @@ const TypeAryPtr *TypeAryPtr::FLOATS;
const TypeAryPtr *TypeAryPtr::DOUBLES;
//------------------------------make-------------------------------------------
const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative) {
const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) {
assert(!(k == NULL && ary->_elem->isa_int()),
"integral arrays must be pre-equipped with a class");
if (!xk) xk = ary->ary_must_be_exact();
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
if (!UseExactTypes) xk = (ptr == Constant);
return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative))->hashcons();
return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative, inline_depth))->hashcons();
}
//------------------------------make-------------------------------------------
const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, bool is_autobox_cache) {
const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth, bool is_autobox_cache) {
assert(!(k == NULL && ary->_elem->isa_int()),
"integral arrays must be pre-equipped with a class");
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
if (!xk) xk = (o != NULL) || ary->ary_must_be_exact();
assert(instance_id <= 0 || xk || !UseExactTypes, "instances are always exactly typed");
if (!UseExactTypes) xk = (ptr == Constant);
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative))->hashcons();
return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
}
//------------------------------cast_to_ptr_type-------------------------------
const Type *TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
if( ptr == _ptr ) return this;
return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative);
return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
}
@ -3625,13 +3719,13 @@ const Type *TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
if( klass_is_exact == _klass_is_exact ) return this;
if (!UseExactTypes) return this;
if (_ary->ary_must_be_exact()) return this; // cannot clear xk
return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative);
return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative, _inline_depth);
}
//-----------------------------cast_to_instance_id----------------------------
const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const {
if( instance_id == _instance_id ) return this;
return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative);
return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative, _inline_depth);
}
//-----------------------------narrow_size_type-------------------------------
@ -3694,7 +3788,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const {
new_size = narrow_size_type(new_size);
if (new_size == size()) return this;
const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative);
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
}
@ -3773,19 +3867,20 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
const TypeOopPtr *tp = t->is_oopptr();
int offset = meet_offset(tp->offset());
PTR ptr = meet_ptr(tp->ptr());
int depth = meet_inline_depth(tp->inline_depth());
switch (tp->ptr()) {
case TopPTR:
case AnyNull: {
int instance_id = meet_instance_id(InstanceTop);
const TypeOopPtr* speculative = xmeet_speculative(tp);
return make(ptr, (ptr == Constant ? const_oop() : NULL),
_ary, _klass, _klass_is_exact, offset, instance_id, speculative);
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
}
case BotPTR:
case NotNull: {
int instance_id = meet_instance_id(tp->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tp);
return TypeOopPtr::make(ptr, offset, instance_id, speculative);
return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
}
default: ShouldNotReachHere();
}
@ -3809,7 +3904,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
int instance_id = meet_instance_id(InstanceTop);
const TypeOopPtr* speculative = _speculative;
return make(ptr, (ptr == Constant ? const_oop() : NULL),
_ary, _klass, _klass_is_exact, offset, instance_id, speculative);
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, _inline_depth);
}
default: ShouldNotReachHere();
}
@ -3826,6 +3921,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
PTR ptr = meet_ptr(tap->ptr());
int instance_id = meet_instance_id(tap->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tap);
int depth = meet_inline_depth(tap->inline_depth());
ciKlass* lazy_klass = NULL;
if (tary->_elem->isa_int()) {
// Integral array element types have irrelevant lattice relations.
@ -3866,7 +3962,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
} else {
xk = (tap->_klass_is_exact | this->_klass_is_exact);
}
return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative);
return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative, depth);
case Constant: {
ciObject* o = const_oop();
if( _ptr == Constant ) {
@ -3885,7 +3981,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
// Only precise for identical arrays
xk = this->_klass_is_exact && (klass() == tap->klass());
}
return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative);
return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative, depth);
}
case NotNull:
case BotPTR:
@ -3894,7 +3990,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
xk = tap->_klass_is_exact;
else xk = (tap->_klass_is_exact & this->_klass_is_exact) &&
(klass() == tap->klass()); // Only precise for identical arrays
return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative);
return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative, depth);
default: ShouldNotReachHere();
}
}
@ -3906,6 +4002,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
PTR ptr = meet_ptr(tp->ptr());
int instance_id = meet_instance_id(tp->instance_id());
const TypeOopPtr* speculative = xmeet_speculative(tp);
int depth = meet_inline_depth(tp->inline_depth());
switch (ptr) {
case TopPTR:
case AnyNull: // Fall 'down' to dual of object klass
@ -3913,12 +4010,12 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
// below the centerline when the superclass is exact. We need to
// do the same here.
if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative);
return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
} else {
// cannot subclass, so the meet has to fall badly below the centerline
ptr = NotNull;
instance_id = InstanceBot;
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative);
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative, depth);
}
case Constant:
case NotNull:
@ -3933,7 +4030,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
// that is, my array type is a subtype of 'tp' klass
return make(ptr, (ptr == Constant ? const_oop() : NULL),
_ary, _klass, _klass_is_exact, offset, instance_id, speculative);
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
}
}
// The other case cannot happen, since t cannot be a subtype of an array.
@ -3941,7 +4038,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
if( ptr == Constant )
ptr = NotNull;
instance_id = InstanceBot;
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative);
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative, depth);
default: typerr(t);
}
}
@ -3952,7 +4049,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
//------------------------------xdual------------------------------------------
// Dual: compute field-by-field dual
const Type *TypeAryPtr::xdual() const {
return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative());
return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth());
}
//----------------------interface_vs_oop---------------------------------------
@ -4005,6 +4102,7 @@ void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
else if (_instance_id != InstanceBot)
st->print(",iid=%d",_instance_id);
dump_inline_depth(st);
dump_speculative(st);
}
#endif
@ -4016,11 +4114,22 @@ bool TypeAryPtr::empty(void) const {
//------------------------------add_offset-------------------------------------
const TypePtr *TypeAryPtr::add_offset(intptr_t offset) const {
return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset));
return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
}
const Type *TypeAryPtr::remove_speculative() const {
return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL);
if (_speculative == NULL) {
return this;
}
assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth);
}
const TypeOopPtr *TypeAryPtr::with_inline_depth(int depth) const {
if (!UseInlineDepthForSpeculativeTypes) {
return this;
}
return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, _speculative, depth);
}
//=============================================================================

View File

@ -415,10 +415,15 @@ public:
bool is_autobox_cache = false);
// Speculative type. See TypeInstPtr
virtual const TypeOopPtr* speculative() const { return NULL; }
virtual ciKlass* speculative_type() const { return NULL; }
const Type* maybe_remove_speculative(bool include_speculative) const;
virtual const Type* remove_speculative() const { return this; }
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const {
return exact_kls != NULL;
}
private:
// support arrays
static const BasicType _basic_type[];
@ -489,6 +494,7 @@ protected:
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
public:
typedef jint NativeType;
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
virtual bool singleton(void) const; // TRUE if type is a singleton
@ -531,6 +537,9 @@ public:
static const TypeInt *POS1;
static const TypeInt *INT;
static const TypeInt *SYMINT; // symmetric range [-max_jint..max_jint]
static const TypeInt *TYPE_DOMAIN; // alias for TypeInt::INT
static const TypeInt *as_self(const Type *t) { return t->is_int(); }
#ifndef PRODUCT
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
#endif
@ -546,6 +555,7 @@ protected:
// Do not kill _widen bits.
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
public:
typedef jlong NativeType;
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
virtual bool singleton(void) const; // TRUE if type is a singleton
@ -568,6 +578,7 @@ public:
virtual bool is_finite() const; // Has a finite value
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
virtual const Type *widen( const Type *t, const Type* limit_type ) const;
@ -580,6 +591,11 @@ public:
static const TypeLong *LONG;
static const TypeLong *INT; // 32-bit subrange [min_jint..max_jint]
static const TypeLong *UINT; // 32-bit unsigned [0..max_juint]
static const TypeLong *TYPE_DOMAIN; // alias for TypeLong::LONG
// static convenience methods.
static const TypeLong *as_self(const Type *t) { return t->is_long(); }
#ifndef PRODUCT
virtual void dump2( Dict &d, uint, outputStream *st ) const;// Specialized per-Type dumping
#endif
@ -834,7 +850,7 @@ public:
// Some kind of oop (Java pointer), either klass or instance or array.
class TypeOopPtr : public TypePtr {
protected:
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative);
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth);
public:
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
@ -845,6 +861,10 @@ public:
};
protected:
enum {
InlineDepthBottom = INT_MAX,
InlineDepthTop = -InlineDepthBottom
};
// Oop is NULL, unless this is a constant oop.
ciObject* _const_oop; // Constant oop
// If _klass is NULL, then so is _sig. This is an unloaded klass.
@ -865,6 +885,11 @@ protected:
// use it, then we have to emit a guard: this part of the type is
// not something we know but something we speculate about the type.
const TypeOopPtr* _speculative;
// For speculative types, we record at what inlining depth the
// profiling point that provided the data is. We want to favor
// profile data coming from outer scopes which are likely better for
// the current compilation.
int _inline_depth;
static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
@ -880,6 +905,12 @@ protected:
#ifndef PRODUCT
void dump_speculative(outputStream *st) const;
#endif
// utility methods to work on the inline depth of the type
int dual_inline_depth() const;
int meet_inline_depth(int depth) const;
#ifndef PRODUCT
void dump_inline_depth(outputStream *st) const;
#endif
// Do not allow interface-vs.-noninterface joins to collapse to top.
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
@ -910,7 +941,7 @@ public:
bool not_null_elements = false);
// Make a generic (unclassed) pointer to an oop.
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative);
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom);
ciObject* const_oop() const { return _const_oop; }
virtual ciKlass* klass() const { return _klass; }
@ -924,7 +955,7 @@ public:
bool is_known_instance() const { return _instance_id > 0; }
int instance_id() const { return _instance_id; }
bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; }
const TypeOopPtr* speculative() const { return _speculative; }
virtual const TypeOopPtr* speculative() const { return _speculative; }
virtual intptr_t get_con() const;
@ -957,18 +988,23 @@ public:
if (_speculative != NULL) {
const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr();
if (speculative->klass_is_exact()) {
return speculative->klass();
return speculative->klass();
}
}
return NULL;
}
int inline_depth() const {
return _inline_depth;
}
virtual const TypeOopPtr* with_inline_depth(int depth) const;
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const;
};
//------------------------------TypeInstPtr------------------------------------
// Class of Java object pointers, pointing either to non-array Java instances
// or to a Klass* (including array klasses).
class TypeInstPtr : public TypeOopPtr {
TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative);
TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth);
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
@ -1004,7 +1040,7 @@ class TypeInstPtr : public TypeOopPtr {
}
// Make a pointer to an oop.
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL);
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom);
/** Create constant type for a constant boxed value */
const Type* get_const_boxed_value() const;
@ -1023,6 +1059,7 @@ class TypeInstPtr : public TypeOopPtr {
virtual const TypePtr *add_offset( intptr_t offset ) const;
// Return same type without a speculative part
virtual const Type* remove_speculative() const;
virtual const TypeOopPtr* with_inline_depth(int depth) const;
// the core of the computation of the meet of 2 types
virtual const Type *xmeet_helper(const Type *t) const;
@ -1044,8 +1081,8 @@ class TypeInstPtr : public TypeOopPtr {
// Class of Java array pointers
class TypeAryPtr : public TypeOopPtr {
TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative)
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative),
int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative, int inline_depth)
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth),
_ary(ary),
_is_autobox_cache(is_autobox_cache)
{
@ -1083,9 +1120,9 @@ public:
bool is_autobox_cache() const { return _is_autobox_cache; }
static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL);
static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom);
// Constant pointer to array
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, bool is_autobox_cache = false);
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom, bool is_autobox_cache= false);
// Return a 'ptr' version of this type
virtual const Type *cast_to_ptr_type(PTR ptr) const;
@ -1101,6 +1138,7 @@ public:
virtual const TypePtr *add_offset( intptr_t offset ) const;
// Return same type without a speculative part
virtual const Type* remove_speculative() const;
virtual const TypeOopPtr* with_inline_depth(int depth) const;
// the core of the computation of the meet of 2 types
virtual const Type *xmeet_helper(const Type *t) const;

View File

@ -2408,6 +2408,10 @@ bool Arguments::check_vm_args_consistency() {
status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction");
status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity");
// TieredCompilation needs at least 2 compiler threads.
const int num_min_compiler_threads = (TieredCompilation) ? 2 : 1;
status &=verify_min_value(CICompilerCount, num_min_compiler_threads, "CICompilerCount");
return status;
}

View File

@ -128,7 +128,7 @@ static GrowableArray<MonitorInfo*>* get_or_compute_monitor_info(JavaThread* thre
// Walk monitors youngest to oldest
for (int i = len - 1; i >= 0; i--) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->owner_is_scalar_replaced()) continue;
if (mon_info->eliminated()) continue;
oop owner = mon_info->owner();
if (owner != NULL) {
info->append(mon_info);

View File

@ -1489,6 +1489,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
bool maybe_prior_trap = false;
bool maybe_prior_recompile = false;
pdata = query_update_method_data(trap_mdo, trap_bci, reason,
nm->method(),
//outputs:
this_trap_count,
maybe_prior_trap,
@ -1534,7 +1535,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
}
// Go back to the compiler if there are too many traps in this method.
if (this_trap_count >= (uint)PerMethodTrapLimit) {
if (this_trap_count >= per_method_trap_limit(reason)) {
// If there are too many traps in this method, force a recompile.
// This will allow the compiler to see the limit overflow, and
// take corrective action, if possible.
@ -1622,6 +1623,7 @@ ProfileData*
Deoptimization::query_update_method_data(MethodData* trap_mdo,
int trap_bci,
Deoptimization::DeoptReason reason,
Method* compiled_method,
//outputs:
uint& ret_this_trap_count,
bool& ret_maybe_prior_trap,
@ -1645,9 +1647,16 @@ Deoptimization::query_update_method_data(MethodData* trap_mdo,
// Find the profile data for this BCI. If there isn't one,
// try to allocate one from the MDO's set of spares.
// This will let us detect a repeated trap at this point.
pdata = trap_mdo->allocate_bci_to_data(trap_bci);
pdata = trap_mdo->allocate_bci_to_data(trap_bci, reason_is_speculate(reason) ? compiled_method : NULL);
if (pdata != NULL) {
if (reason_is_speculate(reason) && !pdata->is_SpeculativeTrapData()) {
if (LogCompilation && xtty != NULL) {
ttyLocker ttyl;
// no more room for speculative traps in this MDO
xtty->elem("speculative_traps_oom");
}
}
// Query the trap state of this profile datum.
int tstate0 = pdata->trap_state();
if (!trap_state_has_reason(tstate0, per_bc_reason))
@ -1685,8 +1694,10 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr
uint ignore_this_trap_count;
bool ignore_maybe_prior_trap;
bool ignore_maybe_prior_recompile;
assert(!reason_is_speculate(reason), "reason speculate only used by compiler");
query_update_method_data(trap_mdo, trap_bci,
(DeoptReason)reason,
NULL,
ignore_this_trap_count,
ignore_maybe_prior_trap,
ignore_maybe_prior_recompile);
@ -1814,7 +1825,8 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = {
"div0_check",
"age",
"predicate",
"loop_limit_check"
"loop_limit_check",
"speculate_class_check"
};
const char* Deoptimization::_trap_action_name[Action_LIMIT] = {
// Note: Keep this in sync. with enum DeoptAction.

View File

@ -59,6 +59,7 @@ class Deoptimization : AllStatic {
Reason_age, // nmethod too old; tier threshold reached
Reason_predicate, // compiler generated predicate failed
Reason_loop_limit_check, // compiler generated loop limits check failed
Reason_speculate_class_check, // saw unexpected object class from type speculation
Reason_LIMIT,
// Note: Keep this enum in sync. with _trap_reason_name.
Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc
@ -311,10 +312,23 @@ class Deoptimization : AllStatic {
return reason;
else if (reason == Reason_div0_check) // null check due to divide-by-zero?
return Reason_null_check; // recorded per BCI as a null check
else if (reason == Reason_speculate_class_check)
return Reason_class_check;
else
return Reason_none;
}
static bool reason_is_speculate(int reason) {
if (reason == Reason_speculate_class_check) {
return true;
}
return false;
}
static uint per_method_trap_limit(int reason) {
return reason_is_speculate(reason) ? (uint)PerMethodSpecTrapLimit : (uint)PerMethodTrapLimit;
}
static const char* trap_reason_name(int reason);
static const char* trap_action_name(int action);
// Format like reason='foo' action='bar' index='123'.
@ -337,6 +351,7 @@ class Deoptimization : AllStatic {
static ProfileData* query_update_method_data(MethodData* trap_mdo,
int trap_bci,
DeoptReason reason,
Method* compiled_method,
//outputs:
uint& ret_this_trap_count,
bool& ret_maybe_prior_trap,

View File

@ -933,20 +933,9 @@ void frame::oops_interpreted_do(OopClosure* f, CLDClosure* cld_f,
cld_f->do_cld(m->method_holder()->class_loader_data());
}
#if !defined(PPC32) || defined(ZERO)
if (m->is_native()) {
#ifdef CC_INTERP
interpreterState istate = get_interpreterState();
f->do_oop((oop*)&istate->_oop_temp);
#else
f->do_oop((oop*)( fp() + interpreter_frame_oop_temp_offset ));
#endif /* CC_INTERP */
if (m->is_native() PPC32_ONLY(&& m->is_static())) {
f->do_oop(interpreter_frame_temp_oop_addr());
}
#else // PPC32
if (m->is_native() && m->is_static()) {
f->do_oop(interpreter_frame_mirror_addr());
}
#endif // PPC32
int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals();

View File

@ -314,6 +314,9 @@ class frame VALUE_OBJ_CLASS_SPEC {
void interpreter_frame_set_monitor_end(BasicObjectLock* value);
#endif // CC_INTERP
// Address of the temp oop in the frame. Needed as GC root.
oop* interpreter_frame_temp_oop_addr() const;
// BasicObjectLocks:
//
// interpreter_frame_monitor_begin is higher in memory than interpreter_frame_monitor_end
@ -350,9 +353,6 @@ class frame VALUE_OBJ_CLASS_SPEC {
void interpreter_frame_set_method(Method* method);
Method** interpreter_frame_method_addr() const;
ConstantPoolCache** interpreter_frame_cache_addr() const;
#ifdef PPC32
oop* interpreter_frame_mirror_addr() const;
#endif
public:
// Entry frames

View File

@ -87,6 +87,13 @@ inline bool frame::is_first_frame() const {
return is_entry_frame() && entry_frame_is_first();
}
#ifdef CC_INTERP
inline oop* frame::interpreter_frame_temp_oop_addr() const {
interpreterState istate = get_interpreterState();
return (oop *)&istate->_oop_temp;
}
#endif // CC_INTERP
// here are the platform-dependent bodies:
#ifdef TARGET_ARCH_x86

View File

@ -3078,9 +3078,15 @@ class CommandLineFlags {
product(intx, PerMethodTrapLimit, 100, \
"Limit on traps (of one kind) in a method (includes inlines)") \
\
experimental(intx, PerMethodSpecTrapLimit, 5000, \
"Limit on speculative traps (of one kind) in a method (includes inlines)") \
\
product(intx, PerBytecodeTrapLimit, 4, \
"Limit on traps (of one kind) at a particular BCI") \
\
experimental(intx, SpecTrapLimitExtraEntries, 3, \
"Extra method data trap entries for speculation") \
\
develop(intx, InlineFrequencyRatio, 20, \
"Ratio of call site execution to caller method invocation") \
\

View File

@ -1176,9 +1176,9 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
c2_nonstatic_field(Block, _pre_order, uint) \
c2_nonstatic_field(Block, _dom_depth, uint) \
c2_nonstatic_field(Block, _idom, Block*) \
c2_nonstatic_field(Block, _freq, jfloat) \
c2_nonstatic_field(Block, _freq, jdouble) \
\
c2_nonstatic_field(CFGElement, _freq, jfloat) \
c2_nonstatic_field(CFGElement, _freq, jdouble) \
\
c2_nonstatic_field(Block_List, _cnt, uint) \
\
@ -1942,15 +1942,6 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
declare_c2_type(CmpF3Node, CmpFNode) \
declare_c2_type(CmpDNode, CmpNode) \
declare_c2_type(CmpD3Node, CmpDNode) \
declare_c2_type(MathExactNode, MultiNode) \
declare_c2_type(MathExactINode, MathExactNode) \
declare_c2_type(AddExactINode, MathExactINode) \
declare_c2_type(AddExactLNode, MathExactLNode) \
declare_c2_type(SubExactINode, MathExactINode) \
declare_c2_type(SubExactLNode, MathExactLNode) \
declare_c2_type(NegExactINode, MathExactINode) \
declare_c2_type(MulExactINode, MathExactINode) \
declare_c2_type(FlagsProjNode, ProjNode) \
declare_c2_type(BoolNode, Node) \
declare_c2_type(AbsNode, Node) \
declare_c2_type(AbsINode, AbsNode) \
@ -2031,6 +2022,15 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
declare_c2_type(ExtractLNode, ExtractNode) \
declare_c2_type(ExtractFNode, ExtractNode) \
declare_c2_type(ExtractDNode, ExtractNode) \
declare_c2_type(OverflowNode, CmpNode) \
declare_c2_type(OverflowINode, OverflowNode) \
declare_c2_type(OverflowAddINode, OverflowINode) \
declare_c2_type(OverflowSubINode, OverflowINode) \
declare_c2_type(OverflowMulINode, OverflowINode) \
declare_c2_type(OverflowLNode, OverflowNode) \
declare_c2_type(OverflowAddLNode, OverflowLNode) \
declare_c2_type(OverflowSubLNode, OverflowLNode) \
declare_c2_type(OverflowMulLNode, OverflowLNode) \
\
/*********************/ \
/* Adapter Blob Entries */ \

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp"
#include "code/dependencies.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "memory/resourceArea.hpp"
@ -338,7 +339,6 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify() {
#endif // PRODUCT
#ifdef ASSERT
template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load) {
@ -351,6 +351,118 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load)
}
#endif
template<class T, class M> GenericHashtable<T, M>::GenericHashtable(int size, bool C_heap, MEMFLAGS memflag) {
assert(size > 0, " Invalid hashtable size");
_size = size;
_C_heap = C_heap;
_memflag = memflag;
// Perform subtype-specific resource allocation
_items = (C_heap) ? NEW_C_HEAP_ARRAY(T*, size, memflag) : NEW_RESOURCE_ARRAY(T*, size);
memset(_items, 0, sizeof(T*) * size);
DEBUG_ONLY(_num_items = 0;)
}
template<class T, class M> GenericHashtable<T, M>::~GenericHashtable() {
if (on_C_heap()) {
// Check backing array
for (int i = 0; i < size(); i++) {
T* item = head(i);
// Delete all items in linked list
while (item != NULL) {
T* next_item = item->next();
delete item;
DEBUG_ONLY(_num_items--);
item = next_item;
}
}
FREE_C_HEAP_ARRAY(T*, _items, _memflag);
_items = NULL;
assert (_num_items == 0, "Not all memory released");
}
}
/**
* Return a pointer to the item 'I' that is stored in the hashtable for
* which match_item->equals(I) == true. If no such item is found, NULL
* is returned.
*/
template<class T, class F> T* GenericHashtable<T, F>::contains(T* match_item) {
if (match_item != NULL) {
int idx = index(match_item);
return contains_impl(match_item, idx);
}
return NULL;
}
/**
* Add item to the hashtable. Return 'true' if the item was added
* and false otherwise.
*/
template<class T, class F> bool GenericHashtable<T, F>::add(T* item) {
if (item != NULL) {
int idx = index(item);
T* found_item = contains_impl(item, idx);
if (found_item == NULL) {
T* list_head = head(idx);
item->set_next(list_head);
item->set_prev(NULL);
if (list_head != NULL) {
list_head->set_prev(item);
}
set_head(item, idx);
DEBUG_ONLY(_num_items++);
return true;
}
}
return false;
}
/**
* Removes an item 'I' from the hashtable, if present. 'I' is removed, if
* match_item->equals(I) == true. Removing an item from the hashtable does
* not free memory.
*/
template<class T, class F> T* GenericHashtable<T, F>::remove(T* match_item) {
if (match_item != NULL) {
int idx = index(match_item);
T* found_item = contains_impl(match_item, idx);
if (found_item != NULL) {
// Remove item from linked list
T* prev = found_item->prev();
T* next = found_item->next();
if (prev != NULL) {
prev->set_next(next);
} else {
set_head(next, idx);
}
if (next != NULL) {
next->set_prev(prev);
}
DEBUG_ONLY(_num_items--);
return found_item;
}
}
return NULL;
}
template<class T, class F> T* GenericHashtable<T, F>::contains_impl(T* item, int idx) {
T* current_item = head(idx);
while (current_item != NULL) {
if (current_item->equals(item)) {
return current_item;
}
current_item = current_item->next();
}
return NULL;
}
// Explicitly instantiate these types
template class Hashtable<ConstantPool*, mtClass>;
template class Hashtable<Symbol*, mtSymbol>;
@ -370,3 +482,5 @@ template class BasicHashtable<mtClass>;
template class BasicHashtable<mtSymbol>;
template class BasicHashtable<mtCode>;
template class BasicHashtable<mtInternal>;
template class GenericHashtable<DependencySignature, ResourceObj>;

View File

@ -300,7 +300,7 @@ public:
};
// Verions of hashtable where two handles are used to compute the index.
// Versions of hashtable where two handles are used to compute the index.
template <class T, MEMFLAGS F> class TwoOopHashtable : public Hashtable<T, F> {
friend class VMStructs;
@ -327,4 +327,86 @@ public:
}
};
/*
* Usage of GenericHashtable:
*
* class X : public GenericHashtableEntry<X, ResourceObj> {
*
* // Implement virtual functions in class X
* bool equals(X* sig) const;
* uintptr_t hash() const;
* };
*
* void foo() {
* GenericHashtable<X, ResourceObj>* table = new GenericHashtable<X, ResourceObj>(11027, false);
*
* X* elem = new X();
* table->add(elem);
* table->contains(elem);
* }
*
* You can choose other allocation types as well. For example, to store the hashtable to a
* particular region (CHeapObj<type>) simply replace ResourceObj with the desired type:
*
* class X : public GenericHashtableEntry<X, CHeapObj<mtCode> > { ... };
*
* To make the destructor (and remove) of the hashtable work:
* 1) override the delete operator of X
* 2) provide a destructor of the X
*
* You may also find it convenient to override the new operator.
*
* If you use this templates do not forget to add an explicit initialization
* (at the end of hashtable.cpp).
*
* template class GenericHashtable<X, ResourceObj>;
*/
template <class T, class M> class GenericHashtableEntry : public M {
private:
T* _next;
T* _prev;
public:
// Must be implemented by subclass.
virtual uintptr_t key() const = 0;
virtual bool equals(T* other) const = 0;
T* next() const { return _next; }
T* prev() const { return _prev; }
void set_next(T* item) { _next = item; }
void set_prev(T* item) { _prev = item; }
// Constructor and destructor
GenericHashtableEntry() : _next(NULL), _prev(NULL) { };
virtual ~GenericHashtableEntry() {};
};
template <class T, class M> class GenericHashtable : public M {
private:
T** _items;
int _size;
bool _C_heap;
MEMFLAGS _memflag;
// Accessor methods
T* head (int idx) const { return _items[idx]; }
void set_head(T* item, int idx) { _items[idx] = item; }
int index (T* item) { assert(item != NULL, "missing null check"); return item->key() % size(); }
// Helper function
T* contains_impl(T* item, int idx);
DEBUG_ONLY(int _num_items;)
public:
GenericHashtable(int size, bool C_heap = false, MEMFLAGS memflag = mtNone);
~GenericHashtable();
T* contains(T* match_item);
T* remove (T* match_item);
bool add (T* item);
bool on_C_heap() const { return _C_heap; }
int size() const { return _size; }
};
#endif // SHARE_VM_UTILITIES_HASHTABLE_HPP

View File

@ -26,7 +26,7 @@
* @bug 8024924
* @summary Test non constant addExact
* @compile AddExactICondTest.java
* @run main AddExactICondTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactICondTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8024924
* @summary Test constant addExact
* @compile AddExactIConstantTest.java Verify.java
* @run main AddExactIConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactIConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8024924
* @summary Test non constant addExact
* @compile AddExactILoadTest.java Verify.java
* @run main AddExactILoadTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactILoadTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8024924
* @summary Test non constant addExact
* @compile AddExactILoopDependentTest.java Verify.java
* @run main AddExactILoopDependentTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactILoopDependentTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8024924
* @summary Test non constant addExact
* @compile AddExactINonConstantTest.java Verify.java
* @run main AddExactINonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactINonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8025657
* @summary Test repeating addExact
* @compile AddExactIRepeatTest.java Verify.java
* @run main AddExactIRepeatTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactIRepeatTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant addExact
* @compile AddExactLConstantTest.java Verify.java
* @run main AddExactLConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactLConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant addExact
* @compile AddExactLNonConstantTest.java Verify.java
* @run main AddExactLNonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main AddExactLNonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026722
* @summary Verify that the compare after addExact is a signed compare
* @compile CompareTest.java
* @run main CompareTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main CompareTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test decrementExact
* @compile DecExactITest.java Verify.java
* @run main DecExactITest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main DecExactITest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test decrementExact
* @compile DecExactLTest.java Verify.java
* @run main DecExactLTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main DecExactLTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8028207
* @summary Verify that GVN doesn't mess up the two addExacts
* @compile GVNTest.java
* @run main GVNTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main GVNTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test incrementExact
* @compile IncExactITest.java Verify.java
* @run main IncExactITest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main IncExactITest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test incrementExact
* @compile IncExactLTest.java Verify.java
* @run main IncExactLTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main IncExactLTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test multiplyExact as condition
* @compile MulExactICondTest.java
* @run main MulExactICondTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactICondTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant multiplyExact
* @compile MulExactIConstantTest.java Verify.java
* @run main MulExactIConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactIConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test multiplyExact
* @compile MulExactILoadTest.java Verify.java
* @run main MulExactILoadTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactILoadTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test loop dependent multiplyExact
* @compile MulExactILoopDependentTest.java Verify.java
* @run main MulExactILoopDependentTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactILoopDependentTest
*
*/
public class MulExactILoopDependentTest {

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant multiplyExact
* @compile MulExactINonConstantTest.java Verify.java
* @run main MulExactINonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactINonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test repeating multiplyExact
* @compile MulExactIRepeatTest.java Verify.java
* @run main MulExactIRepeatTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactIRepeatTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant mulExact
* @compile MulExactLConstantTest.java Verify.java
* @run main MulExactLConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactLConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant mulExact
* @compile MulExactLNonConstantTest.java Verify.java
* @run main MulExactLNonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main MulExactLNonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant negExact
* @compile NegExactIConstantTest.java Verify.java
* @run main NegExactIConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NegExactIConstantTest
*
*/

View File

@ -26,14 +26,14 @@
* @bug 8026844
* @summary Test negExact
* @compile NegExactILoadTest.java Verify.java
* @run main NegExactILoadTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NegExactILoadTest
*
*/
public class NegExactILoadTest {
public static void main(String[] args) {
Verify.LoadTest.init();
Verify.LoadTest.verify(new Verify.UnaryToBinary(new Verify.NegExactI()));
Verify.LoadTest.init();
Verify.LoadTest.verify(new Verify.UnaryToBinary(new Verify.NegExactI()));
}
}

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test negExact loop dependent
* @compile NegExactILoopDependentTest.java Verify.java
* @run main NegExactILoopDependentTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NegExactILoopDependentTest
*
*/
public class NegExactILoopDependentTest {

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant negExact
* @compile NegExactINonConstantTest.java Verify.java
* @run main NegExactINonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NegExactINonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant negExact
* @compile NegExactLConstantTest.java Verify.java
* @run main NegExactLConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NegExactLConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant negExact
* @compile NegExactLNonConstantTest.java Verify.java
* @run main NegExactLNonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NegExactLNonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8027444
* @summary Test nested loops
* @compile NestedMathExactTest.java
* @run main NestedMathExactTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main NestedMathExactTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8028198
* @summary Verify that split through phi does the right thing
* @compile SplitThruPhiTest.java
* @run main SplitThruPhiTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SplitThruPhiTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test subtractExact as condition
* @compile SubExactICondTest.java Verify.java
* @run main SubExactICondTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactICondTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test constant subtractExact
* @compile SubExactIConstantTest.java Verify.java
* @run main SubExactIConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactIConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant subtractExact
* @compile SubExactILoadTest.java Verify.java
* @run main SubExactILoadTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactILoadTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant subtractExact
* @compile SubExactILoopDependentTest.java Verify.java
* @run main SubExactILoopDependentTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactILoopDependentTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test non constant subtractExact
* @compile SubExactINonConstantTest.java Verify.java
* @run main SubExactINonConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactINonConstantTest
*
*/

View File

@ -26,7 +26,7 @@
* @bug 8026844
* @summary Test repeating subtractExact
* @compile SubExactIRepeatTest.java Verify.java
* @run main SubExactIRepeatTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactIRepeatTest
*
*/

View File

@ -27,7 +27,7 @@
* @bug 8027353
* @summary Test constant subtractExact
* @compile SubExactLConstantTest.java Verify.java
* @run main SubExactLConstantTest -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseMathExactIntrinsics
* @run main SubExactLConstantTest
*
*/

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