< prev index next >
src/share/vm/opto/castnode.cpp
Print this page
*** 27,38 ****
--- 27,40 ----
#include "opto/callnode.hpp"
#include "opto/castnode.hpp"
#include "opto/connode.hpp"
#include "opto/matcher.hpp"
#include "opto/phaseX.hpp"
+ #include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
#include "opto/type.hpp"
+ #include "opto/valuetypenode.hpp"
//=============================================================================
// If input is already higher or equal to cast type, then this is an identity.
Node* ConstraintCastNode::Identity(PhaseGVN* phase) {
Node* dom = dominating_cast(phase);
*** 278,287 ****
--- 280,309 ----
//=============================================================================
//------------------------------Identity---------------------------------------
// If input is already higher or equal to cast type, then this is an identity.
Node* CheckCastPPNode::Identity(PhaseGVN* phase) {
+ // This is a value type, its input is a phi. That phi is also a
+ // value type of that same type and its inputs are value types of
+ // the same type: push the cast through the phi.
+ if (phase->is_IterGVN() &&
+ in(0) == NULL &&
+ type()->isa_valuetypeptr() &&
+ in(1) != NULL &&
+ in(1)->is_Phi()) {
+ PhaseIterGVN* igvn = phase->is_IterGVN();
+ Node* phi = in(1);
+ const Type* vtptr = type();
+ for (uint i = 1; i < phi->req(); i++) {
+ if (phi->in(i) != NULL && !phase->type(phi->in(i))->higher_equal(vtptr)) {
+ Node* cast = phase->transform(new CheckCastPPNode(NULL, phi->in(i), vtptr));
+ igvn->replace_input_of(phi, i, cast);
+ }
+ }
+ return phi;
+ }
+
Node* dom = dominating_cast(phase);
if (dom != NULL) {
return dom;
}
if (_carry_dependency) {
*** 373,382 ****
--- 395,580 ----
// }
// // Not joining two pointers
// return join;
}
+ static void replace_in_uses(PhaseIterGVN *igvn, Node* n, Node* m, uint last) {
+ for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+ Node* u = n->fast_out(i);
+ if (u->_idx < last) {
+ assert(n != u && m != u, "cycle!");
+ igvn->rehash_node_delayed(u);
+ int nb = u->replace_edge(n, m);
+ --i, imax -= nb;
+ }
+ }
+ }
+
+ Node* CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+ // This is a value type. Its input is the return of a call: the call
+ // returns a value type and we now know its exact type: build a
+ // ValueTypePtrNode from the call.
+ if (can_reshape &&
+ in(0) == NULL &&
+ phase->C->can_add_value_type_ptr() &&
+ type()->isa_valuetypeptr() &&
+ in(1) != NULL && in(1)->is_Proj() &&
+ in(1)->in(0) != NULL && in(1)->in(0)->is_CallStaticJava() &&
+ in(1)->as_Proj()->_con == TypeFunc::Parms) {
+ ciValueKlass* vk = type()->is_valuetypeptr()->value_type()->value_klass();
+ assert(vk != phase->C->env()->___Value_klass(), "why cast to __Value?");
+ PhaseIterGVN *igvn = phase->is_IterGVN();
+
+ if (ValueTypeReturnedAsFields && vk->can_be_returned_as_fields()) {
+ CallNode* call = in(1)->in(0)->as_Call();
+ // We now know the return type of the call
+ const TypeTuple *range_sig = TypeTuple::make_range(vk, false);
+ const TypeTuple *range_cc = TypeTuple::make_range(vk, true);
+ assert(range_sig != call->_tf->range_sig() && range_cc != call->_tf->range_cc(), "type should change");
+ call->_tf = TypeFunc::make(call->_tf->domain_sig(), call->_tf->domain_cc(),
+ range_sig, range_cc);
+ phase->set_type(call, call->Value(phase));
+
+ CallProjections projs;
+ call->extract_projections(&projs, true, true);
+ Node* ctl = projs.fallthrough_catchproj;
+ Node* mem = projs.fallthrough_memproj;
+ Node* io = projs.fallthrough_ioproj;
+ Node* ex_ctl = projs.catchall_catchproj;
+ Node* ex_mem = projs.catchall_memproj;
+ Node* ex_io = projs.catchall_ioproj;
+
+ uint last = phase->C->unique();
+
+ // We need an oop pointer in case allocation elimination
+ // fails. Allocate a new instance here.
+ MergeMemNode* all_mem = MergeMemNode::make(mem);
+ jint lhelper = vk->layout_helper();
+ assert(lhelper != Klass::_lh_neutral_value, "unsupported");
+
+ AllocateNode* alloc = new AllocateNode(phase->C,
+ AllocateNode::alloc_type(Type::TOP),
+ ctl,
+ mem,
+ io,
+ phase->MakeConX(Klass::layout_helper_size_in_bytes(lhelper)),
+ phase->makecon(TypeKlassPtr::make(vk)),
+ phase->intcon(0),
+ NULL);
+ alloc->set_req(TypeFunc::FramePtr, call->in(TypeFunc::FramePtr));
+ phase->C->add_safepoint_edges(alloc, call->jvms());
+ Node* n = igvn->transform(alloc);
+ assert(n == alloc, "node shouldn't go away");
+
+ ctl = igvn->transform(new ProjNode(alloc, TypeFunc::Control));
+ mem = igvn->transform(new ProjNode(alloc, TypeFunc::Memory, true));
+ all_mem->set_memory_at(Compile::AliasIdxRaw, mem);
+
+ io = igvn->transform(new ProjNode(alloc, TypeFunc::I_O, true));
+ Node* catc = igvn->transform(new CatchNode(ctl, io, 2));
+ Node* norm = igvn->transform(new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci));
+ Node* excp = igvn->transform(new CatchProjNode(catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci));
+
+ Node* r = new RegionNode(3);
+ Node* mem_phi = new PhiNode(r, Type::MEMORY, TypePtr::BOTTOM);
+ Node* io_phi = new PhiNode(r, Type::ABIO);
+
+ r->init_req(1, excp);
+ mem_phi->init_req(1, igvn->transform(all_mem));
+ io_phi->init_req(1, io);
+ r->init_req(2, ex_ctl);
+ mem_phi->init_req(2, ex_mem);
+ io_phi->init_req(2, ex_io);
+
+ r = igvn->transform(r);
+ mem_phi = igvn->transform(mem_phi);
+ io_phi = igvn->transform(io_phi);
+
+ replace_in_uses(igvn, ex_ctl, r, last);
+ replace_in_uses(igvn, ex_mem, mem_phi, last);
+ replace_in_uses(igvn, ex_io, io_phi, last);
+
+ ctl = norm;
+ mem = igvn->transform(new ProjNode(alloc, TypeFunc::Memory));
+ io = igvn->transform(new ProjNode(alloc, TypeFunc::I_O, false));
+ Node* rawoop = igvn->transform(new ProjNode(alloc, TypeFunc::Parms));
+
+ MemBarNode* membar = MemBarNode::make(phase->C, Op_Initialize, Compile::AliasIdxRaw, rawoop);
+ membar->set_req(TypeFunc::Control, ctl);
+
+ InitializeNode* init = membar->as_Initialize();
+
+ const TypeOopPtr* oop_type = type()->is_oopptr();
+ MergeMemNode* minit_in = MergeMemNode::make(mem);
+ init->set_req(InitializeNode::Memory, minit_in);
+ n = igvn->transform(membar);
+ assert(n == membar, "node shouldn't go away");
+ ctl = igvn->transform(new ProjNode(membar, TypeFunc::Control));
+ mem = igvn->transform(new ProjNode(membar, TypeFunc::Memory));
+
+ Node* m = projs.fallthrough_memproj;
+ MergeMemNode* out_mem_merge = MergeMemNode::make(m);
+ for (int i = 0, len = vk->nof_nonstatic_fields(); i < len; i++) {
+ ciField* field = vk->nonstatic_field_at(i);
+ if (field->offset() >= TrackedInitializationLimit * HeapWordSize)
+ continue;
+ int fieldidx = phase->C->alias_type(field)->index();
+ minit_in->set_memory_at(fieldidx, m);
+ out_mem_merge->set_memory_at(fieldidx, mem);
+ }
+
+ n = igvn->transform(minit_in);
+ assert(n == minit_in, "node shouldn't go away");
+ out_mem_merge->set_memory_at(Compile::AliasIdxRaw, mem);
+
+ Node* javaoop = igvn->transform(new CheckCastPPNode(ctl, rawoop, oop_type));
+
+ // Create the ValueTypePtrNode. This will add extra projections
+ // to the call.
+ ValueTypePtrNode* vtptr = ValueTypePtrNode::make(igvn, this);
+ igvn->set_delay_transform(true); // stores can be captured. If
+ // they are the whole subgraph
+ // shouldn't go away.
+
+ // Newly allocated value type must be initialized
+ vtptr->store(igvn, ctl, out_mem_merge, javaoop);
+ igvn->set_delay_transform(false);
+ vtptr->set_oop(javaoop);
+
+ mem = igvn->transform(out_mem_merge);
+ replace_in_uses(igvn, projs.fallthrough_catchproj, ctl, last);
+ replace_in_uses(igvn, projs.fallthrough_memproj, mem, last);
+ replace_in_uses(igvn, projs.fallthrough_ioproj, io, last);
+
+ igvn->replace_node(in(1), igvn->transform(vtptr));
+
+ return this;
+ } else {
+ CallNode* call = in(1)->in(0)->as_Call();
+ // We now know the return type of the call
+ const TypeTuple *range = TypeTuple::make_range(vk, false);
+ if (range != call->_tf->range_sig()) {
+ // Build the ValueTypePtrNode by loading the fields. Use call
+ // return as oop edge in the ValueTypePtrNode.
+ call->_tf = TypeFunc::make(call->_tf->domain_sig(), call->_tf->domain_cc(),
+ range, range);
+ phase->set_type(call, call->Value(phase));
+ phase->set_type(in(1), in(1)->Value(phase));
+ uint last = phase->C->unique();
+ CallNode* call = in(1)->in(0)->as_Call();
+ CallProjections projs;
+ call->extract_projections(&projs, true, true);
+ Node* mem = projs.fallthrough_memproj;
+ Node* vtptr = ValueTypePtrNode::make(*phase, mem, in(1));
+
+ return vtptr;
+ }
+ }
+ }
+ return NULL;
+ }
+
//=============================================================================
//------------------------------Value------------------------------------------
const Type* CastX2PNode::Value(PhaseGVN* phase) const {
const Type* t = phase->type(in(1));
if (t == Type::TOP) return Type::TOP;
< prev index next >