This commit is contained in:
Roland Westrelin 2014-08-11 13:02:44 +00:00
commit dc1afd4abe
15 changed files with 1790 additions and 1082 deletions

View File

@ -1815,3 +1815,49 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
}
return result;
}
ArrayCopyNode::ArrayCopyNode(Compile* C, bool alloc_tightly_coupled)
: CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM), _alloc_tightly_coupled(alloc_tightly_coupled), _kind(ArrayCopy) {
init_class_id(Class_ArrayCopy);
init_flags(Flag_is_macro);
C->add_macro_node(this);
}
uint ArrayCopyNode::size_of() const { return sizeof(*this); }
ArrayCopyNode* ArrayCopyNode::make(GraphKit* kit, bool may_throw,
Node* src, Node* src_offset, Node* dest, Node* dest_offset, Node* length,
bool alloc_tightly_coupled) {
ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled);
Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac);
ac->init_req( ArrayCopyNode::Src, src);
ac->init_req( ArrayCopyNode::SrcPos, src_offset);
ac->init_req( ArrayCopyNode::Dest, dest);
ac->init_req( ArrayCopyNode::DestPos, dest_offset);
ac->init_req( ArrayCopyNode::Length, length);
if (may_throw) {
ac->set_req(TypeFunc::I_O , kit->i_o());
kit->add_safepoint_edges(ac, false);
}
return ac;
}
void ArrayCopyNode::connect_outputs(GraphKit* kit) {
kit->set_all_memory_call(this, true);
kit->set_control(kit->gvn().transform(new ProjNode(this,TypeFunc::Control)));
kit->set_i_o(kit->gvn().transform(new ProjNode(this, TypeFunc::I_O)));
kit->make_slow_call_ex(this, kit->env()->Throwable_klass(), true);
kit->set_all_memory_call(this);
}
#ifndef PRODUCT
const char* ArrayCopyNode::_kind_names[] = {"arraycopy", "arraycopy, validated arguments", "clone", "oop array clone", "CopyOf", "CopyOfRange"};
void ArrayCopyNode::dump_spec(outputStream *st) const {
CallNode::dump_spec(st);
st->print(" (%s%s)", _kind_names[_kind], _alloc_tightly_coupled ? ", tightly coupled allocation" : "");
}
#endif

View File

@ -1063,4 +1063,96 @@ public:
virtual bool guaranteed_safepoint() { return false; }
};
class GraphKit;
class ArrayCopyNode : public CallNode {
private:
// What kind of arraycopy variant is this?
enum {
ArrayCopy, // System.arraycopy()
ArrayCopyNoTest, // System.arraycopy(), all arguments validated
CloneBasic, // A clone that can be copied by 64 bit chunks
CloneOop, // An oop array clone
CopyOf, // Arrays.copyOf()
CopyOfRange // Arrays.copyOfRange()
} _kind;
#ifndef PRODUCT
static const char* _kind_names[CopyOfRange+1];
#endif
// Is the alloc obtained with
// AllocateArrayNode::Ideal_array_allocation() tighly coupled
// (arraycopy follows immediately the allocation)?
// We cache the result of LibraryCallKit::tightly_coupled_allocation
// here because it's much easier to find whether there's a tightly
// couple allocation at parse time than at macro expansion time. At
// macro expansion time, for every use of the allocation node we
// would need to figure out whether it happens after the arraycopy (and
// can be ignored) or between the allocation and the arraycopy. At
// parse time, it's straightforward because whatever happens after
// the arraycopy is not parsed yet so doesn't exist when
// LibraryCallKit::tightly_coupled_allocation() is called.
bool _alloc_tightly_coupled;
static const TypeFunc* arraycopy_type() {
const Type** fields = TypeTuple::fields(ParmLimit - TypeFunc::Parms);
fields[Src] = TypeInstPtr::BOTTOM;
fields[SrcPos] = TypeInt::INT;
fields[Dest] = TypeInstPtr::BOTTOM;
fields[DestPos] = TypeInt::INT;
fields[Length] = TypeInt::INT;
const TypeTuple *domain = TypeTuple::make(ParmLimit, fields);
// create result type (range)
fields = TypeTuple::fields(0);
const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields);
return TypeFunc::make(domain, range);
}
ArrayCopyNode(Compile* C, bool alloc_tightly_coupled);
public:
enum {
Src = TypeFunc::Parms,
SrcPos,
Dest,
DestPos,
Length,
ParmLimit
};
static ArrayCopyNode* make(GraphKit* kit, bool may_throw,
Node* src, Node* src_offset, Node* dest, Node* dest_offset, Node* length,
bool alloc_tightly_coupled);
void connect_outputs(GraphKit* kit);
bool is_arraycopy() const { return _kind == ArrayCopy; }
bool is_arraycopy_notest() const { return _kind == ArrayCopyNoTest; }
bool is_clonebasic() const { return _kind == CloneBasic; }
bool is_cloneoop() const { return _kind == CloneOop; }
bool is_copyof() const { return _kind == CopyOf; }
bool is_copyofrange() const { return _kind == CopyOfRange; }
void set_arraycopy() { _kind = ArrayCopy; }
void set_arraycopy_notest() { _kind = ArrayCopyNoTest; }
void set_clonebasic() { _kind = CloneBasic; }
void set_cloneoop() { _kind = CloneOop; }
void set_copyof() { _kind = CopyOf; }
void set_copyofrange() { _kind = CopyOfRange; }
virtual int Opcode() const;
virtual uint size_of() const; // Size is bigger
virtual bool guaranteed_safepoint() { return false; }
bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; }
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
#endif
};
#endif // SHARE_VM_OPTO_CALLNODE_HPP

View File

@ -37,6 +37,7 @@ macro(Allocate)
macro(AllocateArray)
macro(AndI)
macro(AndL)
macro(ArrayCopy)
macro(AryEq)
macro(AtanD)
macro(Binary)

View File

@ -3787,6 +3787,56 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n
}
}
//----------------------------static_subtype_check-----------------------------
// Shortcut important common cases when superklass is exact:
// (0) superklass is java.lang.Object (can occur in reflective code)
// (1) subklass is already limited to a subtype of superklass => always ok
// (2) subklass does not overlap with superklass => always fail
// (3) superklass has NO subtypes and we can check with a simple compare.
int Compile::static_subtype_check(ciKlass* superk, ciKlass* subk) {
if (StressReflectiveCode) {
return SSC_full_test; // Let caller generate the general case.
}
if (superk == env()->Object_klass()) {
return SSC_always_true; // (0) this test cannot fail
}
ciType* superelem = superk;
if (superelem->is_array_klass())
superelem = superelem->as_array_klass()->base_element_type();
if (!subk->is_interface()) { // cannot trust static interface types yet
if (subk->is_subtype_of(superk)) {
return SSC_always_true; // (1) false path dead; no dynamic test needed
}
if (!(superelem->is_klass() && superelem->as_klass()->is_interface()) &&
!superk->is_subtype_of(subk)) {
return SSC_always_false;
}
}
// If casting to an instance klass, it must have no subtypes
if (superk->is_interface()) {
// Cannot trust interfaces yet.
// %%% S.B. superk->nof_implementors() == 1
} else if (superelem->is_instance_klass()) {
ciInstanceKlass* ik = superelem->as_instance_klass();
if (!ik->has_subklass() && !ik->is_interface()) {
if (!ik->is_final()) {
// Add a dependency if there is a chance of a later subclass.
dependencies()->assert_leaf_type(ik);
}
return SSC_easy_test; // (3) caller can do a simple ptr comparison
}
} else {
// A primitive array type has no subtypes.
return SSC_easy_test; // (3) caller can do a simple ptr comparison
}
return SSC_full_test;
}
// The message about the current inlining is accumulated in
// _print_inlining_stream and transfered into the _print_inlining_list
// once we know whether inlining succeeds or not. For regular

View File

@ -1200,6 +1200,10 @@ class Compile : public Phase {
// Definitions of pd methods
static void pd_compiler2_init();
// Static parse-time type checking logic for gen_subtype_check:
enum { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test };
int static_subtype_check(ciKlass* superk, ciKlass* subk);
// Auxiliary method for randomized fuzzing/stressing
static bool randomized_select(int count);
};

View File

@ -2520,6 +2520,21 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep
set_control(norm);
}
static IfNode* gen_subtype_check_compare(Node* ctrl, Node* in1, Node* in2, BoolTest::mask test, float p, PhaseGVN* gvn, BasicType bt) {
Node* cmp = NULL;
switch(bt) {
case T_INT: cmp = new CmpINode(in1, in2); break;
case T_ADDRESS: cmp = new CmpPNode(in1, in2); break;
default: fatal(err_msg("unexpected comparison type %s", type2name(bt)));
}
gvn->transform(cmp);
Node* bol = gvn->transform(new BoolNode(cmp, test));
IfNode* iff = new IfNode(ctrl, bol, p, COUNT_UNKNOWN);
gvn->transform(iff);
if (!bol->is_Con()) gvn->record_for_igvn(iff);
return iff;
}
//-------------------------------gen_subtype_check-----------------------------
// Generate a subtyping check. Takes as input the subtype and supertype.
@ -2529,16 +2544,17 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep
// but that's not exposed to the optimizer. This call also doesn't take in an
// Object; if you wish to check an Object you need to load the Object's class
// prior to coming here.
Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) {
Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn) {
Compile* C = gvn->C;
// Fast check for identical types, perhaps identical constants.
// The types can even be identical non-constants, in cases
// involving Array.newInstance, Object.clone, etc.
if (subklass == superklass)
return top(); // false path is dead; no test needed.
return C->top(); // false path is dead; no test needed.
if (_gvn.type(superklass)->singleton()) {
ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass();
ciKlass* subk = _gvn.type(subklass)->is_klassptr()->klass();
if (gvn->type(superklass)->singleton()) {
ciKlass* superk = gvn->type(superklass)->is_klassptr()->klass();
ciKlass* subk = gvn->type(subklass)->is_klassptr()->klass();
// In the common case of an exact superklass, try to fold up the
// test before generating code. You may ask, why not just generate
@ -2549,25 +2565,23 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) {
// Foo[] fa = blah(); Foo x = fa[0]; fa[1] = x;
// Here, the type of 'fa' is often exact, so the store check
// of fa[1]=x will fold up, without testing the nullness of x.
switch (static_subtype_check(superk, subk)) {
case SSC_always_false:
switch (C->static_subtype_check(superk, subk)) {
case Compile::SSC_always_false:
{
Node* always_fail = control();
set_control(top());
Node* always_fail = *ctrl;
*ctrl = gvn->C->top();
return always_fail;
}
case SSC_always_true:
return top();
case SSC_easy_test:
case Compile::SSC_always_true:
return C->top();
case Compile::SSC_easy_test:
{
// Just do a direct pointer compare and be done.
Node* cmp = _gvn.transform( new CmpPNode(subklass, superklass) );
Node* bol = _gvn.transform( new BoolNode(cmp, BoolTest::eq) );
IfNode* iff = create_and_xform_if(control(), bol, PROB_STATIC_FREQUENT, COUNT_UNKNOWN);
set_control( _gvn.transform( new IfTrueNode (iff) ) );
return _gvn.transform( new IfFalseNode(iff) );
IfNode* iff = gen_subtype_check_compare(*ctrl, subklass, superklass, BoolTest::eq, PROB_STATIC_FREQUENT, gvn, T_ADDRESS);
*ctrl = gvn->transform(new IfTrueNode(iff));
return gvn->transform(new IfFalseNode(iff));
}
case SSC_full_test:
case Compile::SSC_full_test:
break;
default:
ShouldNotReachHere();
@ -2579,11 +2593,11 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) {
// will always succeed. We could leave a dependency behind to ensure this.
// First load the super-klass's check-offset
Node *p1 = basic_plus_adr( superklass, superklass, in_bytes(Klass::super_check_offset_offset()) );
Node *chk_off = _gvn.transform(new LoadINode(NULL, memory(p1), p1, _gvn.type(p1)->is_ptr(),
TypeInt::INT, MemNode::unordered));
Node *p1 = gvn->transform(new AddPNode(superklass, superklass, gvn->MakeConX(in_bytes(Klass::super_check_offset_offset()))));
Node* m = mem->memory_at(C->get_alias_index(gvn->type(p1)->is_ptr()));
Node *chk_off = gvn->transform(new LoadINode(NULL, m, p1, gvn->type(p1)->is_ptr(), TypeInt::INT, MemNode::unordered));
int cacheoff_con = in_bytes(Klass::secondary_super_cache_offset());
bool might_be_cache = (find_int_con(chk_off, cacheoff_con) == cacheoff_con);
bool might_be_cache = (gvn->find_int_con(chk_off, cacheoff_con) == cacheoff_con);
// Load from the sub-klass's super-class display list, or a 1-word cache of
// the secondary superclass list, or a failing value with a sentinel offset
@ -2591,42 +2605,44 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) {
// hierarchy and we have to scan the secondary superclass list the hard way.
// Worst-case type is a little odd: NULL is allowed as a result (usually
// klass loads can never produce a NULL).
Node *chk_off_X = ConvI2X(chk_off);
Node *p2 = _gvn.transform( new AddPNode(subklass,subklass,chk_off_X) );
Node *chk_off_X = chk_off;
#ifdef _LP64
chk_off_X = gvn->transform(new ConvI2LNode(chk_off_X));
#endif
Node *p2 = gvn->transform(new AddPNode(subklass,subklass,chk_off_X));
// For some types like interfaces the following loadKlass is from a 1-word
// cache which is mutable so can't use immutable memory. Other
// types load from the super-class display table which is immutable.
Node *kmem = might_be_cache ? memory(p2) : immutable_memory();
Node *nkls = _gvn.transform( LoadKlassNode::make( _gvn, kmem, p2, _gvn.type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL ) );
m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr()));
Node *kmem = might_be_cache ? m : C->immutable_memory();
Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
// Compile speed common case: ARE a subtype and we canNOT fail
if( superklass == nkls )
return top(); // false path is dead; no test needed.
return C->top(); // false path is dead; no test needed.
// See if we get an immediate positive hit. Happens roughly 83% of the
// time. Test to see if the value loaded just previously from the subklass
// is exactly the superklass.
Node *cmp1 = _gvn.transform( new CmpPNode( superklass, nkls ) );
Node *bol1 = _gvn.transform( new BoolNode( cmp1, BoolTest::eq ) );
IfNode *iff1 = create_and_xform_if( control(), bol1, PROB_LIKELY(0.83f), COUNT_UNKNOWN );
Node *iftrue1 = _gvn.transform( new IfTrueNode ( iff1 ) );
set_control( _gvn.transform( new IfFalseNode( iff1 ) ) );
IfNode *iff1 = gen_subtype_check_compare(*ctrl, superklass, nkls, BoolTest::eq, PROB_LIKELY(0.83f), gvn, T_ADDRESS);
Node *iftrue1 = gvn->transform( new IfTrueNode (iff1));
*ctrl = gvn->transform(new IfFalseNode(iff1));
// Compile speed common case: Check for being deterministic right now. If
// chk_off is a constant and not equal to cacheoff then we are NOT a
// subklass. In this case we need exactly the 1 test above and we can
// return those results immediately.
if (!might_be_cache) {
Node* not_subtype_ctrl = control();
set_control(iftrue1); // We need exactly the 1 test above
Node* not_subtype_ctrl = *ctrl;
*ctrl = iftrue1; // We need exactly the 1 test above
return not_subtype_ctrl;
}
// Gather the various success & failures here
RegionNode *r_ok_subtype = new RegionNode(4);
record_for_igvn(r_ok_subtype);
gvn->record_for_igvn(r_ok_subtype);
RegionNode *r_not_subtype = new RegionNode(3);
record_for_igvn(r_not_subtype);
gvn->record_for_igvn(r_not_subtype);
r_ok_subtype->init_req(1, iftrue1);
@ -2635,21 +2651,17 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) {
// check-offset points into the subklass display list or the 1-element
// cache. If it points to the display (and NOT the cache) and the display
// missed then it's not a subtype.
Node *cacheoff = _gvn.intcon(cacheoff_con);
Node *cmp2 = _gvn.transform( new CmpINode( chk_off, cacheoff ) );
Node *bol2 = _gvn.transform( new BoolNode( cmp2, BoolTest::ne ) );
IfNode *iff2 = create_and_xform_if( control(), bol2, PROB_LIKELY(0.63f), COUNT_UNKNOWN );
r_not_subtype->init_req(1, _gvn.transform( new IfTrueNode (iff2) ) );
set_control( _gvn.transform( new IfFalseNode(iff2) ) );
Node *cacheoff = gvn->intcon(cacheoff_con);
IfNode *iff2 = gen_subtype_check_compare(*ctrl, chk_off, cacheoff, BoolTest::ne, PROB_LIKELY(0.63f), gvn, T_INT);
r_not_subtype->init_req(1, gvn->transform(new IfTrueNode (iff2)));
*ctrl = gvn->transform(new IfFalseNode(iff2));
// Check for self. Very rare to get here, but it is taken 1/3 the time.
// No performance impact (too rare) but allows sharing of secondary arrays
// which has some footprint reduction.
Node *cmp3 = _gvn.transform( new CmpPNode( subklass, superklass ) );
Node *bol3 = _gvn.transform( new BoolNode( cmp3, BoolTest::eq ) );
IfNode *iff3 = create_and_xform_if( control(), bol3, PROB_LIKELY(0.36f), COUNT_UNKNOWN );
r_ok_subtype->init_req(2, _gvn.transform( new IfTrueNode ( iff3 ) ) );
set_control( _gvn.transform( new IfFalseNode( iff3 ) ) );
IfNode *iff3 = gen_subtype_check_compare(*ctrl, subklass, superklass, BoolTest::eq, PROB_LIKELY(0.36f), gvn, T_ADDRESS);
r_ok_subtype->init_req(2, gvn->transform(new IfTrueNode(iff3)));
*ctrl = gvn->transform(new IfFalseNode(iff3));
// -- Roads not taken here: --
// We could also have chosen to perform the self-check at the beginning
@ -2672,68 +2684,16 @@ Node* GraphKit::gen_subtype_check(Node* subklass, Node* superklass) {
// out of line, and it can only improve I-cache density.
// The decision to inline or out-of-line this final check is platform
// dependent, and is found in the AD file definition of PartialSubtypeCheck.
Node* psc = _gvn.transform(
new PartialSubtypeCheckNode(control(), subklass, superklass) );
Node* psc = gvn->transform(
new PartialSubtypeCheckNode(*ctrl, subklass, superklass));
Node *cmp4 = _gvn.transform( new CmpPNode( psc, null() ) );
Node *bol4 = _gvn.transform( new BoolNode( cmp4, BoolTest::ne ) );
IfNode *iff4 = create_and_xform_if( control(), bol4, PROB_FAIR, COUNT_UNKNOWN );
r_not_subtype->init_req(2, _gvn.transform( new IfTrueNode (iff4) ) );
r_ok_subtype ->init_req(3, _gvn.transform( new IfFalseNode(iff4) ) );
IfNode *iff4 = gen_subtype_check_compare(*ctrl, psc, gvn->zerocon(T_OBJECT), BoolTest::ne, PROB_FAIR, gvn, T_ADDRESS);
r_not_subtype->init_req(2, gvn->transform(new IfTrueNode (iff4)));
r_ok_subtype ->init_req(3, gvn->transform(new IfFalseNode(iff4)));
// Return false path; set default control to true path.
set_control( _gvn.transform(r_ok_subtype) );
return _gvn.transform(r_not_subtype);
}
//----------------------------static_subtype_check-----------------------------
// Shortcut important common cases when superklass is exact:
// (0) superklass is java.lang.Object (can occur in reflective code)
// (1) subklass is already limited to a subtype of superklass => always ok
// (2) subklass does not overlap with superklass => always fail
// (3) superklass has NO subtypes and we can check with a simple compare.
int GraphKit::static_subtype_check(ciKlass* superk, ciKlass* subk) {
if (StressReflectiveCode) {
return SSC_full_test; // Let caller generate the general case.
}
if (superk == env()->Object_klass()) {
return SSC_always_true; // (0) this test cannot fail
}
ciType* superelem = superk;
if (superelem->is_array_klass())
superelem = superelem->as_array_klass()->base_element_type();
if (!subk->is_interface()) { // cannot trust static interface types yet
if (subk->is_subtype_of(superk)) {
return SSC_always_true; // (1) false path dead; no dynamic test needed
}
if (!(superelem->is_klass() && superelem->as_klass()->is_interface()) &&
!superk->is_subtype_of(subk)) {
return SSC_always_false;
}
}
// If casting to an instance klass, it must have no subtypes
if (superk->is_interface()) {
// Cannot trust interfaces yet.
// %%% S.B. superk->nof_implementors() == 1
} else if (superelem->is_instance_klass()) {
ciInstanceKlass* ik = superelem->as_instance_klass();
if (!ik->has_subklass() && !ik->is_interface()) {
if (!ik->is_final()) {
// Add a dependency if there is a chance of a later subclass.
C->dependencies()->assert_leaf_type(ik);
}
return SSC_easy_test; // (3) caller can do a simple ptr comparison
}
} else {
// A primitive array type has no subtypes.
return SSC_easy_test; // (3) caller can do a simple ptr comparison
}
return SSC_full_test;
*ctrl = gvn->transform(r_ok_subtype);
return gvn->transform(r_not_subtype);
}
// Profile-driven exact type check:
@ -2813,7 +2773,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass;
if (exact_kls != NULL) {// no cast failures here
if (require_klass == NULL ||
static_subtype_check(require_klass, exact_kls) == SSC_always_true) {
C->static_subtype_check(require_klass, exact_kls) == Compile::SSC_always_true) {
// If we narrow the type to match what the type profile sees or
// the speculative type, we can then remove the rest of the
// cast.
@ -2833,7 +2793,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
}
return exact_obj;
}
// assert(ssc == SSC_always_true)... except maybe the profile lied to us.
// assert(ssc == Compile::SSC_always_true)... except maybe the profile lied to us.
}
return NULL;
@ -2938,8 +2898,8 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass();
ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass();
if (subk != NULL && subk->is_loaded()) {
int static_res = static_subtype_check(superk, subk);
known_statically = (static_res == SSC_always_true || static_res == SSC_always_false);
int static_res = C->static_subtype_check(superk, subk);
known_statically = (static_res == Compile::SSC_always_true || static_res == Compile::SSC_always_false);
}
}
@ -3007,13 +2967,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
if (tk->singleton()) {
const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr();
if (objtp != NULL && objtp->klass() != NULL) {
switch (static_subtype_check(tk->klass(), objtp->klass())) {
case SSC_always_true:
switch (C->static_subtype_check(tk->klass(), objtp->klass())) {
case Compile::SSC_always_true:
// If we know the type check always succeed 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.
return record_profiled_receiver_for_speculation(obj);
case SSC_always_false:
case Compile::SSC_always_false:
// It needs a null check because a null will *pass* the cast check.
// A non-null value will always produce an exception.
return null_assert(obj);

View File

@ -829,17 +829,13 @@ class GraphKit : public Phase {
Node* gen_checkcast( Node *subobj, Node* superkls,
Node* *failure_control = NULL );
// Generate a subtyping check. Takes as input the subtype and supertype.
// Returns 2 values: sets the default control() to the true path and
// returns the false path. Only reads from constant memory taken from the
// default memory; does not write anything. It also doesn't take in an
// Object; if you wish to check an Object you need to load the Object's
// class prior to coming here.
Node* gen_subtype_check(Node* subklass, Node* superklass);
// Static parse-time type checking logic for gen_subtype_check:
enum { SSC_always_false, SSC_always_true, SSC_easy_test, SSC_full_test };
int static_subtype_check(ciKlass* superk, ciKlass* subk);
Node* gen_subtype_check(Node* subklass, Node* superklass) {
MergeMemNode* mem = merged_memory();
Node* ctrl = control();
Node* n = Phase::gen_subtype_check(subklass, superklass, &ctrl, mem, &_gvn);
set_control(ctrl);
return n;
}
// Exact type check used for predicted calls and casts.
// Rewrites (*casted_receiver) to be casted to the stronger type.

File diff suppressed because it is too large Load Diff

View File

@ -763,9 +763,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
loop->dump_head();
}
#endif
} else if ((cl != NULL) && (proj->_con == predicate_proj->_con) &&
loop->is_range_check_if(iff, this, invar)) {
} else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) {
// Range check for counted loops
const Node* cmp = bol->in(1)->as_Cmp();
Node* idx = cmp->in(1);
@ -800,18 +798,31 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
}
// Test the lower bound
Node* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false);
BoolNode* lower_bound_bol = rc_predicate(loop, ctrl, scale, offset, init, limit, stride, rng, false);
// Negate test if necessary
bool negated = false;
if (proj->_con != predicate_proj->_con) {
lower_bound_bol = new BoolNode(lower_bound_bol->in(1), lower_bound_bol->_test.negate());
register_new_node(lower_bound_bol, ctrl);
negated = true;
}
IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
_igvn.hash_delete(lower_bound_iff);
lower_bound_iff->set_req(1, lower_bound_bol);
if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
if (TraceLoopPredicate) tty->print_cr("lower bound check if: %s %d ", negated ? " negated" : "", lower_bound_iff->_idx);
// Test the upper bound
Node* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true);
BoolNode* upper_bound_bol = rc_predicate(loop, lower_bound_proj, scale, offset, init, limit, stride, rng, true);
negated = false;
if (proj->_con != predicate_proj->_con) {
upper_bound_bol = new BoolNode(upper_bound_bol->in(1), upper_bound_bol->_test.negate());
register_new_node(upper_bound_bol, ctrl);
negated = true;
}
IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
_igvn.hash_delete(upper_bound_iff);
upper_bound_iff->set_req(1, upper_bound_bol);
if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx);
if (TraceLoopPredicate) tty->print_cr("upper bound check if: %s %d ", negated ? " negated" : "", lower_bound_iff->_idx);
// Fall through into rest of the clean up code which will move
// any dependent nodes onto the upper bound test.

View File

@ -2469,6 +2469,8 @@ void PhaseMacroExpand::eliminate_macro_nodes() {
assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
_has_locks = true;
break;
case Node::Class_ArrayCopy:
break;
default:
assert(n->Opcode() == Op_LoopLimit ||
n->Opcode() == Op_Opaque1 ||
@ -2544,6 +2546,25 @@ bool PhaseMacroExpand::expand_macro_nodes() {
}
}
// expand arraycopy "macro" nodes first
// For ReduceBulkZeroing, we must first process all arraycopy nodes
// before the allocate nodes are expanded.
int macro_idx = C->macro_count() - 1;
while (macro_idx >= 0) {
Node * n = C->macro_node(macro_idx);
assert(n->is_macro(), "only macro nodes expected here");
if (_igvn.type(n) == Type::TOP || n->in(0)->is_top() ) {
// node is unreachable, so don't try to expand it
C->remove_macro_node(n);
} else if (n->is_ArrayCopy()){
int macro_count = C->macro_count();
expand_arraycopy_node(n->as_ArrayCopy());
assert(C->macro_count() < macro_count, "must have deleted a node from macro list");
}
if (C->failing()) return true;
macro_idx --;
}
// expand "macro" nodes
// nodes are removed from the macro list as they are processed
while (C->macro_count() > 0) {

View File

@ -37,7 +37,7 @@ class PhaseMacroExpand : public Phase {
private:
PhaseIterGVN &_igvn;
// Helper methods roughly modelled after GraphKit:
// Helper methods roughly modeled after GraphKit:
Node* top() const { return C->top(); }
Node* intcon(jint con) const { return _igvn.intcon(con); }
Node* longcon(jlong con) const { return _igvn.longcon(con); }
@ -101,6 +101,86 @@ private:
void expand_lock_node(LockNode *lock);
void expand_unlock_node(UnlockNode *unlock);
// More helper methods modeled after GraphKit for array copy
void insert_mem_bar(Node** ctrl, Node** mem, int opcode, Node* precedent = NULL);
Node* array_element_address(Node* ary, Node* idx, BasicType elembt);
Node* ConvI2L(Node* offset);
Node* make_leaf_call(Node* ctrl, Node* mem,
const TypeFunc* call_type, address call_addr,
const char* call_name,
const TypePtr* adr_type,
Node* parm0 = NULL, Node* parm1 = NULL,
Node* parm2 = NULL, Node* parm3 = NULL,
Node* parm4 = NULL, Node* parm5 = NULL,
Node* parm6 = NULL, Node* parm7 = NULL);
// helper methods modeled after LibraryCallKit for array copy
Node* generate_guard(Node** ctrl, Node* test, RegionNode* region, float true_prob);
Node* generate_slow_guard(Node** ctrl, Node* test, RegionNode* region);
void generate_negative_guard(Node** ctrl, Node* index, RegionNode* region);
void generate_limit_guard(Node** ctrl, Node* offset, Node* subseq_length, Node* array_length, RegionNode* region);
// More helper methods for array copy
Node* generate_nonpositive_guard(Node** ctrl, Node* index, bool never_negative);
void finish_arraycopy_call(Node* call, Node** ctrl, MergeMemNode** mem, const TypePtr* adr_type);
address basictype2arraycopy(BasicType t,
Node* src_offset,
Node* dest_offset,
bool disjoint_bases,
const char* &name,
bool dest_uninitialized);
Node* generate_arraycopy(ArrayCopyNode *ac,
AllocateArrayNode* alloc,
Node** ctrl, MergeMemNode* mem, Node** io,
const TypePtr* adr_type,
BasicType basic_elem_type,
Node* src, Node* src_offset,
Node* dest, Node* dest_offset,
Node* copy_length,
bool disjoint_bases = false,
bool length_never_negative = false,
RegionNode* slow_region = NULL);
void generate_clear_array(Node* ctrl, MergeMemNode* merge_mem,
const TypePtr* adr_type,
Node* dest,
BasicType basic_elem_type,
Node* slice_idx,
Node* slice_len,
Node* dest_size);
bool generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* io,
const TypePtr* adr_type,
BasicType basic_elem_type,
AllocateNode* alloc,
Node* src, Node* src_offset,
Node* dest, Node* dest_offset,
Node* dest_size, bool dest_uninitialized);
MergeMemNode* generate_slow_arraycopy(ArrayCopyNode *ac,
Node** ctrl, Node* mem, Node** io,
const TypePtr* adr_type,
Node* src, Node* src_offset,
Node* dest, Node* dest_offset,
Node* copy_length, bool dest_uninitialized);
Node* generate_checkcast_arraycopy(Node** ctrl, MergeMemNode** mem,
const TypePtr* adr_type,
Node* dest_elem_klass,
Node* src, Node* src_offset,
Node* dest, Node* dest_offset,
Node* copy_length, bool dest_uninitialized);
Node* generate_generic_arraycopy(Node** ctrl, MergeMemNode** mem,
const TypePtr* adr_type,
Node* src, Node* src_offset,
Node* dest, Node* dest_offset,
Node* copy_length, bool dest_uninitialized);
void generate_unchecked_arraycopy(Node** ctrl, MergeMemNode** mem,
const TypePtr* adr_type,
BasicType basic_elem_type,
bool disjoint_bases,
Node* src, Node* src_offset,
Node* dest, Node* dest_offset,
Node* copy_length, bool dest_uninitialized);
void expand_arraycopy_node(ArrayCopyNode *ac);
int replace_input(Node *use, Node *oldref, Node *newref);
void copy_call_debug_info(CallNode *oldcall, CallNode * newcall);
Node* opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path = false);

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@ class AddPNode;
class AliasInfo;
class AllocateArrayNode;
class AllocateNode;
class ArrayCopyNode;
class Block;
class BoolNode;
class BoxLockNode;
@ -561,6 +562,7 @@ public:
DEFINE_CLASS_ID(AbstractLock, Call, 3)
DEFINE_CLASS_ID(Lock, AbstractLock, 0)
DEFINE_CLASS_ID(Unlock, AbstractLock, 1)
DEFINE_CLASS_ID(ArrayCopy, Call, 4)
DEFINE_CLASS_ID(MultiBranch, Multi, 1)
DEFINE_CLASS_ID(PCTable, MultiBranch, 0)
DEFINE_CLASS_ID(Catch, PCTable, 0)
@ -707,6 +709,7 @@ public:
DEFINE_CLASS_QUERY(AddP)
DEFINE_CLASS_QUERY(Allocate)
DEFINE_CLASS_QUERY(AllocateArray)
DEFINE_CLASS_QUERY(ArrayCopy)
DEFINE_CLASS_QUERY(Bool)
DEFINE_CLASS_QUERY(BoxLock)
DEFINE_CLASS_QUERY(Call)

View File

@ -27,7 +27,10 @@
#include "runtime/timer.hpp"
class Compile;
class IfNode;
class MergeMemNode;
class Node;
class PhaseGVN;
//------------------------------Phase------------------------------------------
// Most optimizations are done in Phases. Creating a phase does any long
@ -114,9 +117,20 @@ protected:
static elapsedTimer _t_instrSched;
static elapsedTimer _t_buildOopMaps;
#endif
// Generate a subtyping check. Takes as input the subtype and supertype.
// Returns 2 values: sets the default control() to the true path and
// returns the false path. Only reads from constant memory taken from the
// default memory; does not write anything. It also doesn't take in an
// Object; if you wish to check an Object you need to load the Object's
// class prior to coming here.
// Used in GraphKit and PhaseMacroExpand
static Node* gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, MergeMemNode* mem, PhaseGVN* gvn);
public:
Compile * C;
Phase( PhaseNumber pnum );
#ifndef PRODUCT
static void print_timers();
#endif

View File

@ -390,6 +390,9 @@ public:
// in a faster or cheaper fashion.
Node *transform( Node *n );
Node *transform_no_reclaim( Node *n );
virtual void record_for_igvn(Node *n) {
C->record_for_igvn(n);
}
void replace_with(PhaseGVN* gvn) {
_table.replace_with(&gvn->_table);
@ -418,9 +421,6 @@ class PhaseIterGVN : public PhaseGVN {
protected:
// Idealize new Node 'n' with respect to its inputs and its value
virtual Node *transform( Node *a_node );
// Warm up hash table, type table and initial worklist
void init_worklist( Node *a_root );
@ -434,6 +434,10 @@ public:
PhaseIterGVN( PhaseGVN *gvn ); // Used after Parser
PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ); // Used after +VerifyOpto
// Idealize new Node 'n' with respect to its inputs and its value
virtual Node *transform( Node *a_node );
virtual void record_for_igvn(Node *n) { }
virtual PhaseIterGVN *is_IterGVN() { return this; }
Unique_Node_List _worklist; // Iterative worklist