--- old/src/hotspot/share/opto/parse2.cpp 2019-07-03 10:04:42.555266337 +0200 +++ new/src/hotspot/share/opto/parse2.cpp 2019-07-03 10:04:42.271266340 +0200 @@ -1878,311 +1878,203 @@ // If current method is ValueBootstrapMethods::isSubstitutable(), // compile the acmp as a regular pointer comparison otherwise we // could call ValueBootstrapMethods::isSubstitutable() back - if (ACmpOnValues == 0 || method() == subst_method) { + if (!EnableValhalla || (method() == subst_method)) { Node* cmp = CmpP(a, b); cmp = optimize_cmp_with_klass(cmp); do_if(btest, cmp); return; } - if (ACmpOnValues == 3) { - // Substitutability test - if (a->is_ValueType()) { - inc_sp(2); - a = a->as_ValueType()->allocate(this, true)->get_oop(); - dec_sp(2); - } - if (b->is_ValueType()) { - inc_sp(2); - b = b->as_ValueType()->allocate(this, true)->get_oop(); - dec_sp(2); - } - - const TypeOopPtr* ta = _gvn.type(a)->isa_oopptr(); - const TypeOopPtr* tb = _gvn.type(b)->isa_oopptr(); - - if (ta == NULL || !ta->can_be_value_type_raw() || - tb == NULL || !tb->can_be_value_type_raw()) { - Node* cmp = CmpP(a, b); - cmp = optimize_cmp_with_klass(cmp); - do_if(btest, cmp); - return; - } - - Node* cmp = CmpP(a, b); - cmp = optimize_cmp_with_klass(cmp); - Node* eq_region = NULL; - if (btest == BoolTest::eq) { - do_if(btest, cmp, true); - if (stopped()) { - return; - } - } else { - assert(btest == BoolTest::ne, "only eq or ne"); - Node* is_not_equal = NULL; - eq_region = new RegionNode(3); - { - PreserveJVMState pjvms(this); - do_if(btest, cmp, false, &is_not_equal); - if (!stopped()) { - eq_region->init_req(1, control()); - } - } - if (is_not_equal == NULL || is_not_equal->is_top()) { - record_for_igvn(eq_region); - set_control(_gvn.transform(eq_region)); - return; - } - set_control(is_not_equal); - } - // Pointers not equal, check for values - Node* ne_region = new RegionNode(6); + // Substitutability test + if (a->is_ValueType()) { inc_sp(2); - Node* null_ctl = top(); - Node* not_null_a = null_check_oop(a, &null_ctl, !too_many_traps(Deoptimization::Reason_null_check), false, false); + a = a->as_ValueType()->allocate(this, true)->get_oop(); dec_sp(2); - ne_region->init_req(1, null_ctl); - if (stopped()) { - record_for_igvn(ne_region); - set_control(_gvn.transform(ne_region)); - if (btest == BoolTest::ne) { - { - PreserveJVMState pjvms(this); - int target_bci = iter().get_dest(); - merge(target_bci); - } - record_for_igvn(eq_region); - set_control(_gvn.transform(eq_region)); - } - return; - } - - Node* is_value = is_always_locked(not_null_a); - Node* value_mask = _gvn.MakeConX(markOopDesc::always_locked_pattern); - Node* is_value_cmp = _gvn.transform(new CmpXNode(is_value, value_mask)); - Node* is_value_bol = _gvn.transform(new BoolNode(is_value_cmp, BoolTest::ne)); - IfNode* is_value_iff = create_and_map_if(control(), is_value_bol, PROB_FAIR, COUNT_UNKNOWN); - Node* not_value = _gvn.transform(new IfTrueNode(is_value_iff)); - set_control(_gvn.transform(new IfFalseNode(is_value_iff))); - ne_region->init_req(2, not_value); - - // One of the 2 pointers refers to a value, check if both are of - // the same class + } + if (b->is_ValueType()) { inc_sp(2); - null_ctl = top(); - Node* not_null_b = null_check_oop(b, &null_ctl, !too_many_traps(Deoptimization::Reason_null_check), false, false); + b = b->as_ValueType()->allocate(this, true)->get_oop(); dec_sp(2); - ne_region->init_req(3, null_ctl); - if (stopped()) { - record_for_igvn(ne_region); - set_control(_gvn.transform(ne_region)); - if (btest == BoolTest::ne) { - { - PreserveJVMState pjvms(this); - int target_bci = iter().get_dest(); - merge(target_bci); - } - record_for_igvn(eq_region); - set_control(_gvn.transform(eq_region)); - } - return; - } - Node* kls_a = load_object_klass(not_null_a); - Node* kls_b = load_object_klass(not_null_b); - Node* kls_cmp = CmpP(kls_a, kls_b); - Node* kls_bol = _gvn.transform(new BoolNode(kls_cmp, BoolTest::ne)); - IfNode* kls_iff = create_and_map_if(control(), kls_bol, PROB_FAIR, COUNT_UNKNOWN); - Node* kls_ne = _gvn.transform(new IfTrueNode(kls_iff)); - set_control(_gvn.transform(new IfFalseNode(kls_iff))); - ne_region->init_req(4, kls_ne); + } + + const TypeOopPtr* ta = _gvn.type(a)->isa_oopptr(); + const TypeOopPtr* tb = _gvn.type(b)->isa_oopptr(); + + if (ta == NULL || !ta->can_be_value_type_raw() || + tb == NULL || !tb->can_be_value_type_raw()) { + Node* cmp = CmpP(a, b); + cmp = optimize_cmp_with_klass(cmp); + do_if(btest, cmp); + return; + } + Node* cmp = CmpP(a, b); + cmp = optimize_cmp_with_klass(cmp); + Node* eq_region = NULL; + if (btest == BoolTest::eq) { + do_if(btest, cmp, true); if (stopped()) { - record_for_igvn(ne_region); - set_control(_gvn.transform(ne_region)); - if (btest == BoolTest::ne) { - { - PreserveJVMState pjvms(this); - int target_bci = iter().get_dest(); - merge(target_bci); - } - record_for_igvn(eq_region); - set_control(_gvn.transform(eq_region)); - } return; } - // Both are values of the same class, we need to perform a - // substitutability test. Delegate to - // ValueBootstrapMethods::isSubstitutable(). - - Node* ne_io_phi = PhiNode::make(ne_region, i_o()); - Node* mem = reset_memory(); - Node* ne_mem_phi = PhiNode::make(ne_region, mem); - - Node* eq_io_phi = NULL; - Node* eq_mem_phi = NULL; - if (eq_region != NULL) { - eq_io_phi = PhiNode::make(eq_region, i_o()); - eq_mem_phi = PhiNode::make(eq_region, mem); - } - - set_all_memory(mem); - - kill_dead_locals(); - CallStaticJavaNode *call = new CallStaticJavaNode(C, TypeFunc::make(subst_method), SharedRuntime::get_resolve_static_call_stub(), subst_method, bci()); - call->set_override_symbolic_info(true); - call->init_req(TypeFunc::Parms, not_null_a); - call->init_req(TypeFunc::Parms+1, not_null_b); - inc_sp(2); - set_edges_for_java_call(call, false, false); - Node* ret = set_results_for_java_call(call, false, true); - dec_sp(2); - - // Test the return value of ValueBootstrapMethods::isSubstitutable() - Node* subst_cmp = _gvn.transform(new CmpINode(ret, intcon(1))); - Node* ctl = C->top(); - if (btest == BoolTest::eq) { - PreserveJVMState pjvms(this); - do_if(btest, subst_cmp); - if (!stopped()) { - ctl = control(); - } - } else { - assert(btest == BoolTest::ne, "only eq or ne"); + } else { + assert(btest == BoolTest::ne, "only eq or ne"); + Node* is_not_equal = NULL; + eq_region = new RegionNode(3); + { PreserveJVMState pjvms(this); - do_if(btest, subst_cmp, false, &ctl); + do_if(btest, cmp, false, &is_not_equal); if (!stopped()) { - eq_region->init_req(2, control()); - eq_io_phi->init_req(2, i_o()); - eq_mem_phi->init_req(2, reset_memory()); + eq_region->init_req(1, control()); } } - ne_region->init_req(5, ctl); - ne_io_phi->init_req(5, i_o()); - ne_mem_phi->init_req(5, reset_memory()); - + if (is_not_equal == NULL || is_not_equal->is_top()) { + record_for_igvn(eq_region); + set_control(_gvn.transform(eq_region)); + return; + } + set_control(is_not_equal); + } + // Pointers not equal, check for values + Node* ne_region = new RegionNode(6); + inc_sp(2); + Node* null_ctl = top(); + Node* not_null_a = null_check_oop(a, &null_ctl, !too_many_traps(Deoptimization::Reason_null_check), false, false); + dec_sp(2); + ne_region->init_req(1, null_ctl); + if (stopped()) { record_for_igvn(ne_region); set_control(_gvn.transform(ne_region)); - set_i_o(_gvn.transform(ne_io_phi)); - set_all_memory(_gvn.transform(ne_mem_phi)); - if (btest == BoolTest::ne) { { PreserveJVMState pjvms(this); int target_bci = iter().get_dest(); merge(target_bci); } - record_for_igvn(eq_region); set_control(_gvn.transform(eq_region)); - set_i_o(_gvn.transform(eq_io_phi)); - set_all_memory(_gvn.transform(eq_mem_phi)); } - - return; - } - // In the case were both operands might be value types, we need to - // use the new acmp implementation. Otherwise, i.e. if one operand - // is not a value type, we can use the old acmp implementation. - Node* cmp = C->optimize_acmp(&_gvn, a, b); - if (cmp != NULL) { - // Use optimized/old acmp - cmp = optimize_cmp_with_klass(_gvn.transform(cmp)); - do_if(btest, cmp); return; } - Node* ctrl = NULL; - bool safe_for_replace = true; - if (ACmpOnValues != 1) { - // Emit old acmp before new acmp for quick a != b check - cmp = CmpP(a, b); - cmp = optimize_cmp_with_klass(_gvn.transform(cmp)); + Node* is_value = is_always_locked(not_null_a); + Node* value_mask = _gvn.MakeConX(markOopDesc::always_locked_pattern); + Node* is_value_cmp = _gvn.transform(new CmpXNode(is_value, value_mask)); + Node* is_value_bol = _gvn.transform(new BoolNode(is_value_cmp, BoolTest::ne)); + IfNode* is_value_iff = create_and_map_if(control(), is_value_bol, PROB_FAIR, COUNT_UNKNOWN); + Node* not_value = _gvn.transform(new IfTrueNode(is_value_iff)); + set_control(_gvn.transform(new IfFalseNode(is_value_iff))); + ne_region->init_req(2, not_value); + + // One of the 2 pointers refers to a value, check if both are of + // the same class + inc_sp(2); + null_ctl = top(); + Node* not_null_b = null_check_oop(b, &null_ctl, !too_many_traps(Deoptimization::Reason_null_check), false, false); + dec_sp(2); + ne_region->init_req(3, null_ctl); + if (stopped()) { + record_for_igvn(ne_region); + set_control(_gvn.transform(ne_region)); if (btest == BoolTest::ne) { - do_if(btest, cmp, true); - if (stopped()) { - return; // Never equal - } - } else if (btest == BoolTest::eq) { - Node* is_equal = NULL; { PreserveJVMState pjvms(this); - do_if(btest, cmp, false, &is_equal); - if (!stopped()) { - // Not equal, skip valuetype check - ctrl = new RegionNode(3); - ctrl->init_req(1, control()); - _gvn.set_type(ctrl, Type::CONTROL); - record_for_igvn(ctrl); - safe_for_replace = false; - } - } - if (is_equal == NULL) { - assert(ctrl != NULL, "no control left"); - set_control(_gvn.transform(ctrl)); - return; // Never equal + int target_bci = iter().get_dest(); + merge(target_bci); } - set_control(is_equal); + record_for_igvn(eq_region); + set_control(_gvn.transform(eq_region)); } + return; } + Node* kls_a = load_object_klass(not_null_a); + Node* kls_b = load_object_klass(not_null_b); + Node* kls_cmp = CmpP(kls_a, kls_b); + Node* kls_bol = _gvn.transform(new BoolNode(kls_cmp, BoolTest::ne)); + IfNode* kls_iff = create_and_map_if(control(), kls_bol, PROB_FAIR, COUNT_UNKNOWN); + Node* kls_ne = _gvn.transform(new IfTrueNode(kls_iff)); + set_control(_gvn.transform(new IfFalseNode(kls_iff))); + ne_region->init_req(4, kls_ne); - // Null check operand before loading the is_value bit - bool speculate = false; - if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(b))) { - // Operand 'b' is never null, swap operands to avoid null check - swap(a, b); - } else if (!too_many_traps(Deoptimization::Reason_speculate_null_check)) { - // Speculate on non-nullness of one operand - if (!_gvn.type(a)->speculative_maybe_null()) { - speculate = true; - } else if (!_gvn.type(b)->speculative_maybe_null()) { - speculate = true; - swap(a, b); + if (stopped()) { + record_for_igvn(ne_region); + set_control(_gvn.transform(ne_region)); + if (btest == BoolTest::ne) { + { + PreserveJVMState pjvms(this); + int target_bci = iter().get_dest(); + merge(target_bci); + } + record_for_igvn(eq_region); + set_control(_gvn.transform(eq_region)); } + return; } + // Both are values of the same class, we need to perform a + // substitutability test. Delegate to + // ValueBootstrapMethods::isSubstitutable(). + + Node* ne_io_phi = PhiNode::make(ne_region, i_o()); + Node* mem = reset_memory(); + Node* ne_mem_phi = PhiNode::make(ne_region, mem); + + Node* eq_io_phi = NULL; + Node* eq_mem_phi = NULL; + if (eq_region != NULL) { + eq_io_phi = PhiNode::make(eq_region, i_o()); + eq_mem_phi = PhiNode::make(eq_region, mem); + } + + set_all_memory(mem); + + kill_dead_locals(); + CallStaticJavaNode *call = new CallStaticJavaNode(C, TypeFunc::make(subst_method), SharedRuntime::get_resolve_static_call_stub(), subst_method, bci()); + call->set_override_symbolic_info(true); + call->init_req(TypeFunc::Parms, not_null_a); + call->init_req(TypeFunc::Parms+1, not_null_b); inc_sp(2); - Node* null_ctl = top(); - Node* not_null_a = null_check_oop(a, &null_ctl, speculate, safe_for_replace, speculate); - assert(!stopped(), "operand is always null"); + set_edges_for_java_call(call, false, false); + Node* ret = set_results_for_java_call(call, false, true); dec_sp(2); - Node* region = new RegionNode(2); - Node* is_value = new PhiNode(region, TypeX_X); - if (null_ctl != top()) { - assert(!speculate, "should never be null"); - region->add_req(null_ctl); - is_value->add_req(_gvn.MakeConX(0)); - } - Node* value_mask = _gvn.MakeConX(markOopDesc::always_locked_pattern); - if (ACmpOnValues == 1) { - Node* mark_addr = basic_plus_adr(not_null_a, oopDesc::mark_offset_in_bytes()); - Node* mark = make_load(NULL, mark_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); - Node* not_mark = _gvn.transform(new XorXNode(mark, _gvn.MakeConX(-1))); - Node* andn = _gvn.transform(new AndXNode(not_mark, value_mask)); - Node* neg_if_value = _gvn.transform(new SubXNode(andn, _gvn.MakeConX(1))); - is_value->init_req(1, _gvn.transform(new RShiftXNode(neg_if_value, _gvn.intcon(63)))); + // Test the return value of ValueBootstrapMethods::isSubstitutable() + Node* subst_cmp = _gvn.transform(new CmpINode(ret, intcon(1))); + Node* ctl = C->top(); + if (btest == BoolTest::eq) { + PreserveJVMState pjvms(this); + do_if(btest, subst_cmp); + if (!stopped()) { + ctl = control(); + } } else { - is_value->init_req(1, is_always_locked(not_null_a)); - } - region->init_req(1, control()); + assert(btest == BoolTest::ne, "only eq or ne"); + PreserveJVMState pjvms(this); + do_if(btest, subst_cmp, false, &ctl); + if (!stopped()) { + eq_region->init_req(2, control()); + eq_io_phi->init_req(2, i_o()); + eq_mem_phi->init_req(2, reset_memory()); + } + } + ne_region->init_req(5, ctl); + ne_io_phi->init_req(5, i_o()); + ne_mem_phi->init_req(5, reset_memory()); + + record_for_igvn(ne_region); + set_control(_gvn.transform(ne_region)); + set_i_o(_gvn.transform(ne_io_phi)); + set_all_memory(_gvn.transform(ne_mem_phi)); - set_control(_gvn.transform(region)); - is_value = _gvn.transform(is_value); - - if (ACmpOnValues == 1) { - // Perturbe oop if operand is a value type to make comparison fail - Node* pert = _gvn.transform(new AddPNode(a, a, is_value)); - cmp = _gvn.transform(new CmpPNode(pert, b)); - } else { - // Check for a value type because we already know that operands are equal - cmp = _gvn.transform(new CmpXNode(is_value, value_mask)); - btest = (btest == BoolTest::eq) ? BoolTest::ne : BoolTest::eq; - } - cmp = optimize_cmp_with_klass(cmp); - do_if(btest, cmp); + if (btest == BoolTest::ne) { + { + PreserveJVMState pjvms(this); + int target_bci = iter().get_dest(); + merge(target_bci); + } - if (ctrl != NULL) { - ctrl->init_req(2, control()); - set_control(_gvn.transform(ctrl)); + record_for_igvn(eq_region); + set_control(_gvn.transform(eq_region)); + set_i_o(_gvn.transform(eq_io_phi)); + set_all_memory(_gvn.transform(eq_mem_phi)); } }