< prev index next >
src/hotspot/share/opto/castnode.cpp
Print this page
@@ -25,10 +25,11 @@
#include "precompiled.hpp"
#include "opto/addnode.hpp"
#include "opto/callnode.hpp"
#include "opto/castnode.hpp"
#include "opto/connode.hpp"
+#include "opto/graphKit.hpp"
#include "opto/matcher.hpp"
#include "opto/phaseX.hpp"
#include "opto/rootnode.hpp"
#include "opto/subnode.hpp"
#include "opto/type.hpp"
@@ -414,161 +415,157 @@
type()->isa_valuetypeptr() &&
in(1) != NULL && in(1)->is_Proj() &&
in(1)->in(0) != NULL && in(1)->in(0)->is_CallStaticJava() &&
in(1)->in(0)->as_CallStaticJava()->method() != NULL &&
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();
+ const TypeValueTypePtr* cast_type = type()->is_valuetypeptr();
+ ciValueKlass* vk = cast_type->value_type()->value_klass();
+ assert(!vk->is__Value(), "why cast to __Value?");
+ PhaseIterGVN* igvn = phase->is_IterGVN();
if (ValueTypeReturnedAsFields && vk->can_be_returned_as_fields()) {
igvn->set_delay_transform(true);
CallNode* call = in(1)->in(0)->as_Call();
- phase->C->remove_macro_node(call);
+ igvn->C->remove_macro_node(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);
+ 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));
- phase->set_type(in(1), in(1)->Value(phase));
+ igvn->set_type(call, call->Value(igvn));
+ igvn->set_type(in(1), in(1)->Value(igvn));
+ Node* ctl_hook = new Node(1);
+ Node* mem_hook = new Node(1);
+ Node* io_hook = new Node(1);
+ Node* res_hook = new Node(1);
+ Node* ex_ctl_hook = new Node(1);
+ Node* ex_mem_hook = new Node(1);
+ Node* ex_io_hook = new Node(1);
+
+ // Extract projections from the call and hook users to temporary nodes.
+ // We will re-attach them to newly created PhiNodes below.
CallProjections projs;
call->extract_projections(&projs, true, true);
+ igvn->replace_in_uses(projs.fallthrough_catchproj, ctl_hook);
+ igvn->replace_in_uses(projs.fallthrough_memproj, mem_hook);
+ igvn->replace_in_uses(projs.fallthrough_ioproj, io_hook);
+ igvn->replace_in_uses(projs.resproj, res_hook);
+ igvn->replace_in_uses(projs.catchall_catchproj, ex_ctl_hook);
+ igvn->replace_in_uses(projs.catchall_memproj, ex_mem_hook);
+ igvn->replace_in_uses(projs.catchall_ioproj, ex_io_hook);
+
+ // Restore IO input of the CatchNode
+ CatchNode* catchp = projs.fallthrough_catchproj->in(0)->as_Catch();
+ catchp->set_req(TypeFunc::I_O, projs.catchall_ioproj);
+ igvn->rehash_node_delayed(catchp);
+
+ // Rebuild the output JVMState from the call and use it to initialize a GraphKit
+ JVMState* new_jvms = call->jvms()->clone_shallow(igvn->C);
+ SafePointNode* new_map = new SafePointNode(call->req(), new_jvms);
+ for (uint i = TypeFunc::FramePtr; i < call->req(); i++) {
+ new_map->init_req(i, call->in(i));
+ }
+ new_map->set_control(projs.fallthrough_catchproj);
+ new_map->set_memory(MergeMemNode::make(projs.fallthrough_memproj));
+ new_map->set_i_o(projs.fallthrough_ioproj);
+ new_jvms->set_map(new_map);
- Node* init_ctl = new Node(1);
- Node* init_mem = new Node(1);
- Node* init_io = new Node(1);
- Node* init_ex_ctl = new Node(1);
- Node* init_ex_mem = new Node(1);
- Node* init_ex_io = new Node(1);
- Node* res = new Node(1);
-
- Node* ctl = init_ctl;
- Node* mem = init_mem;
- Node* io = init_io;
- Node* ex_ctl = init_ex_ctl;
- Node* ex_mem = init_ex_mem;
- Node* ex_io = init_ex_io;
+ GraphKit kit(new_jvms, igvn);
// Either we get a buffered value pointer and we can case use it
- // or we get a tagged klass pointer and we need to allocate a
- // value.
- Node* cast = phase->transform(new CastP2XNode(ctl, res));
- Node* masked = phase->transform(new AndXNode(cast, phase->MakeConX(0x1)));
- Node* cmp = phase->transform(new CmpXNode(masked, phase->MakeConX(0x1)));
- Node* bol = phase->transform(new BoolNode(cmp, BoolTest::eq));
- IfNode* iff = phase->transform(new IfNode(ctl, bol, PROB_MAX, COUNT_UNKNOWN))->as_If();
- Node* iftrue = phase->transform(new IfTrueNode(iff));
- Node* iffalse = phase->transform(new IfFalseNode(iff));
-
- ctl = iftrue;
-
- Node* ex_r = new RegionNode(3);
- Node* ex_mem_phi = new PhiNode(ex_r, Type::MEMORY, TypePtr::BOTTOM);
- Node* ex_io_phi = new PhiNode(ex_r, Type::ABIO);
-
- ex_r->init_req(2, ex_ctl);
- ex_mem_phi->init_req(2, ex_mem);
- ex_io_phi->init_req(2, ex_io);
-
- // We need an oop pointer in case allocation elimination
- // fails. Allocate a new instance here.
- Node* javaoop = ValueTypeBaseNode::allocate(type(), ctl, mem, io,
- call->in(TypeFunc::FramePtr),
- ex_ctl, ex_mem, ex_io,
- call->jvms(), igvn);
-
-
-
- ex_r->init_req(1, ex_ctl);
- ex_mem_phi->init_req(1, ex_mem);
- ex_io_phi->init_req(1, ex_io);
-
- ex_r = igvn->transform(ex_r);
- ex_mem_phi = igvn->transform(ex_mem_phi);
- ex_io_phi = igvn->transform(ex_io_phi);
-
- // Create the ValueTypePtrNode. This will add extra projections
- // to the call.
- ValueTypePtrNode* vtptr = ValueTypePtrNode::make(igvn, this);
- // Newly allocated value type must be initialized
- vtptr->store(igvn, ctl, mem->as_MergeMem(), javaoop);
- vtptr->set_oop(javaoop);
-
- Node* r = new RegionNode(3);
- Node* mem_phi = new PhiNode(r, Type::MEMORY, TypePtr::BOTTOM);
- Node* io_phi = new PhiNode(r, Type::ABIO);
- Node* res_phi = new PhiNode(r, type());
-
- r->init_req(1, ctl);
- mem_phi->init_req(1, mem);
- io_phi->init_req(1, io);
- res_phi->init_req(1, igvn->transform(vtptr));
-
- ctl = iffalse;
- mem = init_mem;
- io = init_io;
-
- Node* castnotnull = new CastPPNode(res, TypePtr::NOTNULL);
- castnotnull->set_req(0, ctl);
- castnotnull = phase->transform(castnotnull);
- Node* ccast = clone();
- ccast->set_req(0, ctl);
- ccast->set_req(1, castnotnull);
- ccast = phase->transform(ccast);
-
- vtptr = ValueTypePtrNode::make(*phase, mem, ccast);
-
- r->init_req(2, ctl);
- mem_phi->init_req(2, mem);
- io_phi->init_req(2, io);
- res_phi->init_req(2, igvn->transform(vtptr));
-
- r = igvn->transform(r);
- mem_phi = igvn->transform(mem_phi);
- io_phi = igvn->transform(io_phi);
- res_phi = igvn->transform(res_phi);
-
- igvn->replace_in_uses(projs.fallthrough_catchproj, r);
- igvn->replace_in_uses(projs.fallthrough_memproj, mem_phi);
- igvn->replace_in_uses(projs.fallthrough_ioproj, io_phi);
- igvn->replace_in_uses(projs.resproj, res_phi);
- igvn->replace_in_uses(projs.catchall_catchproj, ex_r);
- igvn->replace_in_uses(projs.catchall_memproj, ex_mem_phi);
- igvn->replace_in_uses(projs.catchall_ioproj, ex_io_phi);
+ // or we get a tagged klass pointer and we need to allocate a value.
+ Node* cast = igvn->transform(new CastP2XNode(kit.control(), projs.resproj));
+ Node* masked = igvn->transform(new AndXNode(cast, igvn->MakeConX(0x1)));
+ Node* cmp = igvn->transform(new CmpXNode(masked, igvn->MakeConX(0x1)));
+ Node* bol = kit.Bool(cmp, BoolTest::eq);
+ IfNode* iff = kit.create_and_map_if(kit.control(), bol, PROB_MAX, COUNT_UNKNOWN);
+ Node* iftrue = kit.IfTrue(iff);
+ Node* iffalse = kit.IfFalse(iff);
+
+ Node* region = new RegionNode(3);
+ Node* mem_phi = new PhiNode(region, Type::MEMORY, TypePtr::BOTTOM);
+ Node* io_phi = new PhiNode(region, Type::ABIO);
+ Node* res_phi = new PhiNode(region, cast_type);
+ Node* ex_region = new RegionNode(3);
+ Node* ex_mem_phi = new PhiNode(ex_region, Type::MEMORY, TypePtr::BOTTOM);
+ Node* ex_io_phi = new PhiNode(ex_region, Type::ABIO);
+
+ // True branch: result is a tagged klass pointer
+ // Allocate a value type (will add extra projections to the call)
+ kit.set_control(iftrue);
+ Node* res = igvn->transform(ValueTypePtrNode::make(&kit, vk, call));
+ res = res->isa_ValueTypePtr()->allocate(&kit);
+
+ // Get exception state
+ GraphKit ekit(kit.transfer_exceptions_into_jvms(), igvn);
+ SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
+ Node* ex_oop = ekit.use_exception_state(ex_map);
+
+ region->init_req(1, kit.control());
+ mem_phi->init_req(1, kit.reset_memory());
+ io_phi->init_req(1, kit.i_o());
+ res_phi->init_req(1, res);
+ ex_region->init_req(1, ekit.control());
+ ex_mem_phi->init_req(1, ekit.reset_memory());
+ ex_io_phi->init_req(1, ekit.i_o());
+
+ // False branch: result is not tagged
+ // Load buffered value type from returned oop
+ kit.set_control(iffalse);
+ kit.set_all_memory(projs.fallthrough_memproj);
+ kit.set_i_o(projs.fallthrough_ioproj);
+ // Cast oop to NotNull
+ ConstraintCastNode* res_cast = clone()->as_ConstraintCast();
+ res_cast->set_req(0, kit.control());
+ res_cast->set_req(1, projs.resproj);
+ res_cast->set_type(cast_type->cast_to_ptr_type(TypePtr::NotNull));
+ Node* ctl = kit.control(); // Control may get updated below
+ res = ValueTypePtrNode::make(*igvn, ctl, kit.merged_memory(), igvn->transform(res_cast));
+
+ region->init_req(2, ctl);
+ mem_phi->init_req(2, kit.reset_memory());
+ io_phi->init_req(2, kit.i_o());
+ res_phi->init_req(2, igvn->transform(res));
+ ex_region->init_req(2, projs.catchall_catchproj);
+ ex_mem_phi->init_req(2, projs.catchall_memproj);
+ ex_io_phi->init_req(2, projs.catchall_ioproj);
igvn->set_delay_transform(false);
- igvn->replace_node(init_ctl, projs.fallthrough_catchproj);
- igvn->replace_node(init_mem, projs.fallthrough_memproj);
- igvn->replace_node(init_io, projs.fallthrough_ioproj);
- igvn->replace_node(res, projs.resproj);
- igvn->replace_node(init_ex_ctl, projs.catchall_catchproj);
- igvn->replace_node(init_ex_mem, projs.catchall_memproj);
- igvn->replace_node(init_ex_io, projs.catchall_ioproj);
-
+ // Re-attach users to newly created PhiNodes
+ igvn->replace_node(ctl_hook, igvn->transform(region));
+ igvn->replace_node(mem_hook, igvn->transform(mem_phi));
+ igvn->replace_node(io_hook, igvn->transform(io_phi));
+ igvn->replace_node(res_hook, igvn->transform(res_phi));
+ igvn->replace_node(ex_ctl_hook, igvn->transform(ex_region));
+ igvn->replace_node(ex_mem_hook, igvn->transform(ex_mem_phi));
+ igvn->replace_node(ex_io_hook, igvn->transform(ex_io_phi));
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);
+ 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.
+ // Build the ValueTypePtrNode by loading the fields
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();
+ // Extract projections from the call and hook control users to temporary node
CallProjections projs;
call->extract_projections(&projs, true, true);
+ Node* ctl = projs.fallthrough_catchproj;
Node* mem = projs.fallthrough_memproj;
- Node* vtptr = ValueTypePtrNode::make(*phase, mem, in(1));
-
+ Node* ctl_hook = new Node(1);
+ igvn->replace_in_uses(ctl, ctl_hook);
+ Node* vtptr = ValueTypePtrNode::make(*phase, ctl, mem, in(1));
+ // Attach users to updated control
+ igvn->replace_node(ctl_hook, ctl);
return vtptr;
}
}
}
return NULL;
< prev index next >