--- old/src/hotspot/cpu/x86/templateTable_x86.cpp 2019-07-03 10:04:39.715266376 +0200 +++ new/src/hotspot/cpu/x86/templateTable_x86.cpp 2019-07-03 10:04:39.419266380 +0200 @@ -2471,7 +2471,7 @@ __ pop_ptr(rdx); const int is_value_mask = markOopDesc::always_locked_pattern; - if (EnableValhalla && ACmpOnValues == 3) { + if (EnableValhalla) { __ cmpoop(rdx, rax); __ jcc(Assembler::equal, (cc == equal) ? taken : not_taken); @@ -2505,32 +2505,7 @@ __ stop("Not reachable"); } - - if (EnableValhalla && ACmpOnValues == 1) { - Label is_null; - __ testptr(rdx, rdx); - __ jcc(Assembler::zero, is_null); - __ movptr(rbx, Address(rdx, oopDesc::mark_offset_in_bytes())); - __ andptr(rbx, is_value_mask); - __ cmpl(rbx, is_value_mask); - __ setb(Assembler::equal, rbx); - __ movzbl(rbx, rbx); - __ orptr(rdx, rbx); - __ bind(is_null); - } - __ cmpoop(rdx, rax); - - if (EnableValhalla && ACmpOnValues == 2) { - __ jcc(Assembler::notEqual, (cc == not_equal) ? taken : not_taken); - __ testptr(rdx, rdx); - __ jcc(Assembler::zero, (cc == equal) ? taken : not_taken); - __ movptr(rbx, Address(rdx, oopDesc::mark_offset_in_bytes())); - __ andptr(rbx, is_value_mask); - __ cmpl(rbx, is_value_mask); - cc = (cc == equal) ? not_equal : equal; - } - __ jcc(j_not(cc), not_taken); __ bind(taken); branch(false, false); --- old/src/hotspot/share/c1/c1_GraphBuilder.cpp 2019-07-03 10:04:40.287266368 +0200 +++ new/src/hotspot/share/c1/c1_GraphBuilder.cpp 2019-07-03 10:04:39.995266372 +0200 @@ -1243,8 +1243,7 @@ bool is_bb = tsux->bci() < stream()->cur_bci() || fsux->bci() < stream()->cur_bci(); bool subst_check = false; - if (EnableValhalla && ACmpOnValues == 3 && - (stream()->cur_bc() == Bytecodes::_if_acmpeq || stream()->cur_bc() == Bytecodes::_if_acmpne) && + if (EnableValhalla && (stream()->cur_bc() == Bytecodes::_if_acmpeq || stream()->cur_bc() == Bytecodes::_if_acmpne) && method() != ciEnv::current()->ValueBootstrapMethods_klass()->find_method(ciSymbol::isSubstitutable_name(), ciSymbol::object_object_boolean_signature())) { // If current method is ValueBootstrapMethods::isSubstitutable(), // compile the acmp as a regular pointer comparison otherwise we --- old/src/hotspot/share/opto/callnode.cpp 2019-07-03 10:04:40.859266360 +0200 +++ new/src/hotspot/share/opto/callnode.cpp 2019-07-03 10:04:40.567266364 +0200 @@ -1021,7 +1021,7 @@ return true; // call into runtime or uncommon trap } Bytecodes::Code bc = jvms()->method()->java_code_at_bci(_bci); - if (ACmpOnValues == 3 && (bc == Bytecodes::_if_acmpeq || bc == Bytecodes::_if_acmpne)) { + if (EnableValhalla && (bc == Bytecodes::_if_acmpeq || bc == Bytecodes::_if_acmpne)) { return true; } ciMethod* symbolic_info = jvms()->method()->get_method_at_bci(_bci); --- old/src/hotspot/share/opto/escape.cpp 2019-07-03 10:04:41.415266352 +0200 +++ new/src/hotspot/share/opto/escape.cpp 2019-07-03 10:04:41.131266356 +0200 @@ -173,8 +173,7 @@ // scalar replaceable objects in split_unique_types(). _mergemem_worklist.append(n->as_MergeMem()); } else if (OptimizePtrCompare && n->is_Cmp() && - ((n->Opcode() == Op_CmpP && !(((CmpPNode*)n)->has_perturbed_operand() != NULL)) || - n->Opcode() == Op_CmpN)) { + (n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) { // Collect compare pointers nodes. ptr_cmp_worklist.append(n); } else if (n->is_MemBarStoreStore()) { --- old/src/hotspot/share/opto/mulnode.cpp 2019-07-03 10:04:42.007266344 +0200 +++ new/src/hotspot/share/opto/mulnode.cpp 2019-07-03 10:04:41.707266348 +0200 @@ -598,7 +598,7 @@ } if (con == markOopDesc::always_locked_pattern) { - assert(EnableValhalla || ACmpOnValues == 3, "should only be used for value types"); + assert(EnableValhalla, "should only be used for value types"); if (in(1)->is_Load() && phase->type(in(1)->in(MemNode::Address))->is_valuetypeptr()) { return in(2); // Obj is known to be a value type } --- 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)); } } --- old/src/hotspot/share/opto/subnode.cpp 2019-07-03 10:04:43.127266329 +0200 +++ new/src/hotspot/share/opto/subnode.cpp 2019-07-03 10:04:42.843266333 +0200 @@ -840,14 +840,6 @@ // Simplify an CmpP (compare 2 pointers) node, based on local information. // If both inputs are constants, compare them. const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const { - if (ACmpOnValues != 3 && - (t1->isa_valuetype() || t2->isa_valuetype() || - ((t1->is_valuetypeptr() || t2->is_valuetypeptr()) && - (!t1->maybe_null() || !t2->maybe_null())))) { - // One operand is a value type and one operand is never null, fold to constant false - return TypeInt::CC_GT; - } - const TypePtr *r0 = t1->is_ptr(); // Handy access const TypePtr *r1 = t2->is_ptr(); @@ -986,17 +978,6 @@ // checking to see an unknown klass subtypes a known klass with no subtypes; // this only happens on an exact match. We can shorten this test by 1 load. Node* CmpPNode::Ideal(PhaseGVN *phase, bool can_reshape) { - Node* pert = has_perturbed_operand(); - if (pert != NULL) { - // Optimize new acmp - Node* a = pert->in(AddPNode::Base); // unperturbed a - Node* b = in(2); - Node* cmp = phase->C->optimize_acmp(phase, a, b); - if (cmp != NULL) { - return cmp; - } - } - // Normalize comparisons between Java mirrors into comparisons of the low- // level klass, where a dependent load could be shortened. // @@ -1113,22 +1094,6 @@ return this; } -// Checks if one operand is perturbed and returns it -Node* CmpPNode::has_perturbed_operand() const { - // We always perturbe the first operand - AddPNode* addP = in(1)->isa_AddP(); - if (addP != NULL) { - Node* base = addP->in(AddPNode::Base); - if (base->is_top()) { - // RawPtr comparison - return NULL; - } - assert(EnableValhalla && ACmpOnValues == 1, "unexpected perturbed oop"); - return in(1); - } - return NULL; -} - //============================================================================= //------------------------------sub-------------------------------------------- // Simplify an CmpN (compare 2 pointers) node, based on local information. --- old/src/hotspot/share/opto/subnode.hpp 2019-07-03 10:04:43.687266321 +0200 +++ new/src/hotspot/share/opto/subnode.hpp 2019-07-03 10:04:43.399266325 +0200 @@ -177,7 +177,6 @@ virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *sub( const Type *, const Type * ) const; - Node* has_perturbed_operand() const; }; //------------------------------CmpNNode-------------------------------------- --- old/src/hotspot/share/runtime/arguments.cpp 2019-07-03 10:04:44.239266313 +0200 +++ new/src/hotspot/share/runtime/arguments.cpp 2019-07-03 10:04:43.947266317 +0200 @@ -2141,9 +2141,6 @@ */ } } - if (!EnableValhalla && ACmpOnValues != 3) { - FLAG_SET_CMDLINE(ACmpOnValues, 0); - } return status; } --- old/src/hotspot/share/runtime/globals.hpp 2019-07-03 10:04:44.807266305 +0200 +++ new/src/hotspot/share/runtime/globals.hpp 2019-07-03 10:04:44.523266309 +0200 @@ -2499,13 +2499,6 @@ \ develop(bool, ScalarizeValueTypes, true, \ "Scalarize value types in compiled code") \ - \ - experimental(uint, ACmpOnValues, 3, \ - "0 = regular acmp" \ - "1 = always false for value, perturbation scheme" \ - "2 = always false for value" \ - "3 = substitutability test") \ - range(0, 3) \ --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java 2019-07-03 10:04:45.359266298 +0200 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNewAcmp.java 2019-07-03 10:04:45.075266302 +0200 @@ -88,18 +88,6 @@ int x; } -// Mark test methods that return always false -@Retention(RetentionPolicy.RUNTIME) -@interface AlwaysFalse { - int[] valid_for() default {1, 2}; -} - -// Mark test methods that return always true -@Retention(RetentionPolicy.RUNTIME) -@interface AlwaysTrue { - int[] valid_for() default {1, 2}; -} - // Mark test methods that return false if the argument is null @Retention(RetentionPolicy.RUNTIME) @interface FalseIfNull { } @@ -197,77 +185,62 @@ return get(v) == get(o); // only true if both null } - @AlwaysFalse public boolean testEq07_1(MyValue1 v1, MyValue1 v2) { return getNotNull(v1) == (Object)v2; // false } - @AlwaysFalse public boolean testEq07_2(MyValue1 v1, MyValue1 v2) { return (Object)v1 == getNotNull(v2); // false } - @AlwaysFalse public boolean testEq07_3(MyValue1 v1, MyValue1 v2) { return getNotNull(v1) == getNotNull(v2); // false } - @AlwaysFalse public boolean testEq08_1(MyValue1 v, Object u) { return getNotNull(v) == u; // false } - @AlwaysFalse public boolean testEq08_2(MyValue1 v, Object u) { return (Object)v == getNotNull(u); // false } - @AlwaysFalse public boolean testEq08_3(MyValue1 v, Object u) { return getNotNull(v) == getNotNull(u); // false } - @AlwaysFalse public boolean testEq09_1(Object u, MyValue1 v) { return getNotNull(u) == (Object)v; // false } - @AlwaysFalse public boolean testEq09_2(Object u, MyValue1 v) { return u == getNotNull(v); // false } - @AlwaysFalse public boolean testEq09_3(Object u, MyValue1 v) { return getNotNull(u) == getNotNull(v); // false } - @AlwaysFalse public boolean testEq10_1(MyObject o, MyValue1 v) { return getNotNull(o) == (Object)v; // false } - @AlwaysFalse public boolean testEq10_2(MyObject o, MyValue1 v) { return o == getNotNull(v); // false } - @AlwaysFalse public boolean testEq10_3(MyObject o, MyValue1 v) { return getNotNull(o) == getNotNull(v); // false } - @AlwaysFalse public boolean testEq11_1(MyValue1 v, MyObject o) { return getNotNull(v) == o; // false } - @AlwaysFalse public boolean testEq11_2(MyValue1 v, MyObject o) { return (Object)v == getNotNull(o); // false } - @AlwaysFalse public boolean testEq11_3(MyValue1 v, MyObject o) { return getNotNull(v) == getNotNull(o); // false } @@ -356,32 +329,26 @@ return get(v) == get(a); // only true if both null } - @AlwaysFalse public boolean testEq19_1(Object[] a, MyValue1 v) { return getNotNull(a) == (Object)v; // false } - @AlwaysFalse public boolean testEq19_2(Object[] a, MyValue1 v) { return a == getNotNull(v); // false } - @AlwaysFalse public boolean testEq19_3(Object[] a, MyValue1 v) { return getNotNull(a) == getNotNull(v); // false } - @AlwaysFalse public boolean testEq20_1(MyValue1 v, Object[] a) { return getNotNull(v) == a; // false } - @AlwaysFalse public boolean testEq20_2(MyValue1 v, Object[] a) { return (Object)v == getNotNull(a); // false } - @AlwaysFalse public boolean testEq20_3(MyValue1 v, Object[] a) { return getNotNull(v) == getNotNull(a); // false } @@ -437,32 +404,26 @@ return get(u) == get(v); // only true if both null } - @AlwaysFalse public boolean testEq24_1(MyValue1 v, MyInterface u) { return getNotNull(v) == u; // false } - @AlwaysFalse public boolean testEq24_2(MyValue1 v, MyInterface u) { return (Object)v == getNotNull(u); // false } - @AlwaysFalse public boolean testEq24_3(MyValue1 v, MyInterface u) { return getNotNull(v) == getNotNull(u); // false } - @AlwaysFalse public boolean testEq25_1(MyInterface u, MyValue1 v) { return getNotNull(u) == (Object)v; // false } - @AlwaysFalse public boolean testEq25_2(MyInterface u, MyValue1 v) { return u == getNotNull(v); // false } - @AlwaysFalse public boolean testEq25_3(MyInterface u, MyValue1 v) { return getNotNull(u) == getNotNull(v); // false } @@ -539,32 +500,26 @@ return get(v) == get(a); // only true if both null } - @AlwaysFalse public boolean testEq32_1(MyInterface[] a, MyValue1 v) { return getNotNull(a) == (Object)v; // false } - @AlwaysFalse public boolean testEq32_2(MyInterface[] a, MyValue1 v) { return a == getNotNull(v); // false } - @AlwaysFalse public boolean testEq32_3(MyInterface[] a, MyValue1 v) { return getNotNull(a) == getNotNull(v); // false } - @AlwaysFalse public boolean testEq33_1(MyValue1 v, MyInterface[] a) { return getNotNull(v) == a; // false } - @AlwaysFalse public boolean testEq33_2(MyValue1 v, MyInterface[] a) { return (Object)v == getNotNull(a); // false } - @AlwaysFalse public boolean testEq33_3(MyValue1 v, MyInterface[] a) { return getNotNull(v) == getNotNull(a); // false } @@ -789,77 +744,62 @@ return get(v) != get(o); // only false if both null } - @AlwaysTrue public boolean testNotEq07_1(MyValue1 v1, MyValue1 v2) { return getNotNull(v1) != (Object)v2; // true } - @AlwaysTrue public boolean testNotEq07_2(MyValue1 v1, MyValue1 v2) { return (Object)v1 != getNotNull(v2); // true } - @AlwaysTrue public boolean testNotEq07_3(MyValue1 v1, MyValue1 v2) { return getNotNull(v1) != getNotNull(v2); // true } - @AlwaysTrue public boolean testNotEq08_1(MyValue1 v, Object u) { return getNotNull(v) != u; // true } - @AlwaysTrue public boolean testNotEq08_2(MyValue1 v, Object u) { return (Object)v != getNotNull(u); // true } - @AlwaysTrue public boolean testNotEq08_3(MyValue1 v, Object u) { return getNotNull(v) != getNotNull(u); // true } - @AlwaysTrue public boolean testNotEq09_1(Object u, MyValue1 v) { return getNotNull(u) != (Object)v; // true } - @AlwaysTrue public boolean testNotEq09_2(Object u, MyValue1 v) { return u != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq09_3(Object u, MyValue1 v) { return getNotNull(u) != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq10_1(MyObject o, MyValue1 v) { return getNotNull(o) != (Object)v; // true } - @AlwaysTrue public boolean testNotEq10_2(MyObject o, MyValue1 v) { return o != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq10_3(MyObject o, MyValue1 v) { return getNotNull(o) != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq11_1(MyValue1 v, MyObject o) { return getNotNull(v) != o; // true } - @AlwaysTrue public boolean testNotEq11_2(MyValue1 v, MyObject o) { return (Object)v != getNotNull(o); // true } - @AlwaysTrue public boolean testNotEq11_3(MyValue1 v, MyObject o) { return getNotNull(v) != getNotNull(o); // true } @@ -948,32 +888,26 @@ return get(v) != get(a); // only false if both null } - @AlwaysTrue public boolean testNotEq19_1(Object[] a, MyValue1 v) { return getNotNull(a) != (Object)v; // true } - @AlwaysTrue public boolean testNotEq19_2(Object[] a, MyValue1 v) { return a != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq19_3(Object[] a, MyValue1 v) { return getNotNull(a) != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq20_1(MyValue1 v, Object[] a) { return getNotNull(v) != a; // true } - @AlwaysTrue public boolean testNotEq20_2(MyValue1 v, Object[] a) { return (Object)v != getNotNull(a); // true } - @AlwaysTrue public boolean testNotEq20_3(MyValue1 v, Object[] a) { return getNotNull(v) != getNotNull(a); // true } @@ -1029,32 +963,26 @@ return get(u) != get(v); // only false if both null } - @AlwaysTrue public boolean testNotEq24_1(MyValue1 v, MyInterface u) { return getNotNull(v) != u; // true } - @AlwaysTrue public boolean testNotEq24_2(MyValue1 v, MyInterface u) { return (Object)v != getNotNull(u); // true } - @AlwaysTrue public boolean testNotEq24_3(MyValue1 v, MyInterface u) { return getNotNull(v) != getNotNull(u); // true } - @AlwaysTrue public boolean testNotEq25_1(MyInterface u, MyValue1 v) { return getNotNull(u) != (Object)v; // true } - @AlwaysTrue public boolean testNotEq25_2(MyInterface u, MyValue1 v) { return u != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq25_3(MyInterface u, MyValue1 v) { return getNotNull(u) != getNotNull(v); // true } @@ -1131,32 +1059,26 @@ return get(v) != get(a); // only false if both null } - @AlwaysTrue public boolean testNotEq32_1(MyInterface[] a, MyValue1 v) { return getNotNull(a) != (Object)v; // true } - @AlwaysTrue public boolean testNotEq32_2(MyInterface[] a, MyValue1 v) { return a != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq32_3(MyInterface[] a, MyValue1 v) { return getNotNull(a) != getNotNull(v); // true } - @AlwaysTrue public boolean testNotEq33_1(MyValue1 v, MyInterface[] a) { return getNotNull(v) != a; // true } - @AlwaysTrue public boolean testNotEq33_2(MyValue1 v, MyInterface[] a) { return (Object)v != getNotNull(a); // true } - @AlwaysTrue public boolean testNotEq33_3(MyValue1 v, MyInterface[] a) { return getNotNull(v) != getNotNull(a); // true } @@ -1333,16 +1255,6 @@ return m.isAnnotationPresent(FalseIfNull.class); } - public boolean alwaysTrue(Method m) { - return m.isAnnotationPresent(AlwaysTrue.class) && - Arrays.asList(((AlwaysTrue)m.getAnnotation(AlwaysTrue.class)).valid_for()).contains(ACmpOnValues); - } - - public boolean alwaysFalse(Method m) { - return m.isAnnotationPresent(AlwaysFalse.class) && - Arrays.asList(((AlwaysFalse)m.getAnnotation(AlwaysFalse.class)).valid_for()).contains(ACmpOnValues); - } - public boolean isNegated(Method m) { return m.getName().startsWith("testNot"); } @@ -1398,7 +1310,6 @@ protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); protected static final long TieredStopAtLevel = (Long)WHITE_BOX.getVMFlag("TieredStopAtLevel"); protected static final int COMP_LEVEL_FULL_OPTIMIZATION = get_full_opt_level(); - protected static final long ACmpOnValues = (Long)WHITE_BOX.getVMFlag("ACmpOnValues"); // FIXME: temp -- special handling for C1 testing. protected static final boolean EnableValhallaC1 = (Boolean)WHITE_BOX.getVMFlag("EnableValhallaC1"); @@ -1443,7 +1354,7 @@ // Avoid acmp in the computation of the expected result! boolean equal = equalities[i][j]; equal = isNegated(m) ? !equal : equal; - boolean expected = alwaysTrue(m) || ((i == 0 || j == 0) && trueIfNull(m)) || (!alwaysFalse(m) && equal && !(i == 0 && falseIfNull(m))); + boolean expected = ((i == 0 || j == 0) && trueIfNull(m)) || (equal && !(i == 0 && falseIfNull(m))); for (int run = 0; run < warmup; ++run) { Boolean result = (Boolean)m.invoke(this, args[i], args[j]); if (result != expected && WHITE_BOX.isMethodCompiled(m, false) && warmup == 1) { @@ -1469,15 +1380,15 @@ MyValue1.setX(MyValue1.createDefault(), 42), MyValue2.setX(MyValue2.createDefault(), 42), }; - boolean[][] equalities = { { true, false, false, false, false, false, false, false, false }, - { false, true, false, false, false, false, false, false, false }, - { false, false, true, false, false, false, false, false, false }, - { false, false, false, ACmpOnValues == 3,false, false, false, ACmpOnValues == 3, false }, - { false, false, false, false, true, false, false, false, false }, - { false, false, false, false, false, true, false, false, false }, - { false, false, false, false, false, false, ACmpOnValues == 3, false, false }, - { false, false, false, ACmpOnValues == 3,false, false, false, ACmpOnValues == 3, false }, - { false, false, false, false, false, false, false, false, ACmpOnValues == 3 } }; + boolean[][] equalities = { { true, false, false, false, false, false, false, false, false }, + { false, true, false, false, false, false, false, false, false }, + { false, false, true, false, false, false, false, false, false }, + { false, false, false, true, false, false, false, true, false }, + { false, false, false, false, true, false, false, false, false }, + { false, false, false, false, false, true, false, false, false }, + { false, false, false, false, false, false, true, false, false }, + { false, false, false, true, false, false, false, true, false }, + { false, false, false, false, false, false, false, false, true } }; // Run tests for (Method m : getClass().getMethods()) { @@ -1505,36 +1416,16 @@ Asserts.assertFalse(cmpAlwaysUnEqual1(args[1], args[2])); Asserts.assertTrue(cmpAlwaysUnEqual2(args[1], args[2])); - boolean compiled = WHITE_BOX.isMethodCompiled(cmpAlwaysUnEqual3_m, false); boolean res = cmpAlwaysUnEqual3(args[3]); - if (ACmpOnValues != 3) { - Asserts.assertFalse(res); - } else if (compiled) { - Asserts.assertTrue(res); - } - compiled = WHITE_BOX.isMethodCompiled(cmpAlwaysUnEqual4_m, false); + Asserts.assertTrue(res); res = cmpAlwaysUnEqual4(args[3]); - if (ACmpOnValues != 3) { - Asserts.assertTrue(res); - } else if (compiled) { - Asserts.assertFalse(res); - } + Asserts.assertFalse(res); int idx = i % args.length; - compiled = WHITE_BOX.isMethodCompiled(cmpSometimesEqual1_m, false); res = cmpSometimesEqual1(args[idx]); - if (ACmpOnValues != 3) { - Asserts.assertEQ(res, args[idx] == null || !args[idx].getClass().isInlineClass()); - } else if (compiled) { - Asserts.assertTrue(res); - } - compiled = WHITE_BOX.isMethodCompiled(cmpSometimesEqual2_m, false); + Asserts.assertTrue(res); res = cmpSometimesEqual2(args[idx]); - if (ACmpOnValues != 3) { - Asserts.assertNE(res, args[idx] == null || !args[idx].getClass().isInlineClass()); - } else if (compiled) { - Asserts.assertFalse(res); - } + Asserts.assertFalse(res); } } @@ -1582,35 +1473,27 @@ } int scenario = -1; - for (int nullMode = 0; nullMode <= 2; nullMode++) { // null mode - for (int onVal = 0; onVal < 2; onVal++) { // 0 = default, 1 = -XX:ACmpOnValues=3 - for (int incrInline = 0; incrInline < 2; incrInline++) { // 0 = default, 1 = -XX:+AlwaysIncrementalInline - scenario++; - System.out.println("Scenario #" + scenario + " -------------------"); - String[] cmds = baseOptions; - if (incrInline != 0) { - cmds = addOptions(cmds, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline"); - } - if (onVal != 0) { - cmds = addOptions(cmds, "-XX:+UnlockExperimentalVMOptions", "-XX:ACmpOnValues=3"); - } - - cmds = addOptions(cmds, "compiler.valhalla.valuetypes.TestNewAcmp"); - cmds = addOptions(cmds, Integer.toString(nullMode)); + for (int nullMode = 0; nullMode <= 2; nullMode++) { // null mode + for (int incrInline = 0; incrInline < 2; incrInline++) { // 0 = default, 1 = -XX:+AlwaysIncrementalInline + scenario++; + System.out.println("Scenario #" + scenario + " -------------------"); + String[] cmds = baseOptions; + if (incrInline != 0) { + cmds = addOptions(cmds, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+AlwaysIncrementalInline"); + } - if (scenarios != null && !scenarios.contains(Integer.toString(scenario))) { - System.out.println("Scenario #" + scenario + " is skipped due to -Dscenarios=" + SCENARIOS); - continue; - } else if (EnableValhallaC1 && onVal == 0) { - System.out.println("Scenario #" + scenario + " is skipped because C1 requires -XX:ACmpOnValues=3"); - continue; - } + cmds = addOptions(cmds, "compiler.valhalla.valuetypes.TestNewAcmp"); + cmds = addOptions(cmds, Integer.toString(nullMode)); - OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); - String output = oa.getOutput(); - oa.shouldHaveExitValue(0); - System.out.println(output); + if (scenarios != null && !scenarios.contains(Integer.toString(scenario))) { + System.out.println("Scenario #" + scenario + " is skipped due to -Dscenarios=" + SCENARIOS); + continue; } + + OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); + String output = oa.getOutput(); + oa.shouldHaveExitValue(0); + System.out.println(output); } } } --- old/test/hotspot/jtreg/runtime/valhalla/valuetypes/Ifacmp.java 2019-07-03 10:04:45.923266290 +0200 +++ new/test/hotspot/jtreg/runtime/valhalla/valuetypes/Ifacmp.java 2019-07-03 10:04:45.631266294 +0200 @@ -31,13 +31,8 @@ * @summary if_acmpeq/ne bytecode test * @compile Ifacmp.java * @run main/othervm -Xint -Xms16m -Xmx16m -XX:+UseSerialGC - * -XX:+UnlockExperimentalVMOptions -XX:ACmpOnValues=2 - * runtime.valhalla.valuetypes.Ifacmp alwaysFalse - * @run main/othervm -Xint -Xms16m -Xmx16m -XX:+UseSerialGC - * -XX:+UnlockExperimentalVMOptions -XX:ACmpOnValues=3 * runtime.valhalla.valuetypes.Ifacmp * @run main/othervm -Xcomp -Xms16m -Xmx16m -XX:+UseSerialGC - * -XX:+UnlockExperimentalVMOptions -XX:ACmpOnValues=3 * runtime.valhalla.valuetypes.Ifacmp */ public class Ifacmp {