提交 781f1412 编写于 作者: K kvn

6695810: null oop passed to encode_heap_oop_not_null

Summary: fix several problems in C2 related to Escape Analysis and Compressed Oops.
Reviewed-by: never, jrose
上级 23466ea5
......@@ -5471,7 +5471,7 @@ instruct loadN(iRegN dst, memory mem) %{
// Load Klass Pointer
instruct loadKlass(iRegP dst, memory mem) %{
match(Set dst (LoadKlass mem));
predicate(!n->in(MemNode::Address)->bottom_type()->is_narrow());
predicate(!n->in(MemNode::Address)->bottom_type()->is_ptr_to_narrowoop());
ins_cost(MEMORY_REF_COST);
size(4);
......@@ -5489,7 +5489,7 @@ instruct loadKlass(iRegP dst, memory mem) %{
// Load Klass Pointer
instruct loadKlassComp(iRegP dst, memory mem) %{
match(Set dst (LoadKlass mem));
predicate(n->in(MemNode::Address)->bottom_type()->is_narrow());
predicate(n->in(MemNode::Address)->bottom_type()->is_ptr_to_narrowoop());
ins_cost(MEMORY_REF_COST);
format %{ "LDUW $mem,$dst\t! compressed klass ptr" %}
......
......@@ -6044,10 +6044,9 @@ instruct loadP(rRegP dst, memory mem)
%}
// Load Compressed Pointer
instruct loadN(rRegN dst, memory mem, rFlagsReg cr)
instruct loadN(rRegN dst, memory mem)
%{
match(Set dst (LoadN mem));
effect(KILL cr);
ins_cost(125); // XXX
format %{ "movl $dst, $mem\t# compressed ptr" %}
......@@ -6064,7 +6063,7 @@ instruct loadN(rRegN dst, memory mem, rFlagsReg cr)
instruct loadKlass(rRegP dst, memory mem)
%{
match(Set dst (LoadKlass mem));
predicate(!n->in(MemNode::Address)->bottom_type()->is_narrow());
predicate(!n->in(MemNode::Address)->bottom_type()->is_ptr_to_narrowoop());
ins_cost(125); // XXX
format %{ "movq $dst, $mem\t# class" %}
......@@ -6074,10 +6073,11 @@ instruct loadKlass(rRegP dst, memory mem)
%}
// Load Klass Pointer
instruct loadKlassComp(rRegP dst, memory mem)
instruct loadKlassComp(rRegP dst, memory mem, rFlagsReg cr)
%{
match(Set dst (LoadKlass mem));
predicate(n->in(MemNode::Address)->bottom_type()->is_narrow());
predicate(n->in(MemNode::Address)->bottom_type()->is_ptr_to_narrowoop());
effect(KILL cr);
ins_cost(125); // XXX
format %{ "movl $dst, $mem\t# compressed class\n\t"
......@@ -6358,8 +6358,9 @@ instruct loadConN0(rRegN dst, immN0 src, rFlagsReg cr) %{
ins_pipe(ialu_reg);
%}
instruct loadConN(rRegN dst, immN src) %{
instruct loadConN(rRegN dst, immN src, rFlagsReg cr) %{
match(Set dst src);
effect(KILL cr);
ins_cost(125);
format %{ "movq $dst, $src\t# compressed ptr\n\t"
......@@ -6633,10 +6634,9 @@ instruct storeImmP(memory mem, immP31 src)
%}
// Store Compressed Pointer
instruct storeN(memory mem, rRegN src, rFlagsReg cr)
instruct storeN(memory mem, rRegN src)
%{
match(Set mem (StoreN mem src));
effect(KILL cr);
ins_cost(125); // XXX
format %{ "movl $mem, $src\t# ptr" %}
......
......@@ -637,7 +637,7 @@ bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
}
Compile *C = phase->C;
int offset = adrInst_t->offset();
assert(offset >= 0, "should be valid offset");
assert(adrInst_t->klass_is_exact() && offset >= 0, "should be valid offset");
ciKlass* adr_k = adrInst_t->klass();
assert(adr_k->is_loaded() &&
adr_k->is_java_klass() &&
......@@ -674,12 +674,11 @@ bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
ciKlass* at_k = at_ptr->klass();
if ((adrInst_t->base() == at_ptr->base()) &&
at_k->is_loaded() &&
at_k->is_java_klass() &&
!at_k->is_interface()) {
at_k->is_java_klass()) {
// If we have found an argument matching addr_t, check if the field
// at the specified offset is modified.
int at_idx = C->get_alias_index(at_ptr->add_offset(offset)->isa_oopptr());
if (base_idx == at_idx &&
if ((at_k->is_interface() || adr_k == at_k ||
adr_k->is_subclass_of(at_k) && !at_ptr->klass_is_exact()) &&
(bcea == NULL ||
bcea->is_arg_modified(i - TypeFunc::Parms, offset, size))) {
return true;
......
......@@ -707,8 +707,14 @@ PhiNode* PhiNode::slice_memory(const TypePtr* adr_type) const {
//------------------------split_out_instance-----------------------------------
// Split out an instance type from a bottom phi.
PhiNode* PhiNode::split_out_instance(const TypePtr* at, PhaseIterGVN *igvn) const {
assert(type() == Type::MEMORY && (adr_type() == TypePtr::BOTTOM ||
adr_type() == TypeRawPtr::BOTTOM) , "bottom or raw memory required");
const TypeOopPtr *t_oop = at->isa_oopptr();
assert(t_oop != NULL && t_oop->is_instance(), "expecting instance oopptr");
const TypePtr *t = adr_type();
assert(type() == Type::MEMORY &&
(t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
t->isa_oopptr() && !t->is_oopptr()->is_instance() &&
t->is_oopptr()->cast_to_instance(t_oop->instance_id()) == t_oop),
"bottom or raw memory required");
// Check if an appropriate node already exists.
Node *region = in(0);
......@@ -1342,7 +1348,7 @@ static Node* split_flow_path(PhaseGVN *phase, PhiNode *phi) {
Node *n = phi->in(i);
if( !n ) return NULL;
if( phase->type(n) == Type::TOP ) return NULL;
if( n->Opcode() == Op_ConP )
if( n->Opcode() == Op_ConP || n->Opcode() == Op_ConN )
break;
}
if( i >= phi->req() ) // Only split for constants
......
......@@ -368,7 +368,12 @@ void Compile::init_scratch_buffer_blob() {
BufferBlob* blob = BufferBlob::create("Compile::scratch_buffer", size);
// Record the buffer blob for next time.
set_scratch_buffer_blob(blob);
guarantee(scratch_buffer_blob() != NULL, "Need BufferBlob for code generation");
// Have we run out of code space?
if (scratch_buffer_blob() == NULL) {
// Let CompilerBroker disable further compilations.
record_failure("Not enough space for scratch buffer in CodeCache");
return;
}
// Initialize the relocation buffers
relocInfo* locs_buf = (relocInfo*) blob->instructions_end() - MAX_locs_size;
......@@ -1065,6 +1070,8 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
// No constant oop pointers (such as Strings); they alias with
// unknown strings.
tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
} else if( to->is_instance_field() ) {
tj = to; // Keep NotNull and klass_is_exact for instance type
} else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) {
// During the 2nd round of IterGVN, NotNull castings are removed.
// Make sure the Bottom and NotNull variants alias the same.
......@@ -1084,7 +1091,7 @@ const TypePtr *Compile::flatten_alias_type( const TypePtr *tj ) const {
} else {
ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
if (!k->equals(canonical_holder) || tj->offset() != offset) {
tj = to = TypeInstPtr::make(TypePtr::BotPTR, canonical_holder, false, NULL, offset, to->instance_id());
tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset, to->instance_id());
}
}
}
......
......@@ -578,8 +578,11 @@ Node* DecodeNNode::decode(PhaseGVN* phase, Node* value) {
const Type* newtype = value->bottom_type();
if (newtype == TypeNarrowOop::NULL_PTR) {
return phase->transform(new (phase->C, 1) ConPNode(TypePtr::NULL_PTR));
} else {
} else if (newtype->isa_narrowoop()) {
return phase->transform(new (phase->C, 2) DecodeNNode(value, newtype->is_narrowoop()->make_oopptr()));
} else {
ShouldNotReachHere();
return NULL; // to make C++ compiler happy.
}
}
......@@ -617,6 +620,9 @@ Node* EncodePNode::encode(PhaseGVN* phase, Node* value) {
}
}
Node *EncodePNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1));
}
//=============================================================================
//------------------------------Identity---------------------------------------
......
......@@ -283,6 +283,7 @@ class EncodePNode : public TypeNode {
virtual uint ideal_reg() const { return Op_RegN; }
static Node* encode(PhaseGVN* phase, Node* value);
virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp );
};
//------------------------------DecodeN--------------------------------
......
......@@ -888,6 +888,23 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
record_for_optimizer(n);
if (alloc->is_Allocate() && ptn->_scalar_replaceable &&
(t->isa_instptr() || t->isa_aryptr())) {
// First, put on the worklist all Field edges from Connection Graph
// which is more accurate then putting immediate users from Ideal Graph.
for (uint e = 0; e < ptn->edge_count(); e++) {
Node *use = _nodes->adr_at(ptn->edge_target(e))->_node;
assert(ptn->edge_type(e) == PointsToNode::FieldEdge && use->is_AddP(),
"only AddP nodes are Field edges in CG");
if (use->outcnt() > 0) { // Don't process dead nodes
Node* addp2 = find_second_addp(use, use->in(AddPNode::Base));
if (addp2 != NULL) {
assert(alloc->is_AllocateArray(),"array allocation was expected");
alloc_worklist.append_if_missing(addp2);
}
alloc_worklist.append_if_missing(use);
}
}
// An allocation may have an Initialize which has raw stores. Scan
// the users of the raw allocation result and push AddP users
// on alloc_worklist.
......@@ -919,6 +936,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
tinst = igvn->type(base)->isa_oopptr();
} else if (n->is_Phi() ||
n->is_CheckCastPP() ||
n->Opcode() == Op_EncodeP ||
n->Opcode() == Op_DecodeN ||
(n->is_ConstraintCast() && n->Opcode() == Op_CastPP)) {
if (visited.test_set(n->_idx)) {
assert(n->is_Phi(), "loops only through Phi's");
......@@ -935,13 +954,25 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
tinst = igvn->type(val)->isa_oopptr();
assert(tinst != NULL && tinst->is_instance() &&
tinst->instance_id() == elem , "instance type expected.");
const TypeOopPtr *tn_t = igvn->type(tn)->isa_oopptr();
const TypeOopPtr *tn_t = NULL;
const Type *tn_type = igvn->type(tn);
if (tn_type->isa_narrowoop()) {
tn_t = tn_type->is_narrowoop()->make_oopptr()->isa_oopptr();
} else {
tn_t = tn_type->isa_oopptr();
}
if (tn_t != NULL &&
tinst->cast_to_instance(TypeOopPtr::UNKNOWN_INSTANCE)->higher_equal(tn_t)) {
if (tn_type->isa_narrowoop()) {
tn_type = tinst->make_narrowoop();
} else {
tn_type = tinst;
}
igvn->hash_delete(tn);
igvn->set_type(tn, tinst);
tn->set_type(tinst);
igvn->set_type(tn, tn_type);
tn->set_type(tn_type);
igvn->hash_insert(tn);
record_for_optimizer(n);
}
......@@ -978,6 +1009,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
alloc_worklist.append_if_missing(use);
} else if (use->is_Phi() ||
use->is_CheckCastPP() ||
use->Opcode() == Op_EncodeP ||
use->Opcode() == Op_DecodeN ||
(use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) {
alloc_worklist.append_if_missing(use);
}
......@@ -1199,7 +1232,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
void ConnectionGraph::compute_escape() {
// 1. Populate Connection Graph with Ideal nodes.
// 1. Populate Connection Graph (CG) with Ideal nodes.
Unique_Node_List worklist_init;
worklist_init.map(_compile->unique(), NULL); // preallocate space
......@@ -1281,11 +1314,13 @@ void ConnectionGraph::compute_escape() {
remove_deferred(ni, &deferred_edges, &visited);
if (n->is_AddP()) {
// If this AddP computes an address which may point to more that one
// object, nothing the address points to can be scalar replaceable.
// object or more then one field (array's element), nothing the address
// points to can be scalar replaceable.
Node *base = get_addp_base(n);
ptset.Clear();
PointsTo(ptset, base, igvn);
if (ptset.Size() > 1) {
if (ptset.Size() > 1 ||
(ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) {
for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem;
ptnode_adr(pt)->_scalar_replaceable = false;
......@@ -1979,6 +2014,11 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
assert(false, "Op_ConP");
break;
}
case Op_ConN:
{
assert(false, "Op_ConN");
break;
}
case Op_CreateEx:
{
assert(false, "Op_CreateEx");
......
......@@ -2168,7 +2168,7 @@ bool LibraryCallKit::inline_unsafe_CAS(BasicType type) {
// (They don't if CAS fails, but it isn't worth checking.)
pre_barrier(control(), base, adr, alias_idx, newval, value_type, T_OBJECT);
#ifdef _LP64
if (adr->bottom_type()->is_narrow()) {
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
cas = _gvn.transform(new (C, 5) CompareAndSwapNNode(control(), mem, adr,
EncodePNode::encode(&_gvn, newval),
EncodePNode::encode(&_gvn, oldval)));
......@@ -2838,6 +2838,8 @@ bool LibraryCallKit::inline_native_newArray() {
_sp += nargs; // set original stack for use by uncommon_trap
mirror = do_null_check(mirror, T_OBJECT);
_sp -= nargs;
// If mirror or obj is dead, only null-path is taken.
if (stopped()) return true;
enum { _normal_path = 1, _slow_path = 2, PATH_LIMIT };
RegionNode* result_reg = new(C, PATH_LIMIT) RegionNode(PATH_LIMIT);
......@@ -3827,24 +3829,22 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
if (!stopped()) {
// Copy the fastest available way.
// (No need for PreserveJVMState, since we're using it all up now.)
// TODO: generate fields/elements copies for small objects instead.
Node* src = obj;
Node* dest = raw_obj;
Node* end = dest;
Node* size = _gvn.transform(alloc_siz);
// Exclude the header.
int base_off = instanceOopDesc::base_offset_in_bytes();
if (UseCompressedOops) {
// copy the header gap though.
Node* sptr = basic_plus_adr(src, base_off);
Node* dptr = basic_plus_adr(dest, base_off);
Node* sval = make_load(control(), sptr, TypeInt::INT, T_INT, raw_adr_type);
store_to_memory(control(), dptr, sval, T_INT, raw_adr_type);
base_off += sizeof(int);
assert(base_off % BytesPerLong != 0, "base with compressed oops");
// With compressed oops base_offset_in_bytes is 12 which creates
// the gap since countx is rounded by 8 bytes below.
// Copy klass and the gap.
base_off = instanceOopDesc::klass_offset_in_bytes();
}
src = basic_plus_adr(src, base_off);
dest = basic_plus_adr(dest, base_off);
end = basic_plus_adr(end, size);
// Compute the length also, if needed:
Node* countx = size;
......
......@@ -1282,12 +1282,6 @@ PhaseMacroExpand::initialize_object(AllocateNode* alloc,
}
rawmem = make_store(control, rawmem, object, oopDesc::mark_offset_in_bytes(), mark_node, T_ADDRESS);
if (UseCompressedOops) {
Node *zeronode = makecon(TypeInt::ZERO);
// store uncompressed 0 into klass ptr to zero out gap. The gap is
// used for primitive fields and has to be zeroed.
rawmem = make_store(control, rawmem, object, oopDesc::klass_gap_offset_in_bytes(), zeronode, T_INT);
}
rawmem = make_store(control, rawmem, object, oopDesc::klass_offset_in_bytes(), klass_node, T_OBJECT);
int header_size = alloc->minimum_header_size(); // conservatively small
......
......@@ -880,7 +880,7 @@ Node *Matcher::xform( Node *n, int max_stack ) {
Node *m = n->in(i); // Get input
int op = m->Opcode();
assert((op == Op_BoxLock) == jvms->is_monitor_use(i), "boxes only at monitor sites");
if( op == Op_ConI || op == Op_ConP ||
if( op == Op_ConI || op == Op_ConP || op == Op_ConN ||
op == Op_ConF || op == Op_ConD || op == Op_ConL
// || op == Op_BoxLock // %%%% enable this and remove (+++) in chaitin.cpp
) {
......@@ -1726,6 +1726,14 @@ void Matcher::find_shared( Node *n ) {
}
break;
}
case Op_ConN: { // Convert narrow pointers above the centerline to NUL
TypeNode *tn = n->as_Type(); // Constants derive from type nodes
const TypePtr* tp = tn->type()->is_narrowoop()->make_oopptr();
if (tp->_ptr == TypePtr::AnyNull) {
tn->set_type(TypeNarrowOop::NULL_PTR);
}
break;
}
case Op_Binary: // These are introduced in the Post_Visit state.
ShouldNotReachHere();
break;
......
......@@ -133,7 +133,9 @@ Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGV
PhiNode *mphi = result->as_Phi();
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
const TypePtr *t = mphi->adr_type();
if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM) {
if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM ||
t->isa_oopptr() && !t->is_oopptr()->is_instance() &&
t->is_oopptr()->cast_to_instance(t_oop->instance_id()) == t_oop) {
// clone the Phi with our address type
result = mphi->split_out_instance(t_adr, igvn);
} else {
......@@ -263,7 +265,10 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) {
// of all its inputs dominate or equal to sub's control edge.
// Currently 'sub' is either Allocate, Initialize or Start nodes.
assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start(), "expecting only these nodes");
// Or Region for the check in LoadNode::Ideal();
// 'sub' should have sub->in(0) != NULL.
assert(sub->is_Allocate() || sub->is_Initialize() || sub->is_Start() ||
sub->is_Region(), "expecting only these nodes");
// Get control edge of 'sub'.
sub = sub->find_exact_control(sub->in(0));
......@@ -576,6 +581,9 @@ bool MemNode::adr_phi_is_loop_invariant(Node* adr_phi, Node* cast) {
// Find any cast-away of null-ness and keep its control. Null cast-aways are
// going away in this pass and we need to make this memory op depend on the
// gating null check.
Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
return Ideal_common_DU_postCCP(ccp, this, in(MemNode::Address));
}
// I tried to leave the CastPP's in. This makes the graph more accurate in
// some sense; we get to keep around the knowledge that an oop is not-null
......@@ -585,15 +593,14 @@ bool MemNode::adr_phi_is_loop_invariant(Node* adr_phi, Node* cast) {
// some of the more trivial cases in the optimizer. Removing more useless
// Phi's started allowing Loads to illegally float above null checks. I gave
// up on this approach. CNC 10/20/2000
Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
Node *ctr = in(MemNode::Control);
Node *mem = in(MemNode::Memory);
Node *adr = in(MemNode::Address);
// This static method may be called not from MemNode (EncodePNode calls it).
// Only the control edge of the node 'n' might be updated.
Node *MemNode::Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ) {
Node *skipped_cast = NULL;
// Need a null check? Regular static accesses do not because they are
// from constant addresses. Array ops are gated by the range check (which
// always includes a NULL check). Just check field ops.
if( !ctr ) {
if( n->in(MemNode::Control) == NULL ) {
// Scan upwards for the highest location we can place this memory op.
while( true ) {
switch( adr->Opcode() ) {
......@@ -618,10 +625,10 @@ Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
}
// CastPP is going away in this pass! We need this memory op to be
// control-dependent on the test that is guarding the CastPP.
ccp->hash_delete(this);
set_req(MemNode::Control, adr->in(0));
ccp->hash_insert(this);
return this;
ccp->hash_delete(n);
n->set_req(MemNode::Control, adr->in(0));
ccp->hash_insert(n);
return n;
case Op_Phi:
// Attempt to float above a Phi to some dominating point.
......@@ -652,10 +659,10 @@ Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
adr = adr->in(1);
continue;
}
ccp->hash_delete(this);
set_req(MemNode::Control, adr->in(0));
ccp->hash_insert(this);
return this;
ccp->hash_delete(n);
n->set_req(MemNode::Control, adr->in(0));
ccp->hash_insert(n);
return n;
// List of "safe" opcodes; those that implicitly block the memory
// op below any null check.
......@@ -665,6 +672,7 @@ Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
case Op_LoadN: // Loading from within a klass
case Op_LoadKlass: // Loading from within a klass
case Op_ConP: // Loading from a klass
case Op_ConN: // Loading from a klass
case Op_CreateEx: // Sucking up the guts of an exception oop
case Op_Con: // Reading from TLS
case Op_CMoveP: // CMoveP is pinned
......@@ -676,8 +684,8 @@ Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
{
assert(adr->as_Proj()->_con == TypeFunc::Parms, "must be return value");
const Node* call = adr->in(0);
if (call->is_CallStaticJava()) {
const CallStaticJavaNode* call_java = call->as_CallStaticJava();
if (call->is_CallJava()) {
const CallJavaNode* call_java = call->as_CallJava();
const TypeTuple *r = call_java->tf()->range();
assert(r->cnt() > TypeFunc::Parms, "must return value");
const Type* ret_type = r->field_at(TypeFunc::Parms);
......@@ -749,7 +757,7 @@ Node *LoadNode::make( PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const Type
case T_ADDRESS: return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_ptr() );
case T_OBJECT:
#ifdef _LP64
if (adr->bottom_type()->is_narrow()) {
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
const TypeNarrowOop* narrowtype;
if (rt->isa_narrowoop()) {
narrowtype = rt->is_narrowoop();
......@@ -761,10 +769,10 @@ Node *LoadNode::make( PhaseGVN& gvn, Node *ctl, Node *mem, Node *adr, const Type
return DecodeNNode::decode(&gvn, load);
} else
#endif
{
assert(!adr->bottom_type()->is_narrow(), "should have got back a narrow oop");
return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr());
}
{
assert(!adr->bottom_type()->is_ptr_to_narrowoop(), "should have got back a narrow oop");
return new (C, 3) LoadPNode(ctl, mem, adr, adr_type, rt->is_oopptr());
}
}
ShouldNotReachHere();
return (LoadNode*)NULL;
......@@ -1118,6 +1126,127 @@ Node* LoadNode::eliminate_autobox(PhaseGVN* phase) {
return NULL;
}
//------------------------------split_through_phi------------------------------
// Split instance field load through Phi.
Node *LoadNode::split_through_phi(PhaseGVN *phase) {
Node* mem = in(MemNode::Memory);
Node* address = in(MemNode::Address);
const TypePtr *addr_t = phase->type(address)->isa_ptr();
const TypeOopPtr *t_oop = addr_t->isa_oopptr();
assert(mem->is_Phi() && (t_oop != NULL) &&
t_oop->is_instance_field(), "invalide conditions");
Node *region = mem->in(0);
if (region == NULL) {
return NULL; // Wait stable graph
}
uint cnt = mem->req();
for( uint i = 1; i < cnt; i++ ) {
Node *in = mem->in(i);
if( in == NULL ) {
return NULL; // Wait stable graph
}
}
// Check for loop invariant.
if (cnt == 3) {
for( uint i = 1; i < cnt; i++ ) {
Node *in = mem->in(i);
Node* m = MemNode::optimize_memory_chain(in, addr_t, phase);
if (m == mem) {
set_req(MemNode::Memory, mem->in(cnt - i)); // Skip this phi.
return this;
}
}
}
// Split through Phi (see original code in loopopts.cpp).
assert(phase->C->have_alias_type(addr_t), "instance should have alias type");
// Do nothing here if Identity will find a value
// (to avoid infinite chain of value phis generation).
if ( !phase->eqv(this, this->Identity(phase)) )
return NULL;
// Skip the split if the region dominates some control edge of the address.
if (cnt == 3 && !MemNode::all_controls_dominate(address, region))
return NULL;
const Type* this_type = this->bottom_type();
int this_index = phase->C->get_alias_index(addr_t);
int this_offset = addr_t->offset();
int this_iid = addr_t->is_oopptr()->instance_id();
int wins = 0;
PhaseIterGVN *igvn = phase->is_IterGVN();
Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset);
for( uint i = 1; i < region->req(); i++ ) {
Node *x;
Node* the_clone = NULL;
if( region->in(i) == phase->C->top() ) {
x = phase->C->top(); // Dead path? Use a dead data op
} else {
x = this->clone(); // Else clone up the data op
the_clone = x; // Remember for possible deletion.
// Alter data node to use pre-phi inputs
if( this->in(0) == region ) {
x->set_req( 0, region->in(i) );
} else {
x->set_req( 0, NULL );
}
for( uint j = 1; j < this->req(); j++ ) {
Node *in = this->in(j);
if( in->is_Phi() && in->in(0) == region )
x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone
}
}
// Check for a 'win' on some paths
const Type *t = x->Value(igvn);
bool singleton = t->singleton();
// See comments in PhaseIdealLoop::split_thru_phi().
if( singleton && t == Type::TOP ) {
singleton &= region->is_Loop() && (i != LoopNode::EntryControl);
}
if( singleton ) {
wins++;
x = igvn->makecon(t);
} else {
// We now call Identity to try to simplify the cloned node.
// Note that some Identity methods call phase->type(this).
// Make sure that the type array is big enough for
// our new node, even though we may throw the node away.
// (This tweaking with igvn only works because x is a new node.)
igvn->set_type(x, t);
Node *y = x->Identity(igvn);
if( y != x ) {
wins++;
x = y;
} else {
y = igvn->hash_find(x);
if( y ) {
wins++;
x = y;
} else {
// Else x is a new node we are keeping
// We do not need register_new_node_with_optimizer
// because set_type has already been called.
igvn->_worklist.push(x);
}
}
}
if (x != the_clone && the_clone != NULL)
igvn->remove_dead_node(the_clone);
phi->set_req(i, x);
}
if( wins > 0 ) {
// Record Phi
igvn->register_new_node_with_optimizer(phi);
return phi;
}
igvn->remove_dead_node(phi);
return NULL;
}
//------------------------------Ideal------------------------------------------
// If the load is from Field memory and the pointer is non-null, we can
......@@ -1175,112 +1304,9 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
const TypeOopPtr *t_oop = addr_t->isa_oopptr();
if (can_reshape && opt_mem->is_Phi() &&
(t_oop != NULL) && t_oop->is_instance_field()) {
assert(t_oop->offset() != Type::OffsetBot && t_oop->offset() != Type::OffsetTop, "");
Node *region = opt_mem->in(0);
uint cnt = opt_mem->req();
for( uint i = 1; i < cnt; i++ ) {
Node *in = opt_mem->in(i);
if( in == NULL ) {
region = NULL; // Wait stable graph
break;
}
}
if (region != NULL) {
// Check for loop invariant.
if (cnt == 3) {
for( uint i = 1; i < cnt; i++ ) {
Node *in = opt_mem->in(i);
Node* m = MemNode::optimize_memory_chain(in, addr_t, phase);
if (m == opt_mem) {
set_req(MemNode::Memory, opt_mem->in(cnt - i)); // Skip this phi.
return this;
}
}
}
// Split through Phi (see original code in loopopts.cpp).
assert(phase->C->have_alias_type(addr_t), "instance should have alias type");
// Do nothing here if Identity will find a value
// (to avoid infinite chain of value phis generation).
if ( !phase->eqv(this, this->Identity(phase)) )
return NULL;
const Type* this_type = this->bottom_type();
int this_index = phase->C->get_alias_index(addr_t);
int this_offset = addr_t->offset();
int this_iid = addr_t->is_oopptr()->instance_id();
int wins = 0;
PhaseIterGVN *igvn = phase->is_IterGVN();
Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset);
for( uint i = 1; i < region->req(); i++ ) {
Node *x;
Node* the_clone = NULL;
if( region->in(i) == phase->C->top() ) {
x = phase->C->top(); // Dead path? Use a dead data op
} else {
x = this->clone(); // Else clone up the data op
the_clone = x; // Remember for possible deletion.
// Alter data node to use pre-phi inputs
if( this->in(0) == region ) {
x->set_req( 0, region->in(i) );
} else {
x->set_req( 0, NULL );
}
for( uint j = 1; j < this->req(); j++ ) {
Node *in = this->in(j);
if( in->is_Phi() && in->in(0) == region )
x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone
}
}
// Check for a 'win' on some paths
const Type *t = x->Value(igvn);
bool singleton = t->singleton();
// See comments in PhaseIdealLoop::split_thru_phi().
if( singleton && t == Type::TOP ) {
singleton &= region->is_Loop() && (i != LoopNode::EntryControl);
}
if( singleton ) {
wins++;
x = igvn->makecon(t);
} else {
// We now call Identity to try to simplify the cloned node.
// Note that some Identity methods call phase->type(this).
// Make sure that the type array is big enough for
// our new node, even though we may throw the node away.
// (This tweaking with igvn only works because x is a new node.)
igvn->set_type(x, t);
Node *y = x->Identity(igvn);
if( y != x ) {
wins++;
x = y;
} else {
y = igvn->hash_find(x);
if( y ) {
wins++;
x = y;
} else {
// Else x is a new node we are keeping
// We do not need register_new_node_with_optimizer
// because set_type has already been called.
igvn->_worklist.push(x);
}
}
}
if (x != the_clone && the_clone != NULL)
igvn->remove_dead_node(the_clone);
phi->set_req(i, x);
}
if( wins > 0 ) {
// Record Phi
igvn->register_new_node_with_optimizer(phi);
return phi;
} else {
igvn->remove_dead_node(phi);
}
}
// Split instance field load through Phi.
Node* result = split_through_phi(phase);
if (result != NULL) return result;
}
}
......@@ -1835,7 +1861,7 @@ StoreNode* StoreNode::make( PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, cons
case T_ADDRESS:
case T_OBJECT:
#ifdef _LP64
if (adr->bottom_type()->is_narrow() ||
if (adr->bottom_type()->is_ptr_to_narrowoop() ||
(UseCompressedOops && val->bottom_type()->isa_klassptr() &&
adr->bottom_type()->isa_rawptr())) {
const TypePtr* type = val->bottom_type()->is_ptr();
......
......@@ -72,7 +72,8 @@ public:
// This one should probably be a phase-specific function:
static bool all_controls_dominate(Node* dom, Node* sub);
// Is this Node a MemNode or some descendent? Default is YES.
// Find any cast-away of null-ness and keep its control.
static Node *Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr );
virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp );
virtual const class TypePtr *adr_type() const; // returns bottom_type of address
......@@ -150,6 +151,9 @@ public:
// zero out the control input.
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
// Split instance field load through Phi.
Node* split_through_phi(PhaseGVN *phase);
// Recover original value from boxed values
Node *eliminate_autobox(PhaseGVN *phase);
......
......@@ -1049,51 +1049,80 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
Node* orig_sub = sub;
nlist.clear();
bool this_dominates = false;
uint region_input = 0;
bool result = false; // Conservative answer
while (sub != NULL) { // walk 'sub' up the chain to 'this'
if (sub == this) {
if (nlist.size() == 0) {
// No Region nodes except loops were visited before and the EntryControl
// path was taken for loops: it did not walk in a cycle.
return true;
} else if (!this_dominates) {
result = true;
break;
} else if (this_dominates) {
result = false; // already met before: walk in a cycle
break;
} else {
// Region nodes were visited. Continue walk up to Start or Root
// to make sure that it did not walk in a cycle.
this_dominates = true; // first time meet
iterations_without_region_limit = DominatorSearchLimit; // Reset
} else {
return false; // already met before: walk in a cycle
}
}
}
if (sub->is_Start() || sub->is_Root()) {
result = this_dominates;
break;
}
if (sub->is_Start() || sub->is_Root())
return this_dominates;
Node* up = sub->find_exact_control(sub->in(0));
if (up == NULL || up->is_top())
return false; // Conservative answer for dead code
if (sub == up && sub->is_Loop()) {
if (up == NULL || up->is_top()) {
result = false; // Conservative answer for dead code
break;
}
if (sub == up && (sub->is_Loop() || sub->is_Region() && sub->req() != 3)) {
// Take first valid path on the way up to 'this'.
up = sub->in(1); // in(LoopNode::EntryControl);
} else if (sub == up && sub->is_Region() && sub->req() == 3) {
} else if (sub == up && sub->is_Region()) {
assert(sub->req() == 3, "sanity");
iterations_without_region_limit = DominatorSearchLimit; // Reset
// Try both paths for such Regions.
// It is not accurate without regions dominating information.
// With such information the other path should be checked for
// the most dominating Region which was visited before.
bool region_was_visited_before = false;
uint i = 1;
uint size = nlist.size();
if (size == 0) {
// No Region nodes (except Loops) were visited before.
// No such Region nodes were visited before.
// Take first valid path on the way up to 'this'.
} else if (nlist.at(size - 1) == sub) {
// This Region node was just visited. Take other path.
i = region_input + 1;
nlist.pop();
} else {
// Was this Region node visited before?
for (uint j = 0; j < size; j++) {
if (nlist.at(j) == sub) {
return false; // The Region node was visited before. Give up.
intptr_t ni;
int j = size - 1;
for (; j >= 0; j--) {
ni = (intptr_t)nlist.at(j);
if ((Node*)(ni & ~1) == sub) {
if ((ni & 1) != 0) {
break; // Visited 2 paths. Give up.
} else {
// The Region node was visited before only once.
nlist.remove(j);
region_was_visited_before = true;
for (; i < sub->req(); i++) {
Node* in = sub->in(i);
if (in != NULL && !in->is_top() && in != sub) {
break;
}
}
i++; // Take other path.
break;
}
}
}
if (j >= 0 && (ni & 1) != 0) {
result = false; // Visited 2 paths. Give up.
break;
}
// The Region node was not visited before.
// Take first valid path on the way up to 'this'.
}
for (; i < sub->req(); i++) {
Node* in = sub->in(i);
......@@ -1102,20 +1131,26 @@ bool Node::dominates(Node* sub, Node_List &nlist) {
}
}
if (i < sub->req()) {
nlist.push(sub);
up = sub->in(i);
region_input = i;
if (region_was_visited_before && sub != up) {
// Set 0 bit to indicate that both paths were taken.
nlist.push((Node*)((intptr_t)sub + 1));
} else {
nlist.push(sub);
}
}
}
if (sub == up)
return false; // some kind of tight cycle
if (--iterations_without_region_limit < 0)
return false; // dead cycle
if (sub == up) {
result = false; // some kind of tight cycle
break;
}
if (--iterations_without_region_limit < 0) {
result = false; // dead cycle
break;
}
sub = up;
}
return false;
return result;
}
//------------------------------remove_dead_region-----------------------------
......
......@@ -48,6 +48,7 @@ void Compile::Output() {
// Initialize the space for the BufferBlob used to find and verify
// instruction size in MachNode::emit_size()
init_scratch_buffer_blob();
if (failing()) return; // Out of memory
// Make sure I can find the Start Node
Block_Array& bbs = _cfg->_bbs;
......
......@@ -311,8 +311,18 @@ void Type::Initialize_shared(Compile* current) {
mreg2type[Op_RegFlags] = TypeInt::CC;
TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), current->env()->Object_klass(), false, arrayOopDesc::length_offset_in_bytes());
// There is no shared klass for Object[]. See note in TypeAryPtr::klass().
TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
#ifdef _LP64
if (UseCompressedOops) {
TypeAryPtr::OOPS = TypeAryPtr::NARROWOOPS;
} else
#endif
{
// There is no shared klass for Object[]. See note in TypeAryPtr::klass().
TypeAryPtr::OOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
}
TypeAryPtr::BYTES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE), true, Type::OffsetBot);
TypeAryPtr::SHORTS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT), true, Type::OffsetBot);
TypeAryPtr::CHARS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR), true, Type::OffsetBot);
......@@ -321,9 +331,10 @@ void Type::Initialize_shared(Compile* current) {
TypeAryPtr::FLOATS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT), true, Type::OffsetBot);
TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true, Type::OffsetBot);
TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL; // what should this be?
// Nobody should ask _array_body_type[T_NARROWOOP]. Use NULL as assert.
TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL;
TypeAryPtr::_array_body_type[T_OBJECT] = TypeAryPtr::OOPS;
TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays
TypeAryPtr::_array_body_type[T_ARRAY] = TypeAryPtr::OOPS; // arrays are stored in oop arrays
TypeAryPtr::_array_body_type[T_BYTE] = TypeAryPtr::BYTES;
TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES; // boolean[] is a byte array
TypeAryPtr::_array_body_type[T_SHORT] = TypeAryPtr::SHORTS;
......@@ -696,7 +707,7 @@ void Type::dump_on(outputStream *st) const {
ResourceMark rm;
Dict d(cmpkey,hashkey); // Stop recursive type dumping
dump2(d,1, st);
if (isa_ptr() && is_ptr()->is_narrow()) {
if (is_ptr_to_narrowoop()) {
st->print(" [narrow]");
}
}
......@@ -2146,6 +2157,67 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
// Convenience common pre-built type.
const TypeOopPtr *TypeOopPtr::BOTTOM;
//------------------------------TypeOopPtr-------------------------------------
TypeOopPtr::TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id )
: TypePtr(t, ptr, offset),
_const_oop(o), _klass(k),
_klass_is_exact(xk),
_is_ptr_to_narrowoop(false),
_instance_id(instance_id) {
#ifdef _LP64
if (UseCompressedOops && _offset != 0) {
if (klass() == NULL) {
assert(this->isa_aryptr(), "only arrays without klass");
_is_ptr_to_narrowoop = true;
} else if (_offset == oopDesc::klass_offset_in_bytes()) {
_is_ptr_to_narrowoop = true;
} else if (this->isa_aryptr()) {
_is_ptr_to_narrowoop = (klass()->is_obj_array_klass() &&
_offset != arrayOopDesc::length_offset_in_bytes());
} else if (klass() == ciEnv::current()->Class_klass() &&
(_offset == java_lang_Class::klass_offset_in_bytes() ||
_offset == java_lang_Class::array_klass_offset_in_bytes())) {
// Special hidden fields from the Class.
assert(this->isa_instptr(), "must be an instance ptr.");
_is_ptr_to_narrowoop = true;
} else if (klass()->is_instance_klass()) {
ciInstanceKlass* ik = klass()->as_instance_klass();
ciField* field = NULL;
if (this->isa_klassptr()) {
// Perm objects don't use compressed references, except for
// static fields which are currently compressed.
field = ik->get_field_by_offset(_offset, true);
if (field != NULL) {
BasicType basic_elem_type = field->layout_type();
_is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT ||
basic_elem_type == T_ARRAY);
}
} else if (_offset == OffsetBot || _offset == OffsetTop) {
// unsafe access
_is_ptr_to_narrowoop = true;
} else { // exclude unsafe ops
assert(this->isa_instptr(), "must be an instance ptr.");
// Field which contains a compressed oop references.
field = ik->get_field_by_offset(_offset, false);
if (field != NULL) {
BasicType basic_elem_type = field->layout_type();
_is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT ||
basic_elem_type == T_ARRAY);
} else if (klass()->equals(ciEnv::current()->Object_klass())) {
// Compile::find_alias_type() cast exactness on all types to verify
// that it does not affect alias type.
_is_ptr_to_narrowoop = true;
} else {
// Type for the copy start in LibraryCallKit::inline_native_clone().
assert(!klass_is_exact(), "only non-exact klass");
_is_ptr_to_narrowoop = true;
}
}
}
}
#endif
}
//------------------------------make-------------------------------------------
const TypeOopPtr *TypeOopPtr::make(PTR ptr,
int offset) {
......@@ -2593,9 +2665,13 @@ const Type *TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
//-----------------------------cast_to_instance-------------------------------
const TypeOopPtr *TypeInstPtr::cast_to_instance(int instance_id) const {
if( instance_id == _instance_id) return this;
bool exact = (instance_id == UNKNOWN_INSTANCE) ? _klass_is_exact : true;
return make(ptr(), klass(), exact, const_oop(), _offset, instance_id);
bool exact = true;
PTR ptr_t = NotNull;
if (instance_id == UNKNOWN_INSTANCE) {
exact = _klass_is_exact;
ptr_t = _ptr;
}
return make(ptr_t, klass(), exact, const_oop(), _offset, instance_id);
}
//------------------------------xmeet_unloaded---------------------------------
......@@ -3014,6 +3090,7 @@ const TypePtr *TypeInstPtr::add_offset( int offset ) const {
// Convenience common pre-built types.
const TypeAryPtr *TypeAryPtr::RANGE;
const TypeAryPtr *TypeAryPtr::OOPS;
const TypeAryPtr *TypeAryPtr::NARROWOOPS;
const TypeAryPtr *TypeAryPtr::BYTES;
const TypeAryPtr *TypeAryPtr::SHORTS;
const TypeAryPtr *TypeAryPtr::CHARS;
......@@ -3063,8 +3140,13 @@ const Type *TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
//-----------------------------cast_to_instance-------------------------------
const TypeOopPtr *TypeAryPtr::cast_to_instance(int instance_id) const {
if( instance_id == _instance_id) return this;
bool exact = (instance_id == UNKNOWN_INSTANCE) ? _klass_is_exact : true;
return make(ptr(), const_oop(), _ary, klass(), exact, _offset, instance_id);
bool exact = true;
PTR ptr_t = NotNull;
if (instance_id == UNKNOWN_INSTANCE) {
exact = _klass_is_exact;
ptr_t = _ptr;
}
return make(ptr_t, const_oop(), _ary, klass(), exact, _offset, instance_id);
}
//-----------------------------narrow_size_type-------------------------------
......@@ -3547,7 +3629,7 @@ ciKlass* TypeAryPtr::klass() const {
k_ary = ciTypeArrayKlass::make(el->basic_type());
}
if( this != TypeAryPtr::OOPS )
if( this != TypeAryPtr::OOPS ) {
// The _klass field acts as a cache of the underlying
// ciKlass for this array type. In order to set the field,
// we need to cast away const-ness.
......@@ -3562,6 +3644,11 @@ ciKlass* TypeAryPtr::klass() const {
// a bit less efficient than caching, but calls to
// TypeAryPtr::OOPS->klass() are not common enough to matter.
((TypeAryPtr*)this)->_klass = k_ary;
if (UseCompressedOops && k_ary != NULL && k_ary->is_obj_array_klass() &&
_offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes()) {
((TypeAryPtr*)this)->_is_ptr_to_narrowoop = true;
}
}
return k_ary;
}
......
......@@ -191,9 +191,8 @@ public:
virtual const Type *filter( const Type *kills ) const;
// Returns true if this pointer points at memory which contains a
// compressed oop references. In 32-bit builds it's non-virtual
// since we don't support compressed oops at all in the mode.
LP64_ONLY(virtual) bool is_narrow() const { return false; }
// compressed oop references.
bool is_ptr_to_narrowoop() const;
// Convenience access
float getf() const;
......@@ -213,8 +212,8 @@ public:
const TypePtr *isa_ptr() const; // Returns NULL if not ptr type
const TypeRawPtr *isa_rawptr() const; // NOT Java oop
const TypeRawPtr *is_rawptr() const; // Asserts is rawptr
const TypeNarrowOop *is_narrowoop() const; // Java-style GC'd pointer
const TypeNarrowOop *isa_narrowoop() const; // Returns NULL if not oop ptr type
const TypeNarrowOop *is_narrowoop() const; // Java-style GC'd pointer
const TypeNarrowOop *isa_narrowoop() const; // Returns NULL if not oop ptr type
const TypeOopPtr *isa_oopptr() const; // Returns NULL if not oop ptr type
const TypeOopPtr *is_oopptr() const; // Java-style GC'd pointer
const TypeKlassPtr *isa_klassptr() const; // Returns NULL if not KlassPtr
......@@ -643,7 +642,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 ) : TypePtr(t, ptr, offset), _const_oop(o), _klass(k), _klass_is_exact(xk), _instance_id(instance_id) { }
TypeOopPtr( TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id );
public:
virtual bool eq( const Type *t ) const;
virtual int hash() const; // Type specific hashing
......@@ -660,8 +659,9 @@ protected:
ciKlass* _klass; // Klass object
// Does the type exclude subclasses of the klass? (Inexact == polymorphic.)
bool _klass_is_exact;
bool _is_ptr_to_narrowoop;
int _instance_id; // if not UNKNOWN_INSTANCE, indicates that this is a particular instance
int _instance_id; // if not UNKNOWN_INSTANCE, indicates that this is a particular instance
// of this type which is distinct. This is the the node index of the
// node creating this instance
......@@ -696,6 +696,11 @@ public:
ciObject* const_oop() const { return _const_oop; }
virtual ciKlass* klass() const { return _klass; }
bool klass_is_exact() const { return _klass_is_exact; }
// Returns true if this pointer points at memory which contains a
// compressed oop references.
bool is_ptr_to_narrowoop_nv() const { return _is_ptr_to_narrowoop; }
bool is_instance() const { return _instance_id != UNKNOWN_INSTANCE; }
uint instance_id() const { return _instance_id; }
bool is_instance_field() const { return _instance_id != UNKNOWN_INSTANCE && _offset >= 0; }
......@@ -716,12 +721,6 @@ public:
// returns the equivalent compressed version of this pointer type
virtual const TypeNarrowOop* make_narrowoop() const;
#ifdef _LP64
virtual bool is_narrow() const {
return (UseCompressedOops && _offset != 0);
}
#endif
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
......@@ -843,15 +842,10 @@ public:
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
#ifdef _LP64
virtual bool is_narrow() const {
return (UseCompressedOops && klass() != NULL && _offset != 0);
}
#endif
// Convenience common pre-built types.
static const TypeAryPtr *RANGE;
static const TypeAryPtr *OOPS;
static const TypeAryPtr *NARROWOOPS;
static const TypeAryPtr *BYTES;
static const TypeAryPtr *SHORTS;
static const TypeAryPtr *CHARS;
......@@ -901,18 +895,6 @@ public:
virtual const Type *xmeet( const Type *t ) const;
virtual const Type *xdual() const; // Compute dual right now.
#ifdef _LP64
// Perm objects don't use compressed references, except for static fields
// which are currently compressed
virtual bool is_narrow() const {
if (UseCompressedOops && _offset != 0 && _klass->is_instance_klass()) {
ciInstanceKlass* ik = _klass->as_instance_klass();
return ik != NULL && ik->get_field_by_offset(_offset, true) != NULL;
}
return false;
}
#endif
// Convenience common pre-built types.
static const TypeKlassPtr* OBJECT; // Not-null object klass or below
static const TypeKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same
......@@ -921,7 +903,7 @@ public:
#endif
};
//------------------------------TypeNarrowOop----------------------------------------
//------------------------------TypeNarrowOop----------------------------------
// A compressed reference to some kind of Oop. This type wraps around
// a preexisting TypeOopPtr and forwards most of it's operations to
// the underlying type. It's only real purpose is to track the
......@@ -1013,6 +995,14 @@ public:
};
//------------------------------accessors--------------------------------------
inline bool Type::is_ptr_to_narrowoop() const {
#ifdef _LP64
return (isa_oopptr() != NULL && is_oopptr()->is_ptr_to_narrowoop_nv());
#else
return false;
#endif
}
inline float Type::getf() const {
assert( _base == FloatCon, "Not a FloatCon" );
return ((TypeF*)this)->_f;
......
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* @test
* @bug 6689060
* @summary Escape Analysis does not work with Compressed Oops
* @run main/othervm -Xbatch -XX:CompileCommand=exclude,Test.dummy -XX:+AggressiveOpts Test
*/
import java.lang.reflect.Array;
class Point {
int x;
int y;
Point next;
int ax[];
int ay[];
Point pax[];
Point pay[];
public Point getNext() {
return next;
}
}
public class Test {
void dummy() {
// Empty method to verify correctness of DebugInfo.
// Use -XX:CompileCommand=exclude,Test.dummy
}
int ival(int i) {
return i*2;
}
int test80(int y, int l, int i) {
Point p = new Point();
p.ax = new int[2];
p.ay = new int[2];
int x = 3;
p.ax[0] = x;
p.ay[1] = 3 * x + y;
dummy();
return p.ax[0] * p.ay[1];
}
int test81(int y, int l, int i) {
Point p = new Point();
p.ax = new int[2];
p.ay = new int[2];
int x = 3;
p.ax[0] = x;
p.ay[1] = 3 * x + y;
dummy();
return p.ax[0] * p.ay[1];
}
int test44(int y) {
Point p1 = new Point();
p1.x = ival(3);
dummy();
p1.y = 3 * p1.x + y;
return p1.y;
}
int test43(int y) {
Point p1 = new Point();
if ( (y & 1) == 1 ) {
p1.x = ival(3);
} else {
p1.x = ival(5);
}
dummy();
p1.y = 3 * p1.x + y;
return p1.y;
}
int test42(int y) {
Point p1 = new Point();
p1.x = 3;
for (int i = 0; i < y; i++) {
if ( (i & 1) == 1 ) {
p1.x += 4;
}
}
p1.y = 3 * y + p1.x;
return p1.y;
}
int test40(int y) {
Point p1 = new Point();
if ( (y & 1) == 1 ) {
p1.x = 3;
} else {
p1.x = 5;
}
p1.y = 3 * p1.x + y;
return p1.y;
}
int test41(int y) {
Point p1 = new Point();
if ( (y & 1) == 1 ) {
p1.x += 4;
} else {
p1.x += 5;
}
p1.y = 3 * p1.x + y;
return p1.y;
}
Point test00(int y) {
int x = 3;
Point p = new Point();
p.x = x;
p.y = 3 * x + y;
return p;
}
Point test01(int y) {
int x = 3;
Point p = new Point();
p.x = x;
p.y = 3 * x + y;
dummy();
return p;
}
Point test02(int y) {
int x = 3;
Point p1 = null;
for (int i = 0; i < y; i++) {
Point p2 = new Point();
p2.x = x;
p2.y = 3 * y + x;
p2.next = p1;
p1 = p2;
}
return p1;
}
Point test03(int y) {
int x = 3;
Point p1 = null;
for (int i = 0; i < y; i++) {
Point p2 = new Point();
p2.x = x;
p2.y = 3 * y + x;
p2.next = p1;
p1 = p2;
}
dummy();
return p1;
}
Point test04(int y) {
int x = 3;
Point p1 = null;
for (int i = 0; i < y; i++) {
Point p2 = new Point();
p2.x = x;
p2.y = 3 * y + x;
p2.next = p1;
dummy();
p1 = p2;
}
return p1;
}
int test05(int y) {
int x = 3;
Point p1 = new Point();
for (int i = 0; i < y; i++) {
Point p2 = new Point();
p2.x = x;
p2.y = 3 * y + x;
p1.next = p2;
p1 = p2;
}
return p1.y;
}
int test0(int y) {
int x = 3;
Point p = new Point();
p.x = x;
p.y = 3 * x + y;
dummy();
return p.x * p.y;
}
int test1(int y) {
Point p = new Point();
if ( (y & 1) == 1 ) {
p = new Point(); // Kill previous
}
int x = 3;
p.x = x;
p.y = 3 * x + y;
dummy();
return p.x * p.y;
}
int test2(int y) {
Point p1 = new Point();
Point p2 = new Point();
p1.x = 3;
p2.x = 4;
p1.y = 3 * p2.x + y;
p2.y = 3 * p1.x + y;
dummy();
return p1.y * p2.y;
}
int test3(int y, Point p1) {
Point p2 = new Point();
p1.x = 3;
p2.x = 4;
p1.y = 3 * p2.x + y;
p2.y = 3 * p1.x + y;
dummy();
return p1.y * p2.y;
}
int test4(int y) {
Point p1 = new Point();
Point p2 = new Point();
if ( (y & 1) == 1 ) {
p1.x = 3;
p2.x = 4;
} else {
p1.x = 5;
p2.x = 6;
}
p1.y = 3 * p2.x + y;
p2.y = 3 * p1.x + y;
dummy();
return p1.y * p2.y;
}
int test5(int y, Point p1) {
Point p2 = new Point();
if ( (y & 1) == 1 ) {
p1.x = 3;
p2.x = 4;
} else {
p1.x = 5;
p2.x = 6;
}
p1.y = 3 * p2.x + y;
p2.y = 3 * p1.x + y;
dummy();
return p1.y * p2.y;
}
int test6(int y) {
Point p1 = new Point();
Point p2 = new Point();
p1.next = p2;
if ( (y & 1) == 1 ) {
p1.x = 3;
p1.getNext().x = 4;
} else {
p1.x = 5;
p1.getNext().x = 6;
}
p1.y = 3 * p2.x + y;
p2.y = 3 * p1.x + y;
dummy();
return p1.y * p2.y;
}
int test7(int y, Point p1) {
Point p2 = new Point();
p1.next = p2;
if ( (y & 1) == 1 ) {
p1.x = 3;
p1.getNext().x = 4;
} else {
p1.x = 5;
p1.getNext().x = 6;
}
p1.y = 3 * p2.x + y;
p2.y = 3 * p1.x + y;
dummy();
return p1.y * p2.y;
}
int test8(int y, int l, int i) {
Point p = new Point();
p.ax = new int[l];
p.ay = new int[l];
int x = 3;
p.ax[i] = x;
p.ay[i] = 3 * x + y;
dummy();
return p.ax[i] * p.ay[i];
}
int test9(int y, int l, int i) {
Point p = new Point();
p.pax = new Point[l];
p.pay = new Point[l];
p.pax[i] = new Point();
p.pay[i] = new Point();
p.pax[i].x = 3;
p.pay[i].x = 4;
p.pax[i].y = 3 * p.pay[i].x + y;
p.pay[i].y = 3 * p.pax[i].x + y;
dummy();
return p.pax[i].y * p.pay[i].y;
}
int test10(int y, int l, int i, Class cls) {
Point p = new Point();
try {
p.pax = (Point[])Array.newInstance(cls, l);
p.pax[i] = (Point)cls.newInstance();
}
catch(java.lang.InstantiationException ex) {
return 0;
}
catch(java.lang.IllegalAccessException ex) {
return 0;
}
p.pax[i].x = 3;
p.pax[i].y = 3 * p.pax[i].x + y;
dummy();
return p.pax[i].x * p.pax[i].y;
}
int test11(int y) {
Point p1 = new Point();
Point p2 = new Point();
p1.next = p2;
if ( (y & 1) == 1 ) {
p1.x = 3;
p1.next.x = 4;
} else {
p1.x = 5;
p1.next.x = 6;
}
p1.y = 3 * p1.next.x + y;
p1.next.y = 3 * p1.x + y;
dummy();
return p1.y * p1.next.y;
}
int test12(int y) {
Point p1 = new Point();
p1.next = p1;
if ( (y & 1) == 1 ) {
p1.x = 3;
p1.next.x = 4;
} else {
p1.x = 5;
p1.next.x = 6;
}
p1.y = 3 * p1.next.x + y;
p1.next.y = 3 * p1.x + y;
dummy();
return p1.y * p1.next.y;
}
public static void main(String args[]) {
Test tsr = new Test();
Point p = new Point();
Point ptmp = p;
Class cls = Point.class;
int y = 0;
for (int i=0; i<10000; i++) {
ptmp.next = tsr.test00(1);
ptmp.next = tsr.test01(1);
ptmp.next = tsr.test02(1);
ptmp.next = tsr.test03(1);
ptmp.next = tsr.test04(1);
y = tsr.test05(1);
y = tsr.test80(y, 1, 0);
y = tsr.test81(y, 1, 0);
y = tsr.test44(y);
y = tsr.test43(y);
y = tsr.test42(y);
y = tsr.test40(y);
y = tsr.test41(y);
y = tsr.test0(y);
y = tsr.test1(y);
y = tsr.test2(y);
y = tsr.test3(y, p);
y = tsr.test4(y);
y = tsr.test5(y, p);
y = tsr.test6(y);
y = tsr.test7(y, p);
y = tsr.test8(y, 1, 0);
y = tsr.test9(y, 1, 0);
y = tsr.test10(y, 1, 0, cls);
y = tsr.test11(y);
y = tsr.test12(y);
}
for (int i=0; i<10000; i++) {
ptmp.next = tsr.test00(1);
ptmp.next = tsr.test01(1);
ptmp.next = tsr.test02(1);
ptmp.next = tsr.test03(1);
ptmp.next = tsr.test04(1);
y = tsr.test05(1);
y = tsr.test80(y, 1, 0);
y = tsr.test81(y, 1, 0);
y = tsr.test44(y);
y = tsr.test43(y);
y = tsr.test42(y);
y = tsr.test40(y);
y = tsr.test41(y);
y = tsr.test0(y);
y = tsr.test1(y);
y = tsr.test2(y);
y = tsr.test3(y, p);
y = tsr.test4(y);
y = tsr.test5(y, p);
y = tsr.test6(y);
y = tsr.test7(y, p);
y = tsr.test8(y, 1, 0);
y = tsr.test9(y, 1, 0);
y = tsr.test10(y, 1, 0, cls);
y = tsr.test11(y);
y = tsr.test12(y);
}
for (int i=0; i<10000; i++) {
ptmp.next = tsr.test00(1);
ptmp.next = tsr.test01(1);
ptmp.next = tsr.test02(1);
ptmp.next = tsr.test03(1);
ptmp.next = tsr.test04(1);
y = tsr.test05(1);
y = tsr.test80(y, 1, 0);
y = tsr.test81(y, 1, 0);
y = tsr.test44(y);
y = tsr.test43(y);
y = tsr.test42(y);
y = tsr.test40(y);
y = tsr.test41(y);
y = tsr.test0(y);
y = tsr.test1(y);
y = tsr.test2(y);
y = tsr.test3(y, p);
y = tsr.test4(y);
y = tsr.test5(y, p);
y = tsr.test6(y);
y = tsr.test7(y, p);
y = tsr.test8(y, 1, 0);
y = tsr.test9(y, 1, 0);
y = tsr.test10(y, 1, 0, cls);
y = tsr.test11(y);
y = tsr.test12(y);
}
int z = 0;
y = tsr.test80(0, 1, 0);
z += y;
System.out.println("After 'test80' y=" + y);
y = tsr.test81(0, 1, 0);
z += y;
System.out.println("After 'test81' y=" + y);
y = tsr.test44(0);
z += y;
System.out.println("After 'test44' y=" + y);
y = tsr.test43(0);
z += y;
System.out.println("After 'test43' y=" + y);
y = tsr.test42(0);
z += y;
System.out.println("After 'test42' y=" + y);
y = tsr.test40(0);
z += y;
System.out.println("After 'test40' y=" + y);
y = tsr.test41(0);
z += y;
System.out.println("After 'test41' y=" + y);
ptmp.next = tsr.test00(1);
z += y;
System.out.println("After 'test00' p.y=" + ptmp.next.y);
ptmp.next = tsr.test01(1);
z += y;
System.out.println("After 'test01' p.y=" + ptmp.next.y);
ptmp.next = tsr.test02(1);
z += y;
System.out.println("After 'test02' p.y=" + ptmp.next.y);
ptmp.next = tsr.test03(1);
z += y;
System.out.println("After 'test03' p.y=" + ptmp.next.y);
ptmp.next = tsr.test04(1);
z += y;
System.out.println("After 'test04' p.y=" + ptmp.next.y);
y = tsr.test05(1);
z += y;
System.out.println("After 'test05' y=" + y);
y = tsr.test0(0);
z += y;
System.out.println("After 'test0' y=" + y);
y = tsr.test1(0);
z += y;
System.out.println("After 'test1' y=" + y);
y = tsr.test2(0);
z += y;
System.out.println("After 'test2' y=" + y);
y = tsr.test3(0, new Point());
z += y;
System.out.println("After 'test3' y=" + y);
y = tsr.test4(0);
z += y;
System.out.println("After 'test4' y=" + y);
y = tsr.test5(0, new Point());
z += y;
System.out.println("After 'test5' y=" + y);
y = tsr.test6(0);
z += y;
System.out.println("After 'test6' y=" + y);
y = tsr.test7(0, new Point());
z += y;
System.out.println("After 'test7' y=" + y);
y = tsr.test8(0, 1, 0);
z += y;
System.out.println("After 'test8' y=" + y);
y = tsr.test9(0, 1, 0);
z += y;
System.out.println("After 'test9' y=" + y);
y = tsr.test10(0, 1, 0, cls);
z += y;
System.out.println("After 'test10' y=" + y);
y = tsr.test11(0);
z += y;
System.out.println("After 'test11' y=" + y);
y = tsr.test12(0);
z += y;
System.out.println("After 'test12' y=" + y);
System.out.println("Sum of y =" + z);
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* @test
* @bug 6695810
* @summary null oop passed to encode_heap_oop_not_null
* @run main/othervm -Xbatch Test
*/
public class Test {
Test _t;
static void test(Test t1, Test t2) {
if (t2 != null)
t1._t = t2;
if (t2 != null)
t1._t = t2;
}
public static void main(String[] args) {
Test t = new Test();
for (int i = 0; i < 50; i++) {
for (int j = 0; j < 100; j++) {
test(t, t);
}
test(t, null);
}
for (int i = 0; i < 10000; i++) {
test(t, t);
}
test(t, null);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册