mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-25 13:54:38 +02:00
7190310: Inlining WeakReference.get(), and hoisting $referent may lead to non-terminating loops
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
This commit is contained in:
parent
e3c3c8527e
commit
04c6a7ce10
9 changed files with 333 additions and 300 deletions
|
@ -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 = NULL;
|
||||||
|
|
||||||
jbyte* G1PostBarrierStub::byte_map_base_slow() {
|
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 = NULL;
|
||||||
|
|
||||||
jbyte* G1PostBarrierStub::byte_map_base_slow() {
|
jbyte* G1PostBarrierStub::byte_map_base_slow() {
|
||||||
|
|
|
@ -574,71 +574,6 @@ class G1PreBarrierStub: public CodeStub {
|
||||||
#endif // PRODUCT
|
#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 {
|
class G1PostBarrierStub: public CodeStub {
|
||||||
private:
|
private:
|
||||||
LIR_Opr _addr;
|
LIR_Opr _addr;
|
||||||
|
|
|
@ -3058,7 +3058,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
|
||||||
|
|
||||||
case vmIntrinsics::_Reference_get:
|
case vmIntrinsics::_Reference_get:
|
||||||
{
|
{
|
||||||
if (UseG1GC) {
|
{
|
||||||
// With java.lang.ref.reference.get() we must go through the
|
// With java.lang.ref.reference.get() we must go through the
|
||||||
// intrinsic - when G1 is enabled - even when get() is the root
|
// intrinsic - when G1 is enabled - even when get() is the root
|
||||||
// method of the compile so that, if necessary, the value in
|
// 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
|
// object removed from the list of discovered references during
|
||||||
// reference processing.
|
// 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.
|
// Set up a stream so that appending instructions works properly.
|
||||||
ciBytecodeStream s(scope->method());
|
ciBytecodeStream s(scope->method());
|
||||||
s.reset_to_bci(0);
|
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) {
|
bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
||||||
if (!InlineNatives ) INLINE_BAILOUT("intrinsic method inlining disabled");
|
|
||||||
if (callee->is_synchronized()) {
|
if (callee->is_synchronized()) {
|
||||||
// We don't currently support any synchronized intrinsics
|
// We don't currently support any synchronized intrinsics
|
||||||
return false;
|
return false;
|
||||||
|
@ -3234,9 +3236,13 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
||||||
|
|
||||||
// callee seems like a good candidate
|
// callee seems like a good candidate
|
||||||
// determine id
|
// 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 preserves_state = false;
|
||||||
bool cantrap = true;
|
bool cantrap = true;
|
||||||
vmIntrinsics::ID id = callee->intrinsic_id();
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case vmIntrinsics::_arraycopy:
|
case vmIntrinsics::_arraycopy:
|
||||||
if (!InlineArrayCopy) return false;
|
if (!InlineArrayCopy) return false;
|
||||||
|
@ -3376,11 +3382,10 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case vmIntrinsics::_Reference_get:
|
case vmIntrinsics::_Reference_get:
|
||||||
// It is only when G1 is enabled that we absolutely
|
// Use the intrinsic version of Reference.get() so that the value in
|
||||||
// need to use the intrinsic version of Reference.get()
|
// the referent field can be registered by the G1 pre-barrier code.
|
||||||
// so that the value in the referent field, if necessary,
|
// Also to prevent commoning reads from this field across safepoint
|
||||||
// can be registered by the pre-barrier code.
|
// since GC can change its value.
|
||||||
if (!UseG1GC) return false;
|
|
||||||
preserves_state = true;
|
preserves_state = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -2176,9 +2176,9 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
|
||||||
off.load_item();
|
off.load_item();
|
||||||
src.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
|
#ifndef SERIALGC
|
||||||
// We might be reading the value of the referent field of a
|
// 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 (offset == java_lang_ref_Reference::referent_offset) {
|
||||||
// if (src != NULL) {
|
// if (src != NULL) {
|
||||||
// if (klass(src)->reference_type() != REF_NONE) {
|
// 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) {
|
if (UseG1GC && type == T_OBJECT) {
|
||||||
bool gen_code_stub = true; // Assume we need to generate the slow code stub.
|
bool gen_pre_barrier = true; // Assume we need to generate pre_barrier.
|
||||||
bool gen_offset_check = true; // Assume the code stub has to generate the offset guard.
|
bool gen_offset_check = true; // Assume we need to generate the offset guard.
|
||||||
bool gen_source_check = true; // Assume the code stub has to check the src object for null.
|
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()) {
|
if (off.is_constant()) {
|
||||||
jlong off_con = (off.type()->is_int() ?
|
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.
|
// The constant offset is something other than referent_offset.
|
||||||
// We can skip generating/checking the remaining guards and
|
// We can skip generating/checking the remaining guards and
|
||||||
// skip generation of the code stub.
|
// skip generation of the code stub.
|
||||||
gen_code_stub = false;
|
gen_pre_barrier = false;
|
||||||
} else {
|
} else {
|
||||||
// The constant offset is the same as referent_offset -
|
// The constant offset is the same as referent_offset -
|
||||||
// we do not need to generate a runtime offset check.
|
// 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
|
// We don't need to generate stub if the source object is an array
|
||||||
if (gen_code_stub && src.type()->is_array()) {
|
if (gen_pre_barrier && src.type()->is_array()) {
|
||||||
gen_code_stub = false;
|
gen_pre_barrier = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen_code_stub) {
|
if (gen_pre_barrier) {
|
||||||
// We still need to continue with the checks.
|
// We still need to continue with the checks.
|
||||||
if (src.is_constant()) {
|
if (src.is_constant()) {
|
||||||
ciObject* src_con = src.get_jobject_constant();
|
ciObject* src_con = src.get_jobject_constant();
|
||||||
|
@ -2236,7 +2233,7 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
|
||||||
if (src_con->is_null_object()) {
|
if (src_con->is_null_object()) {
|
||||||
// The constant src object is null - We can skip
|
// The constant src object is null - We can skip
|
||||||
// generating the code stub.
|
// generating the code stub.
|
||||||
gen_code_stub = false;
|
gen_pre_barrier = false;
|
||||||
} else {
|
} else {
|
||||||
// Non-null constant source object. We still have to generate
|
// Non-null constant source object. We still have to generate
|
||||||
// the slow stub - but we don't need to generate the runtime
|
// 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) {
|
if (gen_pre_barrier) {
|
||||||
// Temoraries.
|
LabelObj* Lcont = new LabelObj();
|
||||||
LIR_Opr src_klass = new_register(T_OBJECT);
|
|
||||||
|
|
||||||
// Get the thread pointer for the pre-barrier
|
|
||||||
LIR_Opr thread = getThreadPointer();
|
|
||||||
|
|
||||||
CodeStub* stub;
|
|
||||||
|
|
||||||
// We can have generate one runtime check here. Let's start with
|
// We can have generate one runtime check here. Let's start with
|
||||||
// the offset check.
|
// the offset check.
|
||||||
if (gen_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
|
// If offset is an int then we can do the comparison with the
|
||||||
// referent_offset constant; otherwise we need to move
|
// referent_offset constant; otherwise we need to move
|
||||||
// referent_offset into a temporary register and generate
|
// referent_offset into a temporary register and generate
|
||||||
|
@ -2273,43 +2278,36 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
|
||||||
referent_off = new_register(T_LONG);
|
referent_off = new_register(T_LONG);
|
||||||
__ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off);
|
__ move(LIR_OprFact::longConst(java_lang_ref_Reference::referent_offset), referent_off);
|
||||||
}
|
}
|
||||||
|
__ cmp(lir_cond_notEqual, off.result(), referent_off);
|
||||||
__ cmp(lir_cond_equal, off.result(), referent_off);
|
__ branch(lir_cond_notEqual, as_BasicType(off.type()), Lcont->label());
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (gen_source_check) {
|
||||||
// Continuation point
|
// offset is a const and equals referent offset
|
||||||
__ branch_destination(stub->continuation());
|
// 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
|
#endif // SERIALGC
|
||||||
|
|
|
@ -295,7 +295,11 @@ Node* IdealKit::transform(Node* n) {
|
||||||
if (_delay_all_transforms) {
|
if (_delay_all_transforms) {
|
||||||
return delay_transform(n);
|
return delay_transform(n);
|
||||||
} else {
|
} 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.
|
// Helper for inline_unsafe_access.
|
||||||
// Generates the guards that check whether the result of
|
// Generates the guards that check whether the result of
|
||||||
// Unsafe.getObject should be recorded in an SATB log buffer.
|
// 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_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_prefetch(bool is_native_ptr, bool is_store, bool is_static);
|
||||||
bool inline_unsafe_allocate();
|
bool inline_unsafe_allocate();
|
||||||
|
@ -291,6 +291,8 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
||||||
case vmIntrinsics::_equals:
|
case vmIntrinsics::_equals:
|
||||||
case vmIntrinsics::_equalsC:
|
case vmIntrinsics::_equalsC:
|
||||||
break; // InlineNatives does not control String.compareTo
|
break; // InlineNatives does not control String.compareTo
|
||||||
|
case vmIntrinsics::_Reference_get:
|
||||||
|
break; // InlineNatives does not control Reference.get
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -361,11 +363,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vmIntrinsics::_Reference_get:
|
case vmIntrinsics::_Reference_get:
|
||||||
// It is only when G1 is enabled that we absolutely
|
// Use the intrinsic version of Reference.get() so that the value in
|
||||||
// need to use the intrinsic version of Reference.get()
|
// the referent field can be registered by the G1 pre-barrier code.
|
||||||
// so that the value in the referent field, if necessary,
|
// Also add memory barrier to prevent commoning reads from this field
|
||||||
// can be registered by the pre-barrier code.
|
// across safepoint since GC can change it value.
|
||||||
if (!UseG1GC) return NULL;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -2195,14 +2196,17 @@ bool LibraryCallKit::inline_reverseBytes(vmIntrinsics::ID id) {
|
||||||
|
|
||||||
const static BasicType T_ADDRESS_HOLDER = T_LONG;
|
const static BasicType T_ADDRESS_HOLDER = T_LONG;
|
||||||
|
|
||||||
// Helper that guards and inserts a G1 pre-barrier.
|
// Helper that guards and inserts a pre-barrier.
|
||||||
void LibraryCallKit::insert_g1_pre_barrier(Node* base_oop, Node* offset, Node* pre_val) {
|
void LibraryCallKit::insert_pre_barrier(Node* base_oop, Node* offset,
|
||||||
assert(UseG1GC, "should not call this otherwise");
|
Node* pre_val, int nargs, bool need_mem_bar) {
|
||||||
|
|
||||||
// We could be accessing the referent field of a reference object. If so, when G1
|
// 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.
|
// 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
|
// This routine performs some compile time filters and generates suitable
|
||||||
// runtime filters that guard the pre-barrier code.
|
// 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.
|
// 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();
|
const TypeInstPtr* itype = btype->isa_instptr();
|
||||||
if (itype != NULL) {
|
if (itype != NULL) {
|
||||||
// Can the klass of base_oop be statically determined
|
// Can the klass of base_oop be statically determined to be
|
||||||
// to be _not_ a sub-class of Reference?
|
// _not_ a sub-class of Reference and _not_ Object?
|
||||||
ciKlass* klass = itype->klass();
|
ciKlass* klass = itype->klass();
|
||||||
if (klass->is_subtype_of(env()->Reference_klass()) &&
|
if ( klass->is_loaded() &&
|
||||||
!env()->Reference_klass()->is_subtype_of(klass)) {
|
!klass->is_subtype_of(env()->Reference_klass()) &&
|
||||||
|
!env()->Object_klass()->is_subtype_of(klass)) {
|
||||||
return;
|
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
|
// we need to generate the following runtime filters
|
||||||
//
|
//
|
||||||
// if (offset == java_lang_ref_Reference::_reference_offset) {
|
// if (offset == java_lang_ref_Reference::_reference_offset) {
|
||||||
// if (base != null) {
|
// if (instance_of(base, java.lang.ref.Reference)) {
|
||||||
// if (instance_of(base, java.lang.ref.Reference)) {
|
// pre_barrier(_, pre_val, ...);
|
||||||
// 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);
|
Node* referent_off = __ ConX(java_lang_ref_Reference::referent_offset);
|
||||||
|
|
||||||
__ if_then(offset, BoolTest::eq, referent_off, unlikely); {
|
__ if_then(offset, BoolTest::eq, referent_off, unlikely); {
|
||||||
__ if_then(base_oop, BoolTest::ne, null(), likely); {
|
|
||||||
|
|
||||||
// Update graphKit memory and control from IdealKit.
|
// Update graphKit memory and control from IdealKit.
|
||||||
sync_kit(ideal);
|
sync_kit(ideal);
|
||||||
|
|
||||||
Node* ref_klass_con = makecon(TypeKlassPtr::make(env()->Reference_klass()));
|
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);
|
Node* is_instof = gen_instanceof(base_oop, ref_klass_con);
|
||||||
|
_sp -= nargs;
|
||||||
|
|
||||||
// Update IdealKit memory and control from graphKit.
|
// Update IdealKit memory and control from graphKit.
|
||||||
__ sync_kit(this);
|
__ sync_kit(this);
|
||||||
|
|
||||||
Node* one = __ ConI(1);
|
Node* one = __ ConI(1);
|
||||||
|
// is_instof == 0 if base_oop == NULL
|
||||||
__ if_then(is_instof, BoolTest::eq, one, unlikely); {
|
__ if_then(is_instof, BoolTest::eq, one, unlikely); {
|
||||||
|
|
||||||
// Update graphKit from IdeakKit.
|
// 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 */,
|
NULL /* obj */, NULL /* adr */, max_juint /* alias_idx */, NULL /* val */, NULL /* val_type */,
|
||||||
pre_val /* pre_val */,
|
pre_val /* pre_val */,
|
||||||
T_OBJECT);
|
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.
|
// Update IdealKit from graphKit.
|
||||||
__ sync_kit(this);
|
__ sync_kit(this);
|
||||||
|
|
||||||
} __ end_if(); // _ref_type != ref_none
|
} __ end_if(); // _ref_type != ref_none
|
||||||
} __ end_if(); // base != NULL
|
|
||||||
} __ end_if(); // offset == referent_offset
|
} __ end_if(); // offset == referent_offset
|
||||||
|
|
||||||
// Final sync IdealKit and GraphKit.
|
// 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)
|
// object (either by using Unsafe directly or through reflection)
|
||||||
// then, if G1 is enabled, we need to record the referent in an
|
// then, if G1 is enabled, we need to record the referent in an
|
||||||
// SATB log buffer using the pre-barrier mechanism.
|
// 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();
|
offset != top() && heap_base_oop != top();
|
||||||
|
|
||||||
if (!is_store && type == T_OBJECT) {
|
if (!is_store && type == T_OBJECT) {
|
||||||
|
@ -2508,7 +2516,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
|
||||||
break;
|
break;
|
||||||
case T_OBJECT:
|
case T_OBJECT:
|
||||||
if (need_read_barrier) {
|
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);
|
push(p);
|
||||||
break;
|
break;
|
||||||
|
@ -5484,6 +5492,10 @@ bool LibraryCallKit::inline_reference_get() {
|
||||||
result /* pre_val */,
|
result /* pre_val */,
|
||||||
T_OBJECT);
|
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);
|
push(result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
78
hotspot/test/compiler/7190310/Test7190310.java
Normal file
78
hotspot/test/compiler/7190310/Test7190310.java
Normal file
|
@ -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<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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
142
hotspot/test/compiler/7190310/Test7190310_unsafe.java
Normal file
142
hotspot/test/compiler/7190310/Test7190310_unsafe.java
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue