diff --git a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp index c38b82bc5b1107c51dc993b413ba9e80f262e973..b284a3e9307da29cdcd7866a0f7b100cf658f9b5 100644 --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp @@ -435,85 +435,6 @@ void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { } -void G1UnsafeGetObjSATBBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that offset == referent_offset. - // - // So we might have to emit: - // if (src == null) goto continuation. - // - // and we definitely have to emit: - // if (klass(src).reference_type == REF_NONE) goto continuation - // if (!marking_active) goto continuation - // if (pre_val == null) goto continuation - // call pre_barrier(pre_val) - // goto continuation - // - __ bind(_entry); - - assert(src()->is_register(), "sanity"); - Register src_reg = src()->as_register(); - - if (gen_src_check()) { - // The original src operand was not a constant. - // Generate src == null? - if (__ is_in_wdisp16_range(_continuation)) { - __ br_null(src_reg, /*annul*/false, Assembler::pt, _continuation); - } else { - __ cmp(src_reg, G0); - __ brx(Assembler::equal, false, Assembler::pt, _continuation); - } - __ delayed()->nop(); - } - - // Generate src->_klass->_reference_type() == REF_NONE)? - assert(tmp()->is_register(), "sanity"); - Register tmp_reg = tmp()->as_register(); - - __ load_klass(src_reg, tmp_reg); - - Address ref_type_adr(tmp_reg, instanceKlass::reference_type_offset()); - __ ldub(ref_type_adr, tmp_reg); - - // _reference_type field is of type ReferenceType (enum) - assert(REF_NONE == 0, "check this code"); - __ cmp_zero_and_br(Assembler::equal, tmp_reg, _continuation, /*annul*/false, Assembler::pt); - __ delayed()->nop(); - - // Is marking active? - assert(thread()->is_register(), "precondition"); - Register thread_reg = thread()->as_pointer_register(); - - Address in_progress(thread_reg, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); - - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { - __ ld(in_progress, tmp_reg); - } else { - assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldsb(in_progress, tmp_reg); - } - - __ cmp_zero_and_br(Assembler::equal, tmp_reg, _continuation, /*annul*/false, Assembler::pt); - __ delayed()->nop(); - - // val == null? - assert(val()->is_register(), "Precondition."); - Register val_reg = val()->as_register(); - - if (__ is_in_wdisp16_range(_continuation)) { - __ br_null(val_reg, /*annul*/false, Assembler::pt, _continuation); - } else { - __ cmp(val_reg, G0); - __ brx(Assembler::equal, false, Assembler::pt, _continuation); - } - __ delayed()->nop(); - - __ call(Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id)); - __ delayed()->mov(val_reg, G4); - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->nop(); -} - jbyte* G1PostBarrierStub::_byte_map_base = NULL; jbyte* G1PostBarrierStub::byte_map_base_slow() { diff --git a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp index 24b879aec1b4ed5844a3f654b6a9569e1ca75893..618a37c918baa32fd48d765b7a709e80da49bae3 100644 --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp @@ -488,68 +488,6 @@ void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { } -void G1UnsafeGetObjSATBBarrierStub::emit_code(LIR_Assembler* ce) { - // At this point we know that offset == referent_offset. - // - // So we might have to emit: - // if (src == null) goto continuation. - // - // and we definitely have to emit: - // if (klass(src).reference_type == REF_NONE) goto continuation - // if (!marking_active) goto continuation - // if (pre_val == null) goto continuation - // call pre_barrier(pre_val) - // goto continuation - // - __ bind(_entry); - - assert(src()->is_register(), "sanity"); - Register src_reg = src()->as_register(); - - if (gen_src_check()) { - // The original src operand was not a constant. - // Generate src == null? - __ cmpptr(src_reg, (int32_t) NULL_WORD); - __ jcc(Assembler::equal, _continuation); - } - - // Generate src->_klass->_reference_type == REF_NONE)? - assert(tmp()->is_register(), "sanity"); - Register tmp_reg = tmp()->as_register(); - - __ load_klass(tmp_reg, src_reg); - - Address ref_type_adr(tmp_reg, instanceKlass::reference_type_offset()); - __ cmpb(ref_type_adr, REF_NONE); - __ jcc(Assembler::equal, _continuation); - - // Is marking active? - assert(thread()->is_register(), "precondition"); - Register thread_reg = thread()->as_pointer_register(); - - Address in_progress(thread_reg, in_bytes(JavaThread::satb_mark_queue_offset() + - PtrQueue::byte_offset_of_active())); - - if (in_bytes(PtrQueue::byte_width_of_active()) == 4) { - __ cmpl(in_progress, 0); - } else { - assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption"); - __ cmpb(in_progress, 0); - } - __ jcc(Assembler::equal, _continuation); - - // val == null? - assert(val()->is_register(), "Precondition."); - Register val_reg = val()->as_register(); - - __ cmpptr(val_reg, (int32_t) NULL_WORD); - __ jcc(Assembler::equal, _continuation); - - ce->store_parameter(val()->as_register(), 0); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::g1_pre_barrier_slow_id))); - __ jmp(_continuation); -} - jbyte* G1PostBarrierStub::_byte_map_base = NULL; jbyte* G1PostBarrierStub::byte_map_base_slow() { diff --git a/src/share/vm/c1/c1_CodeStubs.hpp b/src/share/vm/c1/c1_CodeStubs.hpp index 128a6d48cdd657e2ae455e0d3a56d0069af07e19..dad29b2fa916932187bd1954f88a3c0dd32a42e9 100644 --- a/src/share/vm/c1/c1_CodeStubs.hpp +++ b/src/share/vm/c1/c1_CodeStubs.hpp @@ -574,71 +574,6 @@ class G1PreBarrierStub: public CodeStub { #endif // PRODUCT }; -// This G1 barrier code stub is used in Unsafe.getObject. -// It generates a sequence of guards around the SATB -// barrier code that are used to detect when we have -// the referent field of a Reference object. -// The first check is assumed to have been generated -// in the code generated for Unsafe.getObject(). - -class G1UnsafeGetObjSATBBarrierStub: public CodeStub { - private: - LIR_Opr _val; - LIR_Opr _src; - - LIR_Opr _tmp; - LIR_Opr _thread; - - bool _gen_src_check; - - public: - // A G1 barrier that is guarded by generated guards that determine whether - // val (which is the result of Unsafe.getObject() should be recorded in an - // SATB log buffer. We could be reading the referent field of a Reference object - // using Unsafe.getObject() and we need to record the referent. - // - // * val is the operand returned by the unsafe.getObject routine. - // * src is the base object - // * tmp is a temp used to load the klass of src, and then reference type - // * thread is the thread object. - - G1UnsafeGetObjSATBBarrierStub(LIR_Opr val, LIR_Opr src, - LIR_Opr tmp, LIR_Opr thread, - bool gen_src_check) : - _val(val), _src(src), - _tmp(tmp), _thread(thread), - _gen_src_check(gen_src_check) - { - assert(_val->is_register(), "should have already been loaded"); - assert(_src->is_register(), "should have already been loaded"); - - assert(_tmp->is_register(), "should be a temporary register"); - } - - LIR_Opr val() const { return _val; } - LIR_Opr src() const { return _src; } - - LIR_Opr tmp() const { return _tmp; } - LIR_Opr thread() const { return _thread; } - - bool gen_src_check() const { return _gen_src_check; } - - virtual void emit_code(LIR_Assembler* e); - - virtual void visit(LIR_OpVisitState* visitor) { - visitor->do_slow_case(); - visitor->do_input(_val); - visitor->do_input(_src); - visitor->do_input(_thread); - - visitor->do_temp(_tmp); - } - -#ifndef PRODUCT - virtual void print_name(outputStream* out) const { out->print("G1UnsafeGetObjSATBBarrierStub"); } -#endif // PRODUCT -}; - class G1PostBarrierStub: public CodeStub { private: LIR_Opr _addr; diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp index 737d39f38501637e0dcc85fb206a22f353a667d6..98fa7f6c5f4bb0c0eb4cbfb5ed2c96628476fd59 100644 --- a/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3058,7 +3058,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) case vmIntrinsics::_Reference_get: { - if (UseG1GC) { + { // With java.lang.ref.reference.get() we must go through the // intrinsic - when G1 is enabled - even when get() is the root // method of the compile so that, if necessary, the value in @@ -3070,6 +3070,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) // object removed from the list of discovered references during // reference processing. + // Also we need intrinsic to prevent commoning reads from this field + // across safepoint since GC can change its value. + // Set up a stream so that appending instructions works properly. ciBytecodeStream s(scope->method()); s.reset_to_bci(0); @@ -3226,7 +3229,6 @@ const char* GraphBuilder::should_not_inline(ciMethod* callee) const { bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { - if (!InlineNatives ) INLINE_BAILOUT("intrinsic method inlining disabled"); if (callee->is_synchronized()) { // We don't currently support any synchronized intrinsics return false; @@ -3234,9 +3236,13 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { // callee seems like a good candidate // determine id + vmIntrinsics::ID id = callee->intrinsic_id(); + if (!InlineNatives && id != vmIntrinsics::_Reference_get) { + // InlineNatives does not control Reference.get + INLINE_BAILOUT("intrinsic method inlining disabled"); + } bool preserves_state = false; bool cantrap = true; - vmIntrinsics::ID id = callee->intrinsic_id(); switch (id) { case vmIntrinsics::_arraycopy: if (!InlineArrayCopy) return false; @@ -3376,11 +3382,10 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { return true; case vmIntrinsics::_Reference_get: - // It is only when G1 is enabled that we absolutely - // need to use the intrinsic version of Reference.get() - // so that the value in the referent field, if necessary, - // can be registered by the pre-barrier code. - if (!UseG1GC) return false; + // Use the intrinsic version of Reference.get() so that the value in + // the referent field can be registered by the G1 pre-barrier code. + // Also to prevent commoning reads from this field across safepoint + // since GC can change its value. preserves_state = true; break; diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp index 111f93bf3b4d30d0568535ca9efac6999ff08f3a..c87992163057c1bb10ba5be42dc418374328de29 100644 --- a/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/src/share/vm/c1/c1_LIRGenerator.cpp @@ -2176,9 +2176,9 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { off.load_item(); src.load_item(); - LIR_Opr reg = rlock_result(x, x->basic_type()); + LIR_Opr value = rlock_result(x, x->basic_type()); - get_Object_unsafe(reg, src.result(), off.result(), type, x->is_volatile()); + get_Object_unsafe(value, src.result(), off.result(), type, x->is_volatile()); #ifndef SERIALGC // We might be reading the value of the referent field of a @@ -2191,19 +2191,16 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { // if (offset == java_lang_ref_Reference::referent_offset) { // if (src != NULL) { // if (klass(src)->reference_type() != REF_NONE) { - // pre_barrier(..., reg, ...); + // pre_barrier(..., value, ...); // } // } // } - // - // The first non-constant check of either the offset or - // the src operand will be done here; the remainder - // will take place in the generated code stub. if (UseG1GC && type == T_OBJECT) { - bool gen_code_stub = true; // Assume we need to generate the slow code stub. - bool gen_offset_check = true; // Assume the code stub has to generate the offset guard. - bool gen_source_check = true; // Assume the code stub has to check the src object for null. + bool gen_pre_barrier = true; // Assume we need to generate pre_barrier. + bool gen_offset_check = true; // Assume we need to generate the offset guard. + bool gen_source_check = true; // Assume we need to check the src object for null. + bool gen_type_check = true; // Assume we need to check the reference_type. if (off.is_constant()) { jlong off_con = (off.type()->is_int() ? @@ -2215,7 +2212,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { // The constant offset is something other than referent_offset. // We can skip generating/checking the remaining guards and // skip generation of the code stub. - gen_code_stub = false; + gen_pre_barrier = false; } else { // The constant offset is the same as referent_offset - // we do not need to generate a runtime offset check. @@ -2224,11 +2221,11 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { } // We don't need to generate stub if the source object is an array - if (gen_code_stub && src.type()->is_array()) { - gen_code_stub = false; + if (gen_pre_barrier && src.type()->is_array()) { + gen_pre_barrier = false; } - if (gen_code_stub) { + if (gen_pre_barrier) { // We still need to continue with the checks. if (src.is_constant()) { ciObject* src_con = src.get_jobject_constant(); @@ -2236,7 +2233,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { if (src_con->is_null_object()) { // The constant src object is null - We can skip // generating the code stub. - gen_code_stub = false; + gen_pre_barrier = false; } else { // Non-null constant source object. We still have to generate // the slow stub - but we don't need to generate the runtime @@ -2245,20 +2242,28 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { } } } + if (gen_pre_barrier && !PatchALot) { + // Can the klass of object be statically determined to be + // a sub-class of Reference? + ciType* type = src.value()->declared_type(); + if ((type != NULL) && type->is_loaded()) { + if (type->is_subtype_of(compilation()->env()->Reference_klass())) { + gen_type_check = false; + } else if (type->is_klass() && + !compilation()->env()->Object_klass()->is_subtype_of(type->as_klass())) { + // Not Reference and not Object klass. + gen_pre_barrier = false; + } + } + } - if (gen_code_stub) { - // Temoraries. - LIR_Opr src_klass = new_register(T_OBJECT); - - // Get the thread pointer for the pre-barrier - LIR_Opr thread = getThreadPointer(); - - CodeStub* stub; + if (gen_pre_barrier) { + LabelObj* Lcont = new LabelObj(); // We can have generate one runtime check here. Let's start with // the offset check. if (gen_offset_check) { - // if (offset == referent_offset) -> slow code stub + // if (offset != referent_offset) -> continue // If offset is an int then we can do the comparison with the // referent_offset constant; otherwise we need to move // referent_offset into a temporary register and generate @@ -2273,43 +2278,36 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) { referent_off = new_register(T_LONG); __ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off); } - - __ cmp(lir_cond_equal, off.result(), referent_off); - - // Optionally generate "src == null" check. - stub = new G1UnsafeGetObjSATBBarrierStub(reg, src.result(), - src_klass, thread, - gen_source_check); - - __ branch(lir_cond_equal, as_BasicType(off.type()), stub); - } else { - if (gen_source_check) { - // offset is a const and equals referent offset - // if (source != null) -> slow code stub - __ cmp(lir_cond_notEqual, src.result(), LIR_OprFact::oopConst(NULL)); - - // Since we are generating the "if src == null" guard here, - // there is no need to generate the "src == null" check again. - stub = new G1UnsafeGetObjSATBBarrierStub(reg, src.result(), - src_klass, thread, - false); - - __ branch(lir_cond_notEqual, T_OBJECT, stub); - } else { - // We have statically determined that offset == referent_offset - // && src != null so we unconditionally branch to code stub - // to perform the guards and record reg in the SATB log buffer. - - stub = new G1UnsafeGetObjSATBBarrierStub(reg, src.result(), - src_klass, thread, - false); - - __ branch(lir_cond_always, T_ILLEGAL, stub); - } + __ cmp(lir_cond_notEqual, off.result(), referent_off); + __ branch(lir_cond_notEqual, as_BasicType(off.type()), Lcont->label()); } - - // Continuation point - __ branch_destination(stub->continuation()); + if (gen_source_check) { + // offset is a const and equals referent offset + // if (source == null) -> continue + __ cmp(lir_cond_equal, src.result(), LIR_OprFact::oopConst(NULL)); + __ branch(lir_cond_equal, T_OBJECT, Lcont->label()); + } + LIR_Opr src_klass = new_register(T_OBJECT); + if (gen_type_check) { + // We have determined that offset == referent_offset && src != null. + // if (src->_klass->_reference_type == REF_NONE) -> continue + __ move(new LIR_Address(src.result(), oopDesc::klass_offset_in_bytes(), T_OBJECT), src_klass); + LIR_Address* reference_type_addr = new LIR_Address(src_klass, in_bytes(instanceKlass::reference_type_offset()), T_BYTE); + LIR_Opr reference_type = new_register(T_INT); + __ move(reference_type_addr, reference_type); + __ cmp(lir_cond_equal, reference_type, LIR_OprFact::intConst(REF_NONE)); + __ branch(lir_cond_equal, T_INT, Lcont->label()); + } + { + // We have determined that src->_klass->_reference_type != REF_NONE + // so register the value in the referent field with the pre-barrier. + pre_barrier(LIR_OprFact::illegalOpr /* addr_opr */, + value /* pre_val */, + false /* do_load */, + false /* patch */, + NULL /* info */); + } + __ branch_destination(Lcont->label()); } } #endif // SERIALGC diff --git a/src/share/vm/opto/idealKit.cpp b/src/share/vm/opto/idealKit.cpp index c9cb0f8557863e9f67cc7ba179b11b1496070861..1cc4b2bd13315c4891a440c7b22e027d82313f1f 100644 --- a/src/share/vm/opto/idealKit.cpp +++ b/src/share/vm/opto/idealKit.cpp @@ -295,7 +295,11 @@ Node* IdealKit::transform(Node* n) { if (_delay_all_transforms) { return delay_transform(n); } else { - return gvn().transform(n); + n = gvn().transform(n); + if (!gvn().is_IterGVN()) { + C->record_for_igvn(n); + } + return n; } } diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp index cb8dcbb65ceb485398501ec9611890eb2e5eb046..3ae12baa78e0ebf0b180e732abfaddf10068c09b 100644 --- a/src/share/vm/opto/library_call.cpp +++ b/src/share/vm/opto/library_call.cpp @@ -171,7 +171,7 @@ class LibraryCallKit : public GraphKit { // Helper for inline_unsafe_access. // Generates the guards that check whether the result of // Unsafe.getObject should be recorded in an SATB log buffer. - void insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* pre_val); + void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, int nargs, bool need_mem_bar); bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile); bool inline_unsafe_prefetch(bool is_native_ptr, bool is_store, bool is_static); bool inline_unsafe_allocate(); @@ -291,6 +291,8 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { case vmIntrinsics::_equals: case vmIntrinsics::_equalsC: break; // InlineNatives does not control String.compareTo + case vmIntrinsics::_Reference_get: + break; // InlineNatives does not control Reference.get default: return NULL; } @@ -361,11 +363,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { break; case vmIntrinsics::_Reference_get: - // It is only when G1 is enabled that we absolutely - // need to use the intrinsic version of Reference.get() - // so that the value in the referent field, if necessary, - // can be registered by the pre-barrier code. - if (!UseG1GC) return NULL; + // Use the intrinsic version of Reference.get() so that the value in + // the referent field can be registered by the G1 pre-barrier code. + // Also add memory barrier to prevent commoning reads from this field + // across safepoint since GC can change it value. break; default: @@ -2195,14 +2196,17 @@ bool LibraryCallKit::inline_reverseBytes(vmIntrinsics::ID id) { const static BasicType T_ADDRESS_HOLDER = T_LONG; -// Helper that guards and inserts a G1 pre-barrier. -void LibraryCallKit::insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* pre_val) { - assert(UseG1GC, "should not call this otherwise"); - +// Helper that guards and inserts a pre-barrier. +void LibraryCallKit::insert_pre_barrier(Node* base_oop, Node* offset, + Node* pre_val, int nargs, bool need_mem_bar) { // We could be accessing the referent field of a reference object. If so, when G1 // is enabled, we need to log the value in the referent field in an SATB buffer. // This routine performs some compile time filters and generates suitable // runtime filters that guard the pre-barrier code. + // Also add memory barrier for non volatile load from the referent field + // to prevent commoning of loads across safepoint. + if (!UseG1GC && !need_mem_bar) + return; // Some compile time checks. @@ -2224,11 +2228,12 @@ void LibraryCallKit::insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* p const TypeInstPtr* itype = btype->isa_instptr(); if (itype != NULL) { - // Can the klass of base_oop be statically determined - // to be _not_ a sub-class of Reference? + // Can the klass of base_oop be statically determined to be + // _not_ a sub-class of Reference and _not_ Object? ciKlass* klass = itype->klass(); - if (klass->is_subtype_of(env()->Reference_klass()) && - !env()->Reference_klass()->is_subtype_of(klass)) { + if ( klass->is_loaded() && + !klass->is_subtype_of(env()->Reference_klass()) && + !env()->Object_klass()->is_subtype_of(klass)) { return; } } @@ -2238,10 +2243,8 @@ void LibraryCallKit::insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* p // we need to generate the following runtime filters // // if (offset == java_lang_ref_Reference::_reference_offset) { - // if (base != null) { - // if (instance_of(base, java.lang.ref.Reference)) { - // pre_barrier(_, pre_val, ...); - // } + // if (instance_of(base, java.lang.ref.Reference)) { + // pre_barrier(_, pre_val, ...); // } // } @@ -2254,19 +2257,19 @@ void LibraryCallKit::insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* p Node* referent_off = __ ConX(java_lang_ref_Reference::referent_offset); __ if_then(offset, BoolTest::eq, referent_off, unlikely); { - __ if_then(base_oop, BoolTest::ne, null(), likely); { - // Update graphKit memory and control from IdealKit. sync_kit(ideal); Node* ref_klass_con = makecon(TypeKlassPtr::make(env()->Reference_klass())); + _sp += nargs; // gen_instanceof might do an uncommon trap Node* is_instof = gen_instanceof(base_oop, ref_klass_con); + _sp -= nargs; // Update IdealKit memory and control from graphKit. __ sync_kit(this); Node* one = __ ConI(1); - + // is_instof == 0 if base_oop == NULL __ if_then(is_instof, BoolTest::eq, one, unlikely); { // Update graphKit from IdeakKit. @@ -2278,12 +2281,15 @@ void LibraryCallKit::insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* p NULL /* obj */, NULL /* adr */, max_juint /* alias_idx */, NULL /* val */, NULL /* val_type */, pre_val /* pre_val */, T_OBJECT); - + if (need_mem_bar) { + // Add memory barrier to prevent commoning reads from this field + // across safepoint since GC can change its value. + insert_mem_bar(Op_MemBarCPUOrder); + } // Update IdealKit from graphKit. __ sync_kit(this); } __ end_if(); // _ref_type != ref_none - } __ end_if(); // base != NULL } __ end_if(); // offset == referent_offset // Final sync IdealKit and GraphKit. @@ -2418,7 +2424,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // object (either by using Unsafe directly or through reflection) // then, if G1 is enabled, we need to record the referent in an // SATB log buffer using the pre-barrier mechanism. - bool need_read_barrier = UseG1GC && !is_native_ptr && !is_store && + // Also we need to add memory barrier to prevent commoning reads + // from this field across safepoint since GC can change its value. + bool need_read_barrier = !is_native_ptr && !is_store && offset != top() && heap_base_oop != top(); if (!is_store && type == T_OBJECT) { @@ -2508,7 +2516,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; case T_OBJECT: if (need_read_barrier) { - insert_g1_pre_barrier(heap_base_oop, offset, p); + insert_pre_barrier(heap_base_oop, offset, p, nargs, !(is_volatile || need_mem_bar)); } push(p); break; @@ -5484,6 +5492,10 @@ bool LibraryCallKit::inline_reference_get() { result /* pre_val */, T_OBJECT); + // Add memory barrier to prevent commoning reads from this field + // across safepoint since GC can change its value. + insert_mem_bar(Op_MemBarCPUOrder); + push(result); return true; } diff --git a/test/compiler/7190310/Test7190310.java b/test/compiler/7190310/Test7190310.java new file mode 100644 index 0000000000000000000000000000000000000000..57a89b93b397a516b07e8e4a87ecb845fad15c9a --- /dev/null +++ b/test/compiler/7190310/Test7190310.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * Manual test + */ + +import java.lang.ref.*; + +public class Test7190310 { + private static Object str = new Object() { + public String toString() { + return "The Object"; + } + + protected void finalize() throws Throwable { + System.out.println("The Object is being finalized"); + super.finalize(); + } + }; + private final static ReferenceQueue rq = + new ReferenceQueue(); + private final static WeakReference wr = + new WeakReference(str, rq); + + public static void main(String[] args) + throws InterruptedException { + Thread reader = new Thread() { + public void run() { + while (wr.get() != null) { + } + System.out.println("wr.get() returned null"); + } + }; + + Thread queueReader = new Thread() { + public void run() { + try { + Reference ref = rq.remove(); + System.out.println(ref); + System.out.println("queueReader returned, ref==wr is " + + (ref == wr)); + } catch (InterruptedException e) { + System.err.println("Sleep interrupted - exiting"); + } + } + }; + + reader.start(); + queueReader.start(); + + Thread.sleep(1000); + str = null; + System.gc(); + } +} + diff --git a/test/compiler/7190310/Test7190310_unsafe.java b/test/compiler/7190310/Test7190310_unsafe.java new file mode 100644 index 0000000000000000000000000000000000000000..3f97f28e403d94c28354baab93f91e1f61ea59f7 --- /dev/null +++ b/test/compiler/7190310/Test7190310_unsafe.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 7190310 + * @summary Inlining WeakReference.get(), and hoisting $referent may lead to non-terminating loops + * @run main/othervm -Xbatch Test7190310_unsafe + */ + +import java.lang.ref.*; +import java.lang.reflect.*; +import sun.misc.Unsafe; + +public class Test7190310_unsafe { + + static class TestObject { + public String toString() { + return "TestObject"; + } + }; + + private static TestObject str = new TestObject(); + private static final WeakReference ref = new WeakReference(str); + + private TestObject obj; + + public static void main(String[] args) throws Exception { + Class c = Test7190310_unsafe.class.getClassLoader().loadClass("sun.misc.Unsafe"); + Field f = c.getDeclaredField("theUnsafe"); + f.setAccessible(true); + Unsafe unsafe = (Unsafe)f.get(c); + + f = Reference.class.getDeclaredField("referent"); + f.setAccessible(true); + long referent_offset = unsafe.objectFieldOffset(f); + + Test7190310_unsafe t = new Test7190310_unsafe(); + TestObject o = new TestObject(); + t.obj = o; + + // Warmup (compile methods) + System.err.println("Warmup"); + Object obj = null; + for (int i = 0; i < 11000; i++) { + obj = getRef0(ref); + } + for (int i = 0; i < 11000; i++) { + obj = getRef1(unsafe, ref, referent_offset); + } + for (int i = 0; i < 11000; i++) { + obj = getRef2(unsafe, ref, referent_offset); + } + for (int i = 0; i < 11000; i++) { + obj = getRef3(unsafe, ref, referent_offset); + } + for (int i = 0; i < 11000; i++) { + obj = getRef4(unsafe, t, referent_offset); + } + + // Access verification + System.err.println("Verification"); + if (!verifyGet(referent_offset, unsafe)) { + System.exit(97); + } + + obj = getRef3(unsafe, t, referent_offset); + if (obj != o) { + System.out.println("FAILED: unsafe.getObject(Object, " + referent_offset + ") " + obj + " != " + o); + System.exit(97); + } + obj = getRef4(unsafe, t, referent_offset); + if (obj != o) { + System.out.println("FAILED: unsafe.getObject(Test7190310, " + referent_offset + ") " + obj + " != " + o); + System.exit(97); + } + } + + static boolean verifyGet(long referent_offset, Unsafe unsafe) throws Exception { + // Access verification + System.out.println("referent: " + str); + Object obj = getRef0(ref); + if (obj != str) { + System.out.println("FAILED: weakRef.get() " + obj + " != " + str); + return false; + } + obj = getRef1(unsafe, ref, referent_offset); + if (obj != str) { + System.out.println("FAILED: unsafe.getObject(weakRef, " + referent_offset + ") " + obj + " != " + str); + return false; + } + obj = getRef2(unsafe, ref, referent_offset); + if (obj != str) { + System.out.println("FAILED: unsafe.getObject(abstRef, " + referent_offset + ") " + obj + " != " + str); + return false; + } + obj = getRef3(unsafe, ref, referent_offset); + if (obj != str) { + System.out.println("FAILED: unsafe.getObject(Object, " + referent_offset + ") " + obj + " != " + str); + return false; + } + return true; + } + + static Object getRef0(WeakReference ref) throws Exception { + return ref.get(); + } + static Object getRef1(Unsafe unsafe, WeakReference ref, long referent_offset) throws Exception { + return unsafe.getObject(ref, referent_offset); + } + static Object getRef2(Unsafe unsafe, Reference ref, long referent_offset) throws Exception { + return unsafe.getObject(ref, referent_offset); + } + static Object getRef3(Unsafe unsafe, Object ref, long referent_offset) throws Exception { + return unsafe.getObject(ref, referent_offset); + } + static Object getRef4(Unsafe unsafe, Test7190310_unsafe ref, long referent_offset) throws Exception { + return unsafe.getObject(ref, referent_offset); + } +} +