提交 3ee418e4 编写于 作者: K kvn

7190310: Inlining WeakReference.get(), and hoisting $referent may lead to non-terminating loops

Summary: In C2 add software membar after load from Reference.referent field to prevent commoning of loads across safepoint since GC can change its value. In C1 always generate Reference.get() intrinsic.
Reviewed-by: roland, twisti, dholmes, johnc
上级 ee3f4ddf
......@@ -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() {
......
......@@ -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() {
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
}
}
......
......@@ -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;
}
/*
* 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<Object> rq =
new ReferenceQueue<Object>();
private final static WeakReference<Object> wr =
new WeakReference<Object>(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<? extends Object> 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();
}
}
/*
* 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);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册