--- old/src/share/vm/opto/macro.cpp 2017-08-04 21:19:18.264349901 +0200 +++ new/src/share/vm/opto/macro.cpp 2017-08-04 21:19:10.775361990 +0200 @@ -2636,6 +2636,207 @@ _igvn.replace_node(_memproj_fallthrough, mem_phi); } +// A value type is returned from the call but we don't know its +// type. One of the values being returned is the klass of the value +// type. We need to allocate a value type instance of that type and +// initialize it with other values being returned. This is done with +// the stub call below that we add right after this call. +void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) { + Node* ret = call->proj_out(TypeFunc::Parms); + if (ret == NULL) { + return; + } + assert(ret->bottom_type()->is_valuetypeptr()->klass() == C->env()->___Value_klass(), "unexpected return type from MH intrinsic"); + const TypeFunc* tf = call->_tf; + const TypeTuple* domain = OptoRuntime::store_value_type_fields_Type()->domain_cc(); + const TypeFunc* new_tf = TypeFunc::make(tf->domain_sig(), tf->domain_cc(), tf->range_sig(), domain); + call->_tf = new_tf; + // Make sure the change of type is applied before projections are + // processed by igvn + _igvn.set_type(call, call->Value(&_igvn)); + _igvn.set_type(ret, ret->Value(&_igvn)); + + // Before any new projection is added: + CallProjections projs; + call->extract_projections(&projs, true, true); + + Node* ctl = new Node(1); + Node* mem = new Node(1); + Node* io = new Node(1); + Node* ex_ctl = new Node(1); + Node* ex_mem = new Node(1); + Node* ex_io = new Node(1); + Node* res = new Node(1); + + Node* cast = transform_later(new CastP2XNode(ctl, res)); + Node* mask = MakeConX(0x1); + Node* masked = transform_later(new AndXNode(cast, mask)); + Node* cmp = transform_later(new CmpXNode(masked, mask)); + Node* bol = transform_later(new BoolNode(cmp, BoolTest::eq)); + IfNode* allocation_iff = new IfNode(ctl, bol, PROB_MAX, COUNT_UNKNOWN); + transform_later(allocation_iff); + Node* allocation_ctl = transform_later(new IfTrueNode(allocation_iff)); + Node* no_allocation_ctl = transform_later(new IfFalseNode(allocation_iff)); + + Node* no_allocation_res = transform_later(new CheckCastPPNode(no_allocation_ctl, res, TypeValueTypePtr::NOTNULL)); + + assert(UseTLAB, "unsupported with tlabs off"); + + Node* mask2 = MakeConX(-2); + Node* masked2 = transform_later(new AndXNode(cast, mask2)); + Node* rawklassptr = transform_later(new CastX2PNode(masked2)); + Node* klass_node = transform_later(new CheckCastPPNode(allocation_ctl, rawklassptr, TypeKlassPtr::VALUE)); + + Node* top_adr; + Node* end_adr; + + set_eden_pointers(top_adr, end_adr); + Node *end = make_load(ctl, mem, end_adr, 0, TypeRawPtr::BOTTOM, T_ADDRESS); + Node *old_top = new LoadPNode(ctl, mem, top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM, MemNode::unordered); + transform_later(old_top); + Node* layout_val = make_load(NULL, mem, klass_node, in_bytes(Klass::layout_helper_offset()), TypeInt::INT, T_INT); + Node* size_in_bytes = ConvI2X(layout_val); + Node *new_top = new AddPNode(top(), old_top, size_in_bytes); + transform_later(new_top); + Node *needgc_cmp = new CmpPNode(new_top, end); + transform_later(needgc_cmp); + Node *needgc_bol = new BoolNode(needgc_cmp, BoolTest::ge); + transform_later(needgc_bol); + IfNode *needgc_iff = new IfNode(allocation_ctl, needgc_bol, PROB_UNLIKELY_MAG(4), COUNT_UNKNOWN); + transform_later(needgc_iff); + + Node *needgc_true = new IfTrueNode(needgc_iff); + transform_later(needgc_true); + + + CallStaticJavaNode* slow_call = new CallStaticJavaNode(OptoRuntime::store_value_type_fields_Type(), + StubRoutines::store_value_type_fields_to_buf(), + "store_value_type_fields", + call->jvms()->bci(), + TypePtr::BOTTOM); + slow_call->init_req(TypeFunc::Control, needgc_true); + slow_call->init_req(TypeFunc::Memory, mem); + slow_call->init_req(TypeFunc::I_O, io); + slow_call->init_req(TypeFunc::FramePtr, call->in(TypeFunc::FramePtr)); + slow_call->init_req(TypeFunc::ReturnAdr, call->in(TypeFunc::ReturnAdr)); + slow_call->init_req(TypeFunc::Parms, res); + + Node* slow_ctl = transform_later(new ProjNode(slow_call, TypeFunc::Control)); + Node* slow_mem = transform_later(new ProjNode(slow_call, TypeFunc::Memory)); + Node* slow_io = transform_later(new ProjNode(slow_call, TypeFunc::I_O)); + Node* slow_res = transform_later(new ProjNode(slow_call, TypeFunc::Parms)); + Node* slow_catc = transform_later(new CatchNode(slow_ctl, slow_io, 2)); + Node* slow_norm = transform_later(new CatchProjNode(slow_catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci)); + Node* slow_excp = transform_later(new CatchProjNode(slow_catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci)); + + 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(1, slow_excp); + ex_mem_phi->init_req(1, slow_mem); + ex_io_phi->init_req(1, slow_io); + ex_r->init_req(2, ex_ctl); + ex_mem_phi->init_req(2, ex_mem); + ex_io_phi->init_req(2, ex_io); + + transform_later(ex_r); + transform_later(ex_mem_phi); + transform_later(ex_io_phi); + + Node *needgc_false = new IfFalseNode(needgc_iff); + transform_later(needgc_false); + Node* rawmem = new StorePNode(needgc_false, mem, top_adr, TypeRawPtr::BOTTOM, new_top, MemNode::unordered); + transform_later(rawmem); + Node* mark_node = NULL; + // For now only enable fast locking for non-array types + if (UseBiasedLocking) { + mark_node = make_load(needgc_false, rawmem, klass_node, in_bytes(Klass::prototype_header_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); + } else { + mark_node = makecon(TypeRawPtr::make((address)markOopDesc::prototype())); + } + rawmem = make_store(needgc_false, rawmem, old_top, oopDesc::mark_offset_in_bytes(), mark_node, T_ADDRESS); + rawmem = make_store(needgc_false, rawmem, old_top, oopDesc::klass_offset_in_bytes(), klass_node, T_METADATA); + rawmem = make_store(needgc_false, rawmem, old_top, oopDesc::klass_gap_offset_in_bytes(), intcon(0), T_INT); + Node* pack_handler = make_load(needgc_false, rawmem, klass_node, in_bytes(ValueKlass::pack_handler_offset()), TypeRawPtr::BOTTOM, T_ADDRESS); + + CallLeafNoFPNode* handler_call = new CallLeafNoFPNode(OptoRuntime::pack_value_type_Type(), + NULL, + "pack handler", + TypeRawPtr::BOTTOM); + handler_call->init_req(TypeFunc::Control, needgc_false); + handler_call->init_req(TypeFunc::Memory, rawmem); + handler_call->init_req(TypeFunc::I_O, top()); + handler_call->init_req(TypeFunc::FramePtr, call->in(TypeFunc::FramePtr)); + handler_call->init_req(TypeFunc::ReturnAdr, top()); + handler_call->init_req(TypeFunc::Parms, pack_handler); + handler_call->init_req(TypeFunc::Parms+1, old_top); + + // We don't know how many values are returned. This assumes the + // worst case, that all available registers are used. + for (uint i = TypeFunc::Parms+1; i < domain->cnt(); i++) { + if (domain->field_at(i) == Type::HALF) { + slow_call->init_req(i, top()); + handler_call->init_req(i+1, top()); + continue; + } + Node* proj = transform_later(new ProjNode(call, i)); + slow_call->init_req(i, proj); + handler_call->init_req(i+1, proj); + } + + // We can safepoint at that new call + C->add_safepoint_edges(slow_call, call->jvms()); + transform_later(slow_call); + transform_later(handler_call); + + Node* handler_ctl = transform_later(new ProjNode(handler_call, TypeFunc::Control)); + rawmem = transform_later(new ProjNode(handler_call, TypeFunc::Memory)); + Node* needgc_false_res = transform_later(new ProjNode(handler_call, TypeFunc::Parms)); + + MergeMemNode* needgc_false_mem = MergeMemNode::make(mem); + needgc_false_mem->set_memory_at(Compile::AliasIdxRaw, rawmem); + transform_later(needgc_false_mem); + + Node* r = new RegionNode(4); + Node* mem_phi = new PhiNode(r, Type::MEMORY, TypePtr::BOTTOM); + Node* io_phi = new PhiNode(r, Type::ABIO); + Node* res_phi = new PhiNode(r, ret->bottom_type()); + + r->init_req(1, no_allocation_ctl); + mem_phi->init_req(1, mem); + io_phi->init_req(1, io); + res_phi->init_req(1, no_allocation_res); + r->init_req(2, slow_norm); + mem_phi->init_req(2, slow_mem); + io_phi->init_req(2, slow_io); + res_phi->init_req(2, slow_res); + r->init_req(3, handler_ctl); + mem_phi->init_req(3, needgc_false_mem); + io_phi->init_req(3, io); + res_phi->init_req(3, needgc_false_res); + + transform_later(r); + transform_later(mem_phi); + transform_later(io_phi); + transform_later(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); + + _igvn.replace_node(ctl, projs.fallthrough_catchproj); + _igvn.replace_node(mem, projs.fallthrough_memproj); + _igvn.replace_node(io, projs.fallthrough_ioproj); + _igvn.replace_node(res, projs.resproj); + _igvn.replace_node(ex_ctl, projs.catchall_catchproj); + _igvn.replace_node(ex_mem, projs.catchall_memproj); + _igvn.replace_node(ex_io, projs.catchall_ioproj); + } + //---------------------------eliminate_macro_nodes---------------------- // Eliminate scalar replaced allocations and associated locks. void PhaseMacroExpand::eliminate_macro_nodes() { @@ -2680,9 +2881,13 @@ case Node::Class_AllocateArray: success = eliminate_allocate_node(n->as_Allocate()); break; - case Node::Class_CallStaticJava: - success = eliminate_boxing_node(n->as_CallStaticJava()); + case Node::Class_CallStaticJava: { + CallStaticJavaNode* call = n->as_CallStaticJava(); + if (!call->method()->is_method_handle_intrinsic()) { + success = eliminate_boxing_node(n->as_CallStaticJava()); + } break; + } case Node::Class_Lock: case Node::Class_Unlock: assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); @@ -2728,10 +2933,13 @@ _igvn._worklist.push(n); success = true; } else if (n->Opcode() == Op_CallStaticJava) { - // Remove it from macro list and put on IGVN worklist to optimize. - C->remove_macro_node(n); - _igvn._worklist.push(n); - success = true; + CallStaticJavaNode* call = n->as_CallStaticJava(); + if (!call->method()->is_method_handle_intrinsic()) { + // Remove it from macro list and put on IGVN worklist to optimize. + C->remove_macro_node(n); + _igvn._worklist.push(n); + success = true; + } } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { _igvn.replace_node(n, n->in(1)); success = true; @@ -2808,6 +3016,10 @@ case Node::Class_Unlock: expand_unlock_node(n->as_Unlock()); break; + case Node::Class_CallStaticJava: + expand_mh_intrinsic_return(n->as_CallStaticJava()); + C->remove_macro_node(n); + break; default: assert(false, "unknown node type in macro list"); }