< prev index next >

src/hotspot/share/opto/parse2.cpp

Print this page

        

*** 34,49 **** --- 34,51 ---- #include "opto/addnode.hpp" #include "opto/castnode.hpp" #include "opto/convertnode.hpp" #include "opto/divnode.hpp" #include "opto/idealGraphPrinter.hpp" + #include "opto/idealKit.hpp" #include "opto/matcher.hpp" #include "opto/memnode.hpp" #include "opto/mulnode.hpp" #include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/runtime.hpp" + #include "opto/valuetypenode.hpp" #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" #ifndef PRODUCT extern int explicit_null_checks_inserted,
*** 51,112 **** #endif //---------------------------------array_load---------------------------------- void Parse::array_load(BasicType bt) { const Type* elemtype = Type::TOP; - bool big_val = bt == T_DOUBLE || bt == T_LONG; Node* adr = array_addressing(bt, 0, &elemtype); if (stopped()) return; // guaranteed null or range check ! pop(); // index (already used) ! Node* array = pop(); // the array itself if (elemtype == TypeInt::BOOL) { bt = T_BOOLEAN; } else if (bt == T_OBJECT) { ! elemtype = _gvn.type(array)->is_aryptr()->elem()->make_oopptr(); } const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); ! ! Node* ld = access_load_at(array, adr, adr_type, elemtype, bt, IN_HEAP | IS_ARRAY | C2_CONTROL_DEPENDENT_LOAD); ! if (big_val) { ! push_pair(ld); ! } else { ! push(ld); } } //--------------------------------array_store---------------------------------- void Parse::array_store(BasicType bt) { const Type* elemtype = Type::TOP; ! bool big_val = bt == T_DOUBLE || bt == T_LONG; ! Node* adr = array_addressing(bt, big_val ? 2 : 1, &elemtype); if (stopped()) return; // guaranteed null or range check if (bt == T_OBJECT) { ! array_store_check(); } ! Node* val; // Oop to store ! if (big_val) { ! val = pop_pair(); } else { ! val = pop(); } - pop(); // index (already used) - Node* array = pop(); // the array itself if (elemtype == TypeInt::BOOL) { bt = T_BOOLEAN; } else if (bt == T_OBJECT) { ! elemtype = _gvn.type(array)->is_aryptr()->elem()->make_oopptr(); } const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); ! access_store_at(array, adr, adr_type, val, elemtype, bt, MO_UNORDERED | IN_HEAP | IS_ARRAY); } //------------------------------array_addressing------------------------------- // Pull array and index from the stack. Compute pointer-to-element. --- 53,280 ---- #endif //---------------------------------array_load---------------------------------- void Parse::array_load(BasicType bt) { const Type* elemtype = Type::TOP; Node* adr = array_addressing(bt, 0, &elemtype); if (stopped()) return; // guaranteed null or range check ! Node* idx = pop(); ! Node* ary = pop(); ! ! // Handle value type arrays ! const TypeOopPtr* elemptr = elemtype->make_oopptr(); ! const TypeAryPtr* ary_t = _gvn.type(ary)->is_aryptr(); ! if (elemtype->isa_valuetype() != NULL) { ! // Load from flattened value type array ! ciValueKlass* vk = elemtype->is_valuetype()->value_klass(); ! Node* vt = ValueTypeNode::make_from_flattened(this, vk, ary, adr); ! push(vt); ! return; ! } else if (elemptr != NULL && elemptr->is_valuetypeptr()) { ! // Load from non-flattened value type array (elements can never be null) ! bt = T_VALUETYPE; ! assert(elemptr->meet(TypePtr::NULL_PTR) != elemptr, "value type array elements should never be null"); ! } else if (ValueArrayFlatten && elemptr != NULL && elemptr->can_be_value_type() && ! !ary_t->klass_is_exact()) { ! // Cannot statically determine if array is flattened, emit runtime check ! IdealKit ideal(this); ! IdealVariable res(ideal); ! ideal.declarations_done(); ! Node* kls = load_object_klass(ary); ! Node* tag = load_lh_array_tag(kls); ! ideal.if_then(tag, BoolTest::ne, intcon(Klass::_lh_array_tag_vt_value)); { ! // non flattened ! sync_kit(ideal); ! const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); ! elemtype = ary_t->elem()->make_oopptr(); ! Node* ld = access_load_at(ary, adr, adr_type, elemtype, bt, ! IN_HEAP | IS_ARRAY | C2_CONTROL_DEPENDENT_LOAD); ! ideal.sync_kit(this); ! ideal.set(res, ld); ! } ideal.else_(); { ! // flattened ! sync_kit(ideal); ! Node* k_adr = basic_plus_adr(kls, in_bytes(ArrayKlass::element_klass_offset())); ! Node* elem_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS)); ! Node* obj_size = NULL; ! kill_dead_locals(); ! inc_sp(2); ! Node* alloc_obj = new_instance(elem_klass, NULL, &obj_size, /*deoptimize_on_exception=*/true); ! dec_sp(2); ! ! AllocateNode* alloc = AllocateNode::Ideal_allocation(alloc_obj, &_gvn); ! assert(alloc->maybe_set_complete(&_gvn), ""); ! alloc->initialization()->set_complete_with_arraycopy(); ! BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); ! // Unknown value type so might have reference fields ! if (!bs->array_copy_requires_gc_barriers(false, T_OBJECT, false, BarrierSetC2::Parsing)) { ! int base_off = sizeof(instanceOopDesc); ! Node* dst_base = basic_plus_adr(alloc_obj, base_off); ! Node* countx = obj_size; ! countx = _gvn.transform(new SubXNode(countx, MakeConX(base_off))); ! countx = _gvn.transform(new URShiftXNode(countx, intcon(LogBytesPerLong))); ! ! assert(Klass::_lh_log2_element_size_shift == 0, "use shift in place"); ! Node* lhp = basic_plus_adr(kls, in_bytes(Klass::layout_helper_offset())); ! Node* elem_shift = make_load(NULL, lhp, TypeInt::INT, T_INT, MemNode::unordered); ! uint header = arrayOopDesc::base_offset_in_bytes(T_VALUETYPE); ! Node* base = basic_plus_adr(ary, header); ! idx = Compile::conv_I2X_index(&_gvn, idx, TypeInt::POS, control()); ! Node* scale = _gvn.transform(new LShiftXNode(idx, elem_shift)); ! Node* adr = basic_plus_adr(ary, base, scale); ! ! access_clone(adr, dst_base, countx, false); ! } else { ! ideal.sync_kit(this); ! ideal.make_leaf_call(OptoRuntime::load_unknown_value_Type(), ! CAST_FROM_FN_PTR(address, OptoRuntime::load_unknown_value), ! "load_unknown_value", ! ary, idx, alloc_obj); ! sync_kit(ideal); ! } ! ! insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out_or_null(AllocateNode::RawAddress)); ! ! ideal.sync_kit(this); ! ideal.set(res, alloc_obj); ! } ideal.end_if(); ! sync_kit(ideal); ! push_node(bt, ideal.value(res)); ! return; ! } if (elemtype == TypeInt::BOOL) { bt = T_BOOLEAN; } else if (bt == T_OBJECT) { ! elemtype = ary_t->elem()->make_oopptr(); } const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); ! Node* ld = access_load_at(ary, adr, adr_type, elemtype, bt, IN_HEAP | IS_ARRAY | C2_CONTROL_DEPENDENT_LOAD); ! if (bt == T_VALUETYPE) { ! // Loading a non-flattened (but flattenable) value type from an array ! assert(!gvn().type(ld)->maybe_null(), "value type array elements should never be null"); ! if (elemptr->value_klass()->is_scalarizable()) { ! ld = ValueTypeNode::make_from_oop(this, ld, elemptr->value_klass()); ! } } + + push_node(bt, ld); } //--------------------------------array_store---------------------------------- void Parse::array_store(BasicType bt) { const Type* elemtype = Type::TOP; ! Node* adr = array_addressing(bt, type2size[bt], &elemtype); if (stopped()) return; // guaranteed null or range check + Node* cast_val = NULL; if (bt == T_OBJECT) { ! cast_val = array_store_check(); ! if (stopped()) return; ! } ! Node* val = pop_node(bt); // Value to store ! Node* idx = pop(); // Index in the array ! Node* ary = pop(); // The array itself ! ! const TypeAryPtr* ary_t = _gvn.type(ary)->is_aryptr(); ! if (bt == T_OBJECT) { ! const TypeOopPtr* elemptr = elemtype->make_oopptr(); ! const Type* val_t = _gvn.type(val); ! if (elemtype->isa_valuetype() != NULL) { ! // Store to flattened value type array ! if (!cast_val->is_ValueType()) { ! inc_sp(3); ! cast_val = null_check(cast_val); ! if (stopped()) return; ! dec_sp(3); ! cast_val = ValueTypeNode::make_from_oop(this, cast_val, elemtype->is_valuetype()->value_klass()); ! } ! cast_val->as_ValueType()->store_flattened(this, ary, adr); ! return; ! } else if (elemptr->is_valuetypeptr()) { ! // Store to non-flattened value type array ! if (!cast_val->is_ValueType()) { ! // Can not store null into a value type array ! inc_sp(3); ! cast_val = null_check(cast_val); ! if (stopped()) return; ! dec_sp(3); } ! } else if (elemptr->can_be_value_type() && !ary_t->klass_is_exact() && ! (val->is_ValueType() || val_t == TypePtr::NULL_PTR || val_t->is_oopptr()->can_be_value_type())) { ! if (ValueArrayFlatten) { ! IdealKit ideal(this); ! Node* kls = load_object_klass(ary); ! Node* layout_val = load_lh_array_tag(kls); ! ideal.if_then(layout_val, BoolTest::ne, intcon(Klass::_lh_array_tag_vt_value)); { ! // non flattened ! sync_kit(ideal); ! ! if (!val->is_ValueType() && TypePtr::NULL_PTR->higher_equal(val_t)) { ! gen_value_type_array_guard(ary, val, 3); ! } ! ! const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); ! elemtype = ary_t->elem()->make_oopptr(); ! access_store_at(ary, adr, adr_type, val, elemtype, bt, MO_UNORDERED | IN_HEAP | IS_ARRAY); ! ideal.sync_kit(this); ! } ideal.else_(); { ! // flattened ! // Object/interface array must be flattened, cast it ! if (val->is_ValueType()) { ! sync_kit(ideal); ! const TypeValueType* vt = _gvn.type(val)->is_valuetype(); ! ciArrayKlass* array_klass = ciArrayKlass::make(vt->value_klass()); ! const TypeAryPtr* arytype = TypeOopPtr::make_from_klass(array_klass)->isa_aryptr(); ! ary = _gvn.transform(new CheckCastPPNode(control(), ary, arytype)); ! adr = array_element_address(ary, idx, T_OBJECT, arytype->size(), control()); ! val->as_ValueType()->store_flattened(this, ary, adr); ! ideal.sync_kit(this); } else { ! if (TypePtr::NULL_PTR->higher_equal(val_t)) { ! sync_kit(ideal); ! Node* null_ctl = top(); ! val = null_check_oop(val, &null_ctl); ! if (null_ctl != top()) { ! PreserveJVMState pjvms(this); ! inc_sp(3); ! set_control(null_ctl); ! uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none); ! dec_sp(3); ! } ! ideal.sync_kit(this); ! } ! if (!ideal.ctrl()->is_top()) { ! ideal.make_leaf_call(OptoRuntime::store_unknown_value_Type(), ! CAST_FROM_FN_PTR(address, OptoRuntime::store_unknown_value), ! "store_unknown_value", ! val, ary, idx); ! } ! } ! } ideal.end_if(); ! sync_kit(ideal); ! return; ! } else { ! if (!val->is_ValueType() && TypePtr::NULL_PTR->higher_equal(val_t)) { ! gen_value_type_array_guard(ary, val, 3); ! } ! } ! } } if (elemtype == TypeInt::BOOL) { bt = T_BOOLEAN; } else if (bt == T_OBJECT) { ! elemtype = ary_t->elem()->make_oopptr(); } const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); ! access_store_at(ary, adr, adr_type, val, elemtype, bt, MO_UNORDERED | IN_HEAP | IS_ARRAY); } //------------------------------array_addressing------------------------------- // Pull array and index from the stack. Compute pointer-to-element.
*** 1493,1503 **** branch_block->next_path_num(); } } else { // Path is live. // Update method data profile_taken_branch(target_bci); ! adjust_map_after_if(btest, c, prob, branch_block, next_block); if (!stopped()) { merge(target_bci); } } } --- 1661,1671 ---- branch_block->next_path_num(); } } else { // Path is live. // Update method data profile_taken_branch(target_bci); ! adjust_map_after_if(btest, c, prob, branch_block); if (!stopped()) { merge(target_bci); } } }
*** 1513,1529 **** next_block->next_path_num(); } } else { // Path is live. // Update method data profile_not_taken_branch(); ! adjust_map_after_if(BoolTest(btest).negate(), c, 1.0-prob, ! next_block, branch_block); } } //------------------------------------do_if------------------------------------ ! void Parse::do_if(BoolTest::mask btest, Node* c) { int target_bci = iter().get_dest(); Block* branch_block = successor_for_bci(target_bci); Block* next_block = successor_for_bci(iter().next_bci()); --- 1681,1696 ---- next_block->next_path_num(); } } else { // Path is live. // Update method data profile_not_taken_branch(); ! adjust_map_after_if(BoolTest(btest).negate(), c, 1.0-prob, next_block); } } //------------------------------------do_if------------------------------------ ! void Parse::do_if(BoolTest::mask btest, Node* c, bool new_path, Node** ctrl_taken) { int target_bci = iter().get_dest(); Block* branch_block = successor_for_bci(target_bci); Block* next_block = successor_for_bci(iter().next_bci());
*** 1608,1645 **** { PreserveJVMState pjvms(this); taken_branch = _gvn.transform(taken_branch); set_control(taken_branch); if (stopped()) { ! if (C->eliminate_boxing()) { ! // Mark the successor block as parsed branch_block->next_path_num(); } } else { // Update method data profile_taken_branch(target_bci); ! adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); if (!stopped()) { merge(target_bci); } } } untaken_branch = _gvn.transform(untaken_branch); set_control(untaken_branch); // Branch not taken. ! if (stopped()) { if (C->eliminate_boxing()) { ! // Mark the successor block as parsed next_block->next_path_num(); } } else { // Update method data profile_not_taken_branch(); ! adjust_map_after_if(untaken_btest, c, untaken_prob, ! next_block, branch_block); } } bool Parse::path_is_suitable_for_uncommon_trap(float prob) const { // Don't want to speculate on uncommon traps when running with -Xcomp --- 1775,2131 ---- { PreserveJVMState pjvms(this); taken_branch = _gvn.transform(taken_branch); set_control(taken_branch); if (stopped()) { ! if (C->eliminate_boxing() && !new_path) { ! // Mark the successor block as parsed (if we haven't created a new path) branch_block->next_path_num(); } } else { // Update method data profile_taken_branch(target_bci); ! adjust_map_after_if(taken_btest, c, prob, branch_block); if (!stopped()) { + if (new_path) { + // Merge by using a new path + merge_new_path(target_bci); + } else if (ctrl_taken != NULL) { + // Don't merge but save taken branch to be wired by caller + *ctrl_taken = control(); + } else { merge(target_bci); } } } + } untaken_branch = _gvn.transform(untaken_branch); set_control(untaken_branch); // Branch not taken. ! if (stopped() && ctrl_taken == NULL) { if (C->eliminate_boxing()) { ! // Mark the successor block as parsed (if caller does not re-wire control flow) next_block->next_path_num(); } } else { // Update method data profile_not_taken_branch(); ! adjust_map_after_if(untaken_btest, c, untaken_prob, next_block); ! } ! } ! ! void Parse::do_acmp(BoolTest::mask btest, Node* a, Node* b) { ! ciMethod* subst_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 ! // could call ValueBootstrapMethods::isSubstitutable() back ! if (ACmpOnValues == 0 || method() == subst_method) { ! Node* cmp = CmpP(a, b); ! cmp = optimize_cmp_with_klass(cmp); ! do_if(btest, cmp); ! return; ! } ! ! if (ACmpOnValues == 3) { ! // Substituability 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); ! 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)); ! 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 ! 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) { ! { ! 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); ! ! 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))); ! if (btest == BoolTest::eq) { ! do_if(btest, subst_cmp); ! } else { ! assert(btest == BoolTest::ne, "only eq or ne"); ! Node* is_not_equal = NULL; ! { ! PreserveJVMState pjvms(this); ! do_if(btest, subst_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()); ! } ! } ! set_control(is_not_equal); ! } ! ne_region->init_req(5, control()); ! 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)); ! ! 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)); ! 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 ! } ! set_control(is_equal); ! } ! } ! ! // 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); ! } ! } ! 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"); ! 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)))); ! } else { ! is_value->init_req(1, is_always_locked(not_null_a)); ! } ! region->init_req(1, control()); ! ! 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 (ctrl != NULL) { ! ctrl->init_req(2, control()); ! set_control(_gvn.transform(ctrl)); } } bool Parse::path_is_suitable_for_uncommon_trap(float prob) const { // Don't want to speculate on uncommon traps when running with -Xcomp
*** 1665,1676 **** // Adjust the JVM state to reflect the result of taking this path. // Basically, it means inspecting the CmpNode controlling this // branch, seeing how it constrains a tested value, and then // deciding if it's worth our while to encode this constraint // as graph nodes in the current abstract interpretation map. ! void Parse::adjust_map_after_if(BoolTest::mask btest, Node* c, float prob, ! Block* path, Block* other_path) { if (!c->is_Cmp()) { maybe_add_predicate_after_if(path); return; } --- 2151,2161 ---- // Adjust the JVM state to reflect the result of taking this path. // Basically, it means inspecting the CmpNode controlling this // branch, seeing how it constrains a tested value, and then // deciding if it's worth our while to encode this constraint // as graph nodes in the current abstract interpretation map. ! void Parse::adjust_map_after_if(BoolTest::mask btest, Node* c, float prob, Block* path) { if (!c->is_Cmp()) { maybe_add_predicate_after_if(path); return; }
*** 1876,1885 **** --- 2361,2374 ---- if (obj_type->speculative_type_not_null() != NULL) { ciKlass* k = obj_type->speculative_type(); inc_sp(2); obj = maybe_cast_profiled_obj(obj, k); dec_sp(2); + if (obj->is_ValueType()) { + assert(obj->as_ValueType()->is_allocated(&_gvn), "must be allocated"); + obj = obj->as_ValueType()->get_oop(); + } // Make the CmpP use the casted obj addp = basic_plus_adr(obj, addp->in(AddPNode::Offset)); load_klass = load_klass->clone(); load_klass->set_req(2, addp); load_klass = _gvn.transform(load_klass);
*** 2723,2732 **** --- 3212,3225 ---- handle_if_null: // If this is a backwards branch in the bytecodes, add Safepoint maybe_add_safepoint(iter().get_dest()); a = null(); b = pop(); + if (b->is_ValueType()) { + // Return constant false because 'b' is always non-null + c = _gvn.makecon(TypeInt::CC_GT); + } else { if (!_gvn.type(b)->speculative_maybe_null() && !too_many_traps(Deoptimization::Reason_speculate_null_check)) { inc_sp(1); Node* null_ctl = top(); b = null_check_oop(b, &null_ctl, true, true, true);
*** 2737,2759 **** inc_sp(1); b = null_assert(b); dec_sp(1); } c = _gvn.transform( new CmpPNode(b, a) ); do_ifnull(btest, c); break; case Bytecodes::_if_acmpeq: btest = BoolTest::eq; goto handle_if_acmp; case Bytecodes::_if_acmpne: btest = BoolTest::ne; goto handle_if_acmp; handle_if_acmp: // If this is a backwards branch in the bytecodes, add Safepoint maybe_add_safepoint(iter().get_dest()); a = access_resolve(pop(), 0); b = access_resolve(pop(), 0); ! c = _gvn.transform( new CmpPNode(b, a) ); ! c = optimize_cmp_with_klass(c); ! do_if(btest, c); break; case Bytecodes::_ifeq: btest = BoolTest::eq; goto handle_ifxx; case Bytecodes::_ifne: btest = BoolTest::ne; goto handle_ifxx; case Bytecodes::_iflt: btest = BoolTest::lt; goto handle_ifxx; --- 3230,3251 ---- inc_sp(1); b = null_assert(b); dec_sp(1); } c = _gvn.transform( new CmpPNode(b, a) ); + } do_ifnull(btest, c); break; case Bytecodes::_if_acmpeq: btest = BoolTest::eq; goto handle_if_acmp; case Bytecodes::_if_acmpne: btest = BoolTest::ne; goto handle_if_acmp; handle_if_acmp: // If this is a backwards branch in the bytecodes, add Safepoint maybe_add_safepoint(iter().get_dest()); a = access_resolve(pop(), 0); b = access_resolve(pop(), 0); ! do_acmp(btest, a, b); break; case Bytecodes::_ifeq: btest = BoolTest::eq; goto handle_ifxx; case Bytecodes::_ifne: btest = BoolTest::ne; goto handle_ifxx; case Bytecodes::_iflt: btest = BoolTest::lt; goto handle_ifxx;
*** 2804,2824 **** break; case Bytecodes::_instanceof: do_instanceof(); break; case Bytecodes::_anewarray: ! do_anewarray(); break; case Bytecodes::_newarray: do_newarray((BasicType)iter().get_index()); break; case Bytecodes::_multianewarray: do_multianewarray(); break; case Bytecodes::_new: do_new(); break; case Bytecodes::_jsr: case Bytecodes::_jsr_w: do_jsr(); break; --- 3296,3322 ---- break; case Bytecodes::_instanceof: do_instanceof(); break; case Bytecodes::_anewarray: ! do_newarray(); break; case Bytecodes::_newarray: do_newarray((BasicType)iter().get_index()); break; case Bytecodes::_multianewarray: do_multianewarray(); break; case Bytecodes::_new: do_new(); break; + case Bytecodes::_defaultvalue: + do_defaultvalue(); + break; + case Bytecodes::_withfield: + do_withfield(); + break; case Bytecodes::_jsr: case Bytecodes::_jsr_w: do_jsr(); break;
< prev index next >