< prev index next >

src/share/vm/opto/graphKit.cpp

Print this page
rev 8961 : [mq]: diff-shenandoah.patch

*** 39,48 **** --- 39,49 ---- #include "opto/machnode.hpp" #include "opto/opaquenode.hpp" #include "opto/parse.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" + #include "opto/shenandoahSupport.hpp" #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" //----------------------------GraphKit----------------------------------------- // Main utility constructor.
*** 813,823 **** #endif //ASSERT // Helper function for enforcing certain bytecodes to reexecute if // deoptimization happens static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarray) { ! ciMethod* cur_method = jvms->method(); int cur_bci = jvms->bci(); if (cur_method != NULL && cur_bci != InvocationEntryBci) { Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci); return Interpreter::bytecode_should_reexecute(code) || is_anewarray && code == Bytecodes::_multianewarray; --- 814,824 ---- #endif //ASSERT // Helper function for enforcing certain bytecodes to reexecute if // deoptimization happens static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarray) { ! ciMethod* cur_method = jvms->has_method() ? jvms->method() : NULL; int cur_bci = jvms->bci(); if (cur_method != NULL && cur_bci != InvocationEntryBci) { Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci); return Interpreter::bytecode_should_reexecute(code) || is_anewarray && code == Bytecodes::_multianewarray;
*** 1151,1170 **** --- 1152,1178 ---- //-------------------------load_object_klass----------------------------------- Node* GraphKit::load_object_klass(Node* obj) { // Special-case a fresh allocation to avoid building nodes: Node* akls = AllocateNode::Ideal_klass(obj, &_gvn); if (akls != NULL) return akls; + if (ShenandoahVerifyReadsToFromSpace) { + obj = shenandoah_read_barrier(obj); + } Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS)); } //-------------------------load_array_length----------------------------------- Node* GraphKit::load_array_length(Node* array) { // Special-case a fresh allocation to avoid building nodes: AllocateArrayNode* alloc = AllocateArrayNode::Ideal_array_allocation(array, &_gvn); Node *alen; if (alloc == NULL) { + if (ShenandoahVerifyReadsToFromSpace) { + array = shenandoah_read_barrier(array); + } + Node *r_adr = basic_plus_adr(array, arrayOopDesc::length_offset_in_bytes()); alen = _gvn.transform( new LoadRangeNode(0, immutable_memory(), r_adr, TypeInt::POS)); } else { alen = alloc->Ideal_length(); Node* ccast = alloc->make_ideal_length(_gvn.type(array)->is_oopptr(), &_gvn);
*** 1517,1526 **** --- 1525,1535 ---- BarrierSet* bs = Universe::heap()->barrier_set(); set_control(ctl); switch (bs->kind()) { case BarrierSet::G1SATBCTLogging: + case BarrierSet::ShenandoahBarrierSet: g1_write_barrier_pre(do_load, obj, adr, adr_idx, val, val_type, pre_val, bt); break; case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension:
*** 1535,1544 **** --- 1544,1554 ---- bool GraphKit::can_move_pre_barrier() const { BarrierSet* bs = Universe::heap()->barrier_set(); switch (bs->kind()) { case BarrierSet::G1SATBCTLogging: + case BarrierSet::ShenandoahBarrierSet: return true; // Can move it if no safepoint case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension: case BarrierSet::ModRef:
*** 1569,1578 **** --- 1579,1589 ---- case BarrierSet::CardTableExtension: write_barrier_post(store, obj, adr, adr_idx, val, use_precise); break; case BarrierSet::ModRef: + case BarrierSet::ShenandoahBarrierSet: break; default : ShouldNotReachHere();
*** 1676,1685 **** --- 1687,1699 ---- void GraphKit::set_arguments_for_java_call(CallJavaNode* call) { // Add the call arguments: uint nargs = call->method()->arg_size(); for (uint i = 0; i < nargs; i++) { Node* arg = argument(i); + if (ShenandoahVerifyReadsToFromSpace && call->is_CallDynamicJava() && i == 0) { + arg = shenandoah_read_barrier(arg); + } call->init_req(i + TypeFunc::Parms, arg); } } //---------------------------set_edges_for_java_call---------------------------
*** 2917,2926 **** --- 2931,2944 ---- not_null_obj = cast_obj; } } } + if (ShenandoahVerifyReadsToFromSpace) { + not_null_obj = shenandoah_read_barrier(not_null_obj); + } + // Load the object's klass Node* obj_klass = load_object_klass(not_null_obj); // Generate the subtype check Node* not_subtype_ctrl = gen_subtype_check(obj_klass, superklass);
*** 2998,3007 **** --- 3016,3029 ---- // Null check; get casted pointer; set region slot 3 Node* null_ctl = top(); Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null); + if (ShenandoahVerifyReadsToFromSpace) { + not_null_obj = shenandoah_read_barrier(not_null_obj); + } + // If not_null_obj is dead, only null-path is taken if (stopped()) { // Doing instance-of on a NULL? set_control(null_ctl); return null(); }
*** 3147,3156 **** --- 3169,3180 ---- if (stopped()) // Dead monitor? return NULL; assert(dead_locals_are_killed(), "should kill locals before sync. point"); + obj = shenandoah_write_barrier(obj); + // Box the stack location Node* box = _gvn.transform(new BoxLockNode(next_monitor())); Node* mem = reset_memory(); FastLockNode * flock = _gvn.transform(new FastLockNode(0, obj, box) )->as_FastLock();
*** 3620,3629 **** --- 3644,3657 ---- // Given an oop pointer or raw pointer, see if it feeds from an AllocateNode. AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseTransform* phase) { if (ptr == NULL) { // reduce dumb test in callers return NULL; } + + // Attempt to see through Shenandoah barriers. + ptr = ShenandoahBarrierNode::skip_through_barrier(ptr); + if (ptr->is_CheckCastPP()) { // strip only one raw-to-oop cast ptr = ptr->in(1); if (ptr == NULL) return NULL; } // Return NULL for allocations with several casts:
*** 4272,4281 **** --- 4300,4312 ---- int offset_offset = java_lang_String::offset_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* offset_field_type = string_type->add_offset(offset_offset); int offset_field_idx = C->get_alias_index(offset_field_type); + + str = shenandoah_read_barrier(str); + return make_load(ctrl, basic_plus_adr(str, str, offset_offset), TypeInt::INT, T_INT, offset_field_idx, MemNode::unordered); } else { return intcon(0);
*** 4287,4296 **** --- 4318,4330 ---- int count_offset = java_lang_String::count_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* count_field_type = string_type->add_offset(count_offset); int count_field_idx = C->get_alias_index(count_field_type); + + str = shenandoah_read_barrier(str); + return make_load(ctrl, basic_plus_adr(str, str, count_offset), TypeInt::INT, T_INT, count_field_idx, MemNode::unordered); } else { return load_array_length(load_String_value(ctrl, str));
*** 4304,4313 **** --- 4338,4350 ---- const TypePtr* value_field_type = string_type->add_offset(value_offset); const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull, TypeAry::make(TypeInt::CHAR,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR), true, 0); int value_field_idx = C->get_alias_index(value_field_type); + + str = shenandoah_read_barrier(str); + Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset), value_type, T_OBJECT, value_field_idx, MemNode::unordered); // String.value field is known to be @Stable. if (UseImplicitStableValues) { load = cast_array_to_stable(load, value_type);
*** 4319,4352 **** int offset_offset = java_lang_String::offset_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* offset_field_type = string_type->add_offset(offset_offset); int offset_field_idx = C->get_alias_index(offset_field_type); ! store_to_memory(ctrl, basic_plus_adr(str, offset_offset), value, T_INT, offset_field_idx, MemNode::unordered); } void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) { int value_offset = java_lang_String::value_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* value_field_type = string_type->add_offset(value_offset); ! store_oop_to_object(ctrl, str, basic_plus_adr(str, value_offset), value_field_type, value, TypeAryPtr::CHARS, T_OBJECT, MemNode::unordered); } void GraphKit::store_String_length(Node* ctrl, Node* str, Node* value) { int count_offset = java_lang_String::count_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* count_field_type = string_type->add_offset(count_offset); int count_field_idx = C->get_alias_index(count_field_type); ! store_to_memory(ctrl, basic_plus_adr(str, count_offset), value, T_INT, count_field_idx, MemNode::unordered); } Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) { // Reify the property as a CastPP node in Ideal graph to comply with monotonicity // assumption of CCP analysis. return _gvn.transform(new CastPPNode(ary, ary_type->cast_to_stable(true))); } --- 4356,4593 ---- int offset_offset = java_lang_String::offset_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* offset_field_type = string_type->add_offset(offset_offset); int offset_field_idx = C->get_alias_index(offset_field_type); ! ! // TODO: Use incoming ctrl. ! str = shenandoah_write_barrier(str); ! ! store_to_memory(UseShenandoahGC ? control() : ctrl, basic_plus_adr(str, offset_offset), value, T_INT, offset_field_idx, MemNode::unordered); } void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) { int value_offset = java_lang_String::value_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* value_field_type = string_type->add_offset(value_offset); ! // TODO: Use incoming ctrl. ! str = shenandoah_write_barrier(str); ! value = shenandoah_read_barrier_nomem(value); ! ! store_oop_to_object(UseShenandoahGC ? control() : ctrl, str, basic_plus_adr(str, value_offset), value_field_type, value, TypeAryPtr::CHARS, T_OBJECT, MemNode::unordered); } void GraphKit::store_String_length(Node* ctrl, Node* str, Node* value) { int count_offset = java_lang_String::count_offset_in_bytes(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), false, NULL, 0); const TypePtr* count_field_type = string_type->add_offset(count_offset); int count_field_idx = C->get_alias_index(count_field_type); ! ! // TODO: Use incoming ctrl. ! str = shenandoah_write_barrier(str); ! ! store_to_memory(UseShenandoahGC ? control() : ctrl, basic_plus_adr(str, count_offset), value, T_INT, count_field_idx, MemNode::unordered); } Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) { // Reify the property as a CastPP node in Ideal graph to comply with monotonicity // assumption of CCP analysis. return _gvn.transform(new CastPPNode(ary, ary_type->cast_to_stable(true))); } + + Node* GraphKit::shenandoah_read_barrier(Node* obj) { + return shenandoah_read_barrier_impl(obj, false, true); + } + + Node* GraphKit::shenandoah_read_barrier_nomem(Node* obj) { + return shenandoah_read_barrier_impl(obj, false, false); + } + + Node* GraphKit::shenandoah_read_barrier_impl(Node* obj, bool use_ctrl, bool use_mem) { + + if (UseShenandoahGC && ShenandoahReadBarrier) { + const Type* obj_type = obj->bottom_type(); + if (obj_type->higher_equal(TypePtr::NULL_PTR)) { + // tty->print_cr("killed barrier for NULL object"); + return obj; + } + const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8); + Node* mem = use_mem ? memory(adr_type) : immutable_memory(); + + if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, mem)) { + // We know it is null, no barrier needed. + return obj; + } + + + if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) { + + // We don't know if it's null or not. Need null-check. + enum { _not_null_path = 1, _null_path, PATH_LIMIT }; + RegionNode* region = new RegionNode(PATH_LIMIT); + Node* phi = new PhiNode(region, obj_type); + Node* null_ctrl = top(); + Node* not_null_obj = null_check_oop(obj, &null_ctrl); + + region->init_req(_null_path, null_ctrl); + phi ->init_req(_null_path, obj); + + Node* ctrl = use_ctrl ? control() : NULL; + ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, not_null_obj); + Node* n = _gvn.transform(rb); + + region->init_req(_not_null_path, control()); + phi ->init_req(_not_null_path, n); + + set_control(_gvn.transform(region)); + record_for_igvn(region); + return _gvn.transform(phi); + + } else { + // We know it is not null. Simple barrier is sufficient. + Node* ctrl = use_ctrl ? control() : NULL; + ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj); + Node* n = _gvn.transform(rb); + record_for_igvn(n); + return n; + } + + } else { + return obj; + } + } + + Node* GraphKit::shenandoah_write_barrier(Node* obj) { + + if (UseShenandoahGC && ShenandoahWriteBarrier) { + + if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, NULL)) { + return obj; + } + const Type* obj_type = obj->bottom_type(); + const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8); + // tty->print_cr("memory at:"); + // adr_type->dump(); + // tty->print_cr("\n"); + // memory(adr_type)->dump(); + if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) { + // We don't know if it's null or not. Need null-check. + enum { _not_null_path = 1, _null_path, PATH_LIMIT }; + RegionNode* region = new RegionNode(PATH_LIMIT); + Node* phi = new PhiNode(region, obj_type); + Node* memphi = PhiNode::make(region, memory(adr_type), Type::MEMORY, C->alias_type(adr_type)->adr_type()); + + Node* prev_mem = memory(adr_type); + Node* null_ctrl = top(); + Node* not_null_obj = null_check_oop(obj, &null_ctrl); + + region->init_req(_null_path, null_ctrl); + phi ->init_req(_null_path, null()); + memphi->init_req(_null_path, prev_mem); + + ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), not_null_obj); + Node* n = _gvn.transform(wb); + if (n == wb) { // New barrier needs memory projection. + Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(n)); + set_memory(proj, adr_type); + } + + region->init_req(_not_null_path, control()); + phi ->init_req(_not_null_path, n); + memphi->init_req(_not_null_path, memory(adr_type)); + + set_control(_gvn.transform(region)); + record_for_igvn(region); + set_memory(_gvn.transform(memphi), adr_type); + + Node* res_val = _gvn.transform(phi); + // replace_in_map(obj, res_val); + return res_val; + } else { + // We know it is not null. Simple barrier is sufficient. + ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), obj); + Node* n = _gvn.transform(wb); + if (n == wb) { + Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(wb)); + set_memory(proj, adr_type); + } + // replace_in_map(obj, n); + record_for_igvn(n); + return n; + } + + } else { + return obj; + } + } + + void GraphKit::shenandoah_acmp_barrier(Node*& a, Node*& b) { + if (UseShenandoahGC) { + const Type* a_type = a->bottom_type(); + const Type* b_type = b->bottom_type(); + if (a_type->higher_equal(TypePtr::NULL_PTR) || b_type->higher_equal(TypePtr::NULL_PTR)) { + // We know one arg is gonna be null. No need for barriers. + // tty->print_cr("eliminate acmp barrier on null"); + return; + } + /* + if ((!a_type->isa_oopptr()) || (!b_type->isa_oopptr())) { + a_type->dump(); + b_type->dump(); + } + */ + if (a_type->is_oopptr()->const_oop() != NULL && b_type->is_oopptr()->const_oop() != NULL ) { + // We know one arg is inlined constant. No need for barriers. + // tty->print_cr("eliminate acmp barrier on constant"); + return; + } + if (a->Opcode() == Op_ShenandoahWriteBarrier && b->Opcode() == Op_ShenandoahWriteBarrier) { + // We know one arg is already write-barrier'd. No need for barriers. + // tty->print_cr("eliminate acmp barrier on write barrier"); + return; + } + if (AllocateNode::Ideal_allocation(a, &_gvn) != NULL || AllocateNode::Ideal_allocation(b, &_gvn) != NULL) { + // We know one arg is already in to-space. No need for barriers. + // tty->print_cr("eliminate acmp barrier on new obj"); + return; + } + + enum { _equal = 1, _not_equal, PATH_LIMIT }; + RegionNode* region = new RegionNode(PATH_LIMIT); + PhiNode* phiA = PhiNode::make(region, a); + PhiNode* phiB = PhiNode::make(region, b); + + Node* cmp = _gvn.transform(new CmpPNode(b, a)); + Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::eq)); + + // TODO: Use profiling data. + IfNode* iff = create_and_map_if(control(), tst, PROB_FAIR, COUNT_UNKNOWN); + Node* iftrue = _gvn.transform(new IfTrueNode(iff)); + Node* iffalse = _gvn.transform(new IfFalseNode(iff)); + + // Equal path: Use original values. + region->init_req(_equal, iftrue); + phiA->init_req(_equal, a); + phiB->init_req(_equal, b); + + // Unequal path: retry after read barriers. + set_control(iffalse); + a = shenandoah_read_barrier_impl(a, true, true); + b = shenandoah_read_barrier_impl(b, true, true); + + region->init_req(_not_equal, control()); + phiA->init_req(_not_equal, a); + phiB->init_req(_not_equal, b); + + set_control(_gvn.transform(region)); + record_for_igvn(region); + + a = _gvn.transform(phiA); + b = _gvn.transform(phiB); + } + }
< prev index next >