aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm
diff options
context:
space:
mode:
authorjohnc <none@none>2011-04-07 09:53:20 -0700
committerjohnc <none@none>2011-04-07 09:53:20 -0700
commit39ae0f3b71eb409a242a74e250f4ecc5ee45fd66 (patch)
tree90dffd8107387a2f6ec0069bf6b8baaf3ad4448c /src/share/vm
parentb3f3ded21caf5b2c783f867c8af20967f039e1c9 (diff)
7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer. Reviewed-by: kvn, iveresov, never, tonyp, dholmes
Diffstat (limited to 'src/share/vm')
-rw-r--r--src/share/vm/c1/c1_CodeStubs.hpp102
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.cpp49
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.cpp204
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.hpp6
-rw-r--r--src/share/vm/classfile/vmSymbols.hpp4
-rw-r--r--src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp20
-rw-r--r--src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp9
-rw-r--r--src/share/vm/gc_implementation/g1/g1_globals.hpp14
-rw-r--r--src/share/vm/interpreter/abstractInterpreter.hpp3
-rw-r--r--src/share/vm/interpreter/cppInterpreter.cpp3
-rw-r--r--src/share/vm/interpreter/interpreter.cpp15
-rw-r--r--src/share/vm/interpreter/templateInterpreter.cpp1
-rw-r--r--src/share/vm/oops/instanceKlass.hpp2
-rw-r--r--src/share/vm/opto/compile.cpp23
-rw-r--r--src/share/vm/opto/graphKit.cpp65
-rw-r--r--src/share/vm/opto/graphKit.hpp12
-rw-r--r--src/share/vm/opto/library_call.cpp226
-rw-r--r--src/share/vm/prims/jni.cpp23
-rw-r--r--src/share/vm/prims/unsafe.cpp57
19 files changed, 724 insertions, 114 deletions
diff --git a/src/share/vm/c1/c1_CodeStubs.hpp b/src/share/vm/c1/c1_CodeStubs.hpp
index 1367f080d..128a6d48c 100644
--- a/src/share/vm/c1/c1_CodeStubs.hpp
+++ b/src/share/vm/c1/c1_CodeStubs.hpp
@@ -519,42 +519,126 @@ class ArrayCopyStub: public CodeStub {
// Code stubs for Garbage-First barriers.
class G1PreBarrierStub: public CodeStub {
private:
+ bool _do_load;
LIR_Opr _addr;
LIR_Opr _pre_val;
LIR_PatchCode _patch_code;
CodeEmitInfo* _info;
public:
- // pre_val (a temporary register) must be a register;
+ // Version that _does_ generate a load of the previous value from addr.
// addr (the address of the field to be read) must be a LIR_Address
+ // pre_val (a temporary register) must be a register;
G1PreBarrierStub(LIR_Opr addr, LIR_Opr pre_val, LIR_PatchCode patch_code, CodeEmitInfo* info) :
- _addr(addr), _pre_val(pre_val), _patch_code(patch_code), _info(info)
+ _addr(addr), _pre_val(pre_val), _do_load(true),
+ _patch_code(patch_code), _info(info)
{
assert(_pre_val->is_register(), "should be temporary register");
assert(_addr->is_address(), "should be the address of the field");
}
+ // Version that _does not_ generate load of the previous value; the
+ // previous value is assumed to have already been loaded into pre_val.
+ G1PreBarrierStub(LIR_Opr pre_val) :
+ _addr(LIR_OprFact::illegalOpr), _pre_val(pre_val), _do_load(false),
+ _patch_code(lir_patch_none), _info(NULL)
+ {
+ assert(_pre_val->is_register(), "should be a register");
+ }
+
LIR_Opr addr() const { return _addr; }
LIR_Opr pre_val() const { return _pre_val; }
LIR_PatchCode patch_code() const { return _patch_code; }
CodeEmitInfo* info() const { return _info; }
+ bool do_load() const { return _do_load; }
virtual void emit_code(LIR_Assembler* e);
virtual void visit(LIR_OpVisitState* visitor) {
- // don't pass in the code emit info since it's processed in the fast
- // path
- if (_info != NULL)
- visitor->do_slow_case(_info);
- else
+ if (_do_load) {
+ // don't pass in the code emit info since it's processed in the fast
+ // path
+ if (_info != NULL)
+ visitor->do_slow_case(_info);
+ else
+ visitor->do_slow_case();
+
+ visitor->do_input(_addr);
+ visitor->do_temp(_pre_val);
+ } else {
visitor->do_slow_case();
- visitor->do_input(_addr);
- visitor->do_temp(_pre_val);
+ visitor->do_input(_pre_val);
+ }
}
#ifndef PRODUCT
virtual void print_name(outputStream* out) const { out->print("G1PreBarrierStub"); }
#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 4e5f4edf0..b20c5c72b 100644
--- a/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -2912,6 +2912,46 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
block()->set_end(end);
break;
}
+
+ 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
+ // the referent field of the reference object gets recorded by
+ // the pre-barrier code.
+ // Specifically, if G1 is enabled, the value in the referent
+ // field is recorded by the G1 SATB pre barrier. This will
+ // result in the referent being marked live and the reference
+ // object removed from the list of discovered references during
+ // reference processing.
+
+ // Set up a stream so that appending instructions works properly.
+ ciBytecodeStream s(scope->method());
+ s.reset_to_bci(0);
+ scope_data()->set_stream(&s);
+ s.next();
+
+ // setup the initial block state
+ _block = start_block;
+ _state = start_block->state()->copy_for_parsing();
+ _last = start_block;
+ load_local(objectType, 0);
+
+ // Emit the intrinsic node.
+ bool result = try_inline_intrinsics(scope->method());
+ if (!result) BAILOUT("failed to inline intrinsic");
+ method_return(apop());
+
+ // connect the begin and end blocks and we're all done.
+ BlockEnd* end = last()->as_BlockEnd();
+ block()->set_end(end);
+ break;
+ }
+ // Otherwise, fall thru
+ }
+
default:
scope_data()->add_to_work_list(start_block);
iterate_all_blocks();
@@ -3149,6 +3189,15 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
append_unsafe_CAS(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;
+ preserves_state = true;
+ break;
+
default : return false; // do not inline
}
// create intrinsic node
diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp
index ae3773bcc..ee9f1abf7 100644
--- a/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -1104,6 +1104,38 @@ void LIRGenerator::do_Return(Return* x) {
set_no_result(x);
}
+// Examble: ref.get()
+// Combination of LoadField and g1 pre-write barrier
+void LIRGenerator::do_Reference_get(Intrinsic* x) {
+
+ const int referent_offset = java_lang_ref_Reference::referent_offset;
+ guarantee(referent_offset > 0, "referent offset not initialized");
+
+ assert(x->number_of_arguments() == 1, "wrong type");
+
+ LIRItem reference(x->argument_at(0), this);
+ reference.load_item();
+
+ // need to perform the null check on the reference objecy
+ CodeEmitInfo* info = NULL;
+ if (x->needs_null_check()) {
+ info = state_for(x);
+ }
+
+ LIR_Address* referent_field_adr =
+ new LIR_Address(reference.result(), referent_offset, T_OBJECT);
+
+ LIR_Opr result = rlock_result(x);
+
+ __ load(referent_field_adr, result, info);
+
+ // Register the value in the referent field with the pre-barrier
+ pre_barrier(LIR_OprFact::illegalOpr /* addr_opr */,
+ result /* pre_val */,
+ false /* do_load */,
+ false /* patch */,
+ NULL /* info */);
+}
// Example: object.getClass ()
void LIRGenerator::do_getClass(Intrinsic* x) {
@@ -1246,13 +1278,14 @@ LIR_Opr LIRGenerator::load_constant(LIR_Const* c) {
// Various barriers
-void LIRGenerator::pre_barrier(LIR_Opr addr_opr, bool patch, CodeEmitInfo* info) {
+void LIRGenerator::pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val,
+ bool do_load, bool patch, CodeEmitInfo* info) {
// Do the pre-write barrier, if any.
switch (_bs->kind()) {
#ifndef SERIALGC
case BarrierSet::G1SATBCT:
case BarrierSet::G1SATBCTLogging:
- G1SATBCardTableModRef_pre_barrier(addr_opr, patch, info);
+ G1SATBCardTableModRef_pre_barrier(addr_opr, pre_val, do_load, patch, info);
break;
#endif // SERIALGC
case BarrierSet::CardTableModRef:
@@ -1293,9 +1326,8 @@ void LIRGenerator::post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) {
////////////////////////////////////////////////////////////////////////
#ifndef SERIALGC
-void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, bool patch, CodeEmitInfo* info) {
- if (G1DisablePreBarrier) return;
-
+void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val,
+ bool do_load, bool patch, CodeEmitInfo* info) {
// First we test whether marking is in progress.
BasicType flag_type;
if (in_bytes(PtrQueue::byte_width_of_active()) == 4) {
@@ -1314,26 +1346,40 @@ void LIRGenerator::G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, bool patc
// Read the marking-in-progress flag.
LIR_Opr flag_val = new_register(T_INT);
__ load(mark_active_flag_addr, flag_val);
+ __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
- LIR_PatchCode pre_val_patch_code =
- patch ? lir_patch_normal : lir_patch_none;
+ LIR_PatchCode pre_val_patch_code = lir_patch_none;
- LIR_Opr pre_val = new_register(T_OBJECT);
+ CodeStub* slow;
- __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0));
- if (!addr_opr->is_address()) {
- assert(addr_opr->is_register(), "must be");
- addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT));
+ if (do_load) {
+ assert(pre_val == LIR_OprFact::illegalOpr, "sanity");
+ assert(addr_opr != LIR_OprFact::illegalOpr, "sanity");
+
+ if (patch)
+ pre_val_patch_code = lir_patch_normal;
+
+ pre_val = new_register(T_OBJECT);
+
+ if (!addr_opr->is_address()) {
+ assert(addr_opr->is_register(), "must be");
+ addr_opr = LIR_OprFact::address(new LIR_Address(addr_opr, T_OBJECT));
+ }
+ slow = new G1PreBarrierStub(addr_opr, pre_val, pre_val_patch_code, info);
+ } else {
+ assert(addr_opr == LIR_OprFact::illegalOpr, "sanity");
+ assert(pre_val->is_register(), "must be");
+ assert(pre_val->type() == T_OBJECT, "must be an object");
+ assert(info == NULL, "sanity");
+
+ slow = new G1PreBarrierStub(pre_val);
}
- CodeStub* slow = new G1PreBarrierStub(addr_opr, pre_val, pre_val_patch_code,
- info);
+
__ branch(lir_cond_notEqual, T_INT, slow);
__ branch_destination(slow->continuation());
}
void LIRGenerator::G1SATBCardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val) {
- if (G1DisablePostBarrier) return;
-
// If the "new_val" is a constant NULL, no barrier is necessary.
if (new_val->is_constant() &&
new_val->as_constant_ptr()->as_jobject() == NULL) return;
@@ -1555,6 +1601,8 @@ void LIRGenerator::do_StoreField(StoreField* x) {
if (is_oop) {
// Do the pre-write barrier, if any.
pre_barrier(LIR_OprFact::address(address),
+ LIR_OprFact::illegalOpr /* pre_val */,
+ true /* do_load*/,
needs_patching,
(info ? new CodeEmitInfo(info) : NULL));
}
@@ -1984,9 +2032,127 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
off.load_item();
src.load_item();
- LIR_Opr reg = reg = rlock_result(x, x->basic_type());
+ LIR_Opr reg = rlock_result(x, x->basic_type());
get_Object_unsafe(reg, src.result(), off.result(), type, x->is_volatile());
+
+#ifndef SERIALGC
+ // We might be reading the value of the referent field of a
+ // Reference object in order to attach it back to the live
+ // object graph. If G1 is enabled then we need to record
+ // the value that is being returned in an SATB log buffer.
+ //
+ // We need to generate code similar to the following...
+ //
+ // if (offset == java_lang_ref_Reference::referent_offset) {
+ // if (src != NULL) {
+ // if (klass(src)->reference_type() != REF_NONE) {
+ // pre_barrier(..., reg, ...);
+ // }
+ // }
+ // }
+ //
+ // 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.
+
+ if (off.is_constant()) {
+ jint off_con = off.get_jint_constant();
+
+ if (off_con != java_lang_ref_Reference::referent_offset) {
+ // 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;
+ } else {
+ // The constant offset is the same as referent_offset -
+ // we do not need to generate a runtime offset check.
+ gen_offset_check = false;
+ }
+ }
+
+ // 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_code_stub) {
+ // We still need to continue with the checks.
+ if (src.is_constant()) {
+ ciObject* src_con = src.get_jobject_constant();
+
+ if (src_con->is_null_object()) {
+ // The constant src object is null - We can skip
+ // generating the code stub.
+ gen_code_stub = false;
+ } else {
+ // Non-null constant source object. We still have to generate
+ // the slow stub - but we don't need to generate the runtime
+ // null object check.
+ gen_source_check = 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;
+
+ // 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
+ __ cmp(lir_cond_equal, off.result(),
+ LIR_OprFact::intConst(java_lang_ref_Reference::referent_offset));
+
+ // Optionally generate "src == null" check.
+ stub = new G1UnsafeGetObjSATBBarrierStub(reg, src.result(),
+ src_klass, thread,
+ gen_source_check);
+
+ __ branch(lir_cond_equal, T_INT, 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);
+ }
+ }
+
+ // Continuation point
+ __ branch_destination(stub->continuation());
+ }
+ }
+#endif // SERIALGC
+
if (x->is_volatile() && os::is_MP()) __ membar_acquire();
}
@@ -2652,6 +2818,10 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
do_AttemptUpdate(x);
break;
+ case vmIntrinsics::_Reference_get:
+ do_Reference_get(x);
+ break;
+
default: ShouldNotReachHere(); break;
}
}
diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp
index 4b9c4aeca..2b8fc23e6 100644
--- a/src/share/vm/c1/c1_LIRGenerator.hpp
+++ b/src/share/vm/c1/c1_LIRGenerator.hpp
@@ -246,6 +246,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_AttemptUpdate(Intrinsic* x);
void do_NIOCheckIndex(Intrinsic* x);
void do_FPIntrinsics(Intrinsic* x);
+ void do_Reference_get(Intrinsic* x);
void do_UnsafePrefetch(UnsafePrefetch* x, bool is_store);
@@ -260,13 +261,14 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
// generic interface
- void pre_barrier(LIR_Opr addr_opr, bool patch, CodeEmitInfo* info);
+ void pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val, bool do_load, bool patch, CodeEmitInfo* info);
void post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new_val);
// specific implementations
// pre barriers
- void G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, bool patch, CodeEmitInfo* info);
+ void G1SATBCardTableModRef_pre_barrier(LIR_Opr addr_opr, LIR_Opr pre_val,
+ bool do_load, bool patch, CodeEmitInfo* info);
// post barriers
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
index 81376926f..55dfd7168 100644
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
@@ -706,6 +706,10 @@
do_intrinsic(_checkIndex, java_nio_Buffer, checkIndex_name, int_int_signature, F_R) \
do_name( checkIndex_name, "checkIndex") \
\
+ /* java/lang/ref/Reference */ \
+ do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
+ \
+ \
do_class(sun_misc_AtomicLongCSImpl, "sun/misc/AtomicLongCSImpl") \
do_intrinsic(_get_AtomicLong, sun_misc_AtomicLongCSImpl, get_name, void_long_signature, F_R) \
/* (symbols get_name and void_long_signature defined above) */ \
diff --git a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp
index 8145aa9fc..59d259065 100644
--- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp
+++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2011, 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
@@ -47,7 +47,9 @@ G1SATBCardTableModRefBS::G1SATBCardTableModRefBS(MemRegion whole_heap,
void G1SATBCardTableModRefBS::enqueue(oop pre_val) {
- assert(pre_val->is_oop_or_null(true), "Error");
+ // Nulls should have been already filtered.
+ assert(pre_val->is_oop(true), "Error");
+
if (!JavaThread::satb_mark_queue_set().is_active()) return;
Thread* thr = Thread::current();
if (thr->is_Java_thread()) {
@@ -59,20 +61,6 @@ void G1SATBCardTableModRefBS::enqueue(oop pre_val) {
}
}
-// When we know the current java thread:
-template <class T> void
-G1SATBCardTableModRefBS::write_ref_field_pre_static(T* field,
- oop new_val,
- JavaThread* jt) {
- if (!JavaThread::satb_mark_queue_set().is_active()) return;
- T heap_oop = oopDesc::load_heap_oop(field);
- if (!oopDesc::is_null(heap_oop)) {
- oop pre_val = oopDesc::decode_heap_oop_not_null(heap_oop);
- assert(pre_val->is_oop(true /* ignore mark word */), "Error");
- jt->satb_mark_queue().enqueue(pre_val);
- }
-}
-
template <class T> void
G1SATBCardTableModRefBS::write_ref_array_pre_work(T* dst, int count) {
if (!JavaThread::satb_mark_queue_set().is_active()) return;
diff --git a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp
index a8c7e7e9a..dde3ba4be 100644
--- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp
+++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2011, 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
@@ -37,12 +37,11 @@ class DirtyCardQueueSet;
// snapshot-at-the-beginning marking.
class G1SATBCardTableModRefBS: public CardTableModRefBSForCTRS {
-private:
+public:
// Add "pre_val" to a set of objects that may have been disconnected from the
// pre-marking object graph.
static void enqueue(oop pre_val);
-public:
G1SATBCardTableModRefBS(MemRegion whole_heap,
int max_covered_regions);
@@ -61,10 +60,6 @@ public:
}
}
- // When we know the current java thread:
- template <class T> static void write_ref_field_pre_static(T* field, oop newVal,
- JavaThread* jt);
-
// We export this to make it available in cases where the static
// type of the barrier set is known. Note that it is non-virtual.
template <class T> inline void inline_write_ref_field_pre(T* field, oop newVal) {
diff --git a/src/share/vm/gc_implementation/g1/g1_globals.hpp b/src/share/vm/gc_implementation/g1/g1_globals.hpp
index b42949f22..5fd535533 100644
--- a/src/share/vm/gc_implementation/g1/g1_globals.hpp
+++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp
@@ -89,13 +89,9 @@
"The number of discovered reference objects to process before " \
"draining concurrent marking work queues.") \
\
- experimental(bool, G1UseConcMarkReferenceProcessing, false, \
+ experimental(bool, G1UseConcMarkReferenceProcessing, true, \
"If true, enable reference discovery during concurrent " \
- "marking and reference processing at the end of remark " \
- "(unsafe).") \
- \
- develop(bool, G1SATBBarrierPrintNullPreVals, false, \
- "If true, count frac of ptr writes with null pre-vals.") \
+ "marking and reference processing at the end of remark.") \
\
product(intx, G1SATBBufferSize, 1*K, \
"Number of entries in an SATB log buffer.") \
@@ -150,12 +146,6 @@
develop(bool, G1PrintParCleanupStats, false, \
"When true, print extra stats about parallel cleanup.") \
\
- develop(bool, G1DisablePreBarrier, false, \
- "Disable generation of pre-barrier (i.e., marking barrier) ") \
- \
- develop(bool, G1DisablePostBarrier, false, \
- "Disable generation of post-barrier (i.e., RS barrier) ") \
- \
product(intx, G1UpdateBufferSize, 256, \
"Size of an update buffer") \
\
diff --git a/src/share/vm/interpreter/abstractInterpreter.hpp b/src/share/vm/interpreter/abstractInterpreter.hpp
index a1908a2c9..c407fbaba 100644
--- a/src/share/vm/interpreter/abstractInterpreter.hpp
+++ b/src/share/vm/interpreter/abstractInterpreter.hpp
@@ -104,6 +104,7 @@ class AbstractInterpreter: AllStatic {
java_lang_math_sqrt, // implementation of java.lang.Math.sqrt (x)
java_lang_math_log, // implementation of java.lang.Math.log (x)
java_lang_math_log10, // implementation of java.lang.Math.log10 (x)
+ java_lang_ref_reference_get, // implementation of java.lang.ref.Reference.get()
number_of_method_entries,
invalid = -1
};
@@ -140,7 +141,7 @@ class AbstractInterpreter: AllStatic {
// Method activation
static MethodKind method_kind(methodHandle m);
static address entry_for_kind(MethodKind k) { assert(0 <= k && k < number_of_method_entries, "illegal kind"); return _entry_table[k]; }
- static address entry_for_method(methodHandle m) { return _entry_table[method_kind(m)]; }
+ static address entry_for_method(methodHandle m) { return entry_for_kind(method_kind(m)); }
static void print_method_kind(MethodKind kind) PRODUCT_RETURN;
diff --git a/src/share/vm/interpreter/cppInterpreter.cpp b/src/share/vm/interpreter/cppInterpreter.cpp
index 6ce16e271..9a6669519 100644
--- a/src/share/vm/interpreter/cppInterpreter.cpp
+++ b/src/share/vm/interpreter/cppInterpreter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -125,6 +125,7 @@ void CppInterpreterGenerator::generate_all() {
method_entry(java_lang_math_sqrt );
method_entry(java_lang_math_log );
method_entry(java_lang_math_log10 );
+ method_entry(java_lang_ref_reference_get);
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
method_entry(native);
method_entry(native_synchronized);
diff --git a/src/share/vm/interpreter/interpreter.cpp b/src/share/vm/interpreter/interpreter.cpp
index 04a9d68f4..137f50ee3 100644
--- a/src/share/vm/interpreter/interpreter.cpp
+++ b/src/share/vm/interpreter/interpreter.cpp
@@ -208,12 +208,6 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m)
return empty;
}
- // Accessor method?
- if (m->is_accessor()) {
- assert(m->size_of_parameters() == 1, "fast code for accessors assumes parameter size = 1");
- return accessor;
- }
-
// Special intrinsic method?
// Note: This test must come _after_ the test for native methods,
// otherwise we will run into problems with JDK 1.2, see also
@@ -227,6 +221,15 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(methodHandle m)
case vmIntrinsics::_dsqrt : return java_lang_math_sqrt ;
case vmIntrinsics::_dlog : return java_lang_math_log ;
case vmIntrinsics::_dlog10: return java_lang_math_log10;
+
+ case vmIntrinsics::_Reference_get:
+ return java_lang_ref_reference_get;
+ }
+
+ // Accessor method?
+ if (m->is_accessor()) {
+ assert(m->size_of_parameters() == 1, "fast code for accessors assumes parameter size = 1");
+ return accessor;
}
// Note: for now: zero locals for all non-empty methods
diff --git a/src/share/vm/interpreter/templateInterpreter.cpp b/src/share/vm/interpreter/templateInterpreter.cpp
index 0d1125ecb..6b22dc1eb 100644
--- a/src/share/vm/interpreter/templateInterpreter.cpp
+++ b/src/share/vm/interpreter/templateInterpreter.cpp
@@ -372,6 +372,7 @@ void TemplateInterpreterGenerator::generate_all() {
method_entry(java_lang_math_sqrt )
method_entry(java_lang_math_log )
method_entry(java_lang_math_log10)
+ method_entry(java_lang_ref_reference_get)
// all native method kinds (must be one contiguous block)
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
index 07acfc358..75a1f7654 100644
--- a/src/share/vm/oops/instanceKlass.hpp
+++ b/src/share/vm/oops/instanceKlass.hpp
@@ -403,6 +403,8 @@ class instanceKlass: public Klass {
ReferenceType reference_type() const { return _reference_type; }
void set_reference_type(ReferenceType t) { _reference_type = t; }
+ static int reference_type_offset_in_bytes() { return offset_of(instanceKlass, _reference_type); }
+
// find local field, returns true if found
bool find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const;
// find field in direct superinterfaces, returns the interface in which the field is defined
diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
index 96f304251..93c14b3d1 100644
--- a/src/share/vm/opto/compile.cpp
+++ b/src/share/vm/opto/compile.cpp
@@ -629,7 +629,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
initial_gvn()->transform_no_reclaim(top());
// Set up tf(), start(), and find a CallGenerator.
- CallGenerator* cg;
+ CallGenerator* cg = NULL;
if (is_osr_compilation()) {
const TypeTuple *domain = StartOSRNode::osr_domain();
const TypeTuple *range = TypeTuple::make_range(method()->signature());
@@ -644,9 +644,24 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
StartNode* s = new (this, 2) StartNode(root(), tf()->domain());
initial_gvn()->set_type_bottom(s);
init_start(s);
- float past_uses = method()->interpreter_invocation_count();
- float expected_uses = past_uses;
- cg = CallGenerator::for_inline(method(), expected_uses);
+ if (method()->intrinsic_id() == vmIntrinsics::_Reference_get && 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
+ // the referent field of the reference object gets recorded by
+ // the pre-barrier code.
+ // Specifically, if G1 is enabled, the value in the referent
+ // field is recorded by the G1 SATB pre barrier. This will
+ // result in the referent being marked live and the reference
+ // object removed from the list of discovered references during
+ // reference processing.
+ cg = find_intrinsic(method(), false);
+ }
+ if (cg == NULL) {
+ float past_uses = method()->interpreter_invocation_count();
+ float expected_uses = past_uses;
+ cg = CallGenerator::for_inline(method(), expected_uses);
+ }
}
if (failing()) return;
if (cg == NULL) {
diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp
index b20513e67..d8ada0330 100644
--- a/src/share/vm/opto/graphKit.cpp
+++ b/src/share/vm/opto/graphKit.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2011, 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
@@ -1457,19 +1457,22 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
}
-void GraphKit::pre_barrier(Node* ctl,
+void GraphKit::pre_barrier(bool do_load,
+ Node* ctl,
Node* obj,
Node* adr,
uint adr_idx,
Node* val,
const TypeOopPtr* val_type,
+ Node* pre_val,
BasicType bt) {
+
BarrierSet* bs = Universe::heap()->barrier_set();
set_control(ctl);
switch (bs->kind()) {
case BarrierSet::G1SATBCT:
case BarrierSet::G1SATBCTLogging:
- g1_write_barrier_pre(obj, adr, adr_idx, val, val_type, bt);
+ g1_write_barrier_pre(do_load, obj, adr, adr_idx, val, val_type, pre_val, bt);
break;
case BarrierSet::CardTableModRef:
@@ -1532,7 +1535,11 @@ Node* GraphKit::store_oop(Node* ctl,
uint adr_idx = C->get_alias_index(adr_type);
assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
- pre_barrier(control(), obj, adr, adr_idx, val, val_type, bt);
+ pre_barrier(true /* do_load */,
+ control(), obj, adr, adr_idx, val, val_type,
+ NULL /* pre_val */,
+ bt);
+
Node* store = store_to_memory(control(), adr, val, bt, adr_idx);
post_barrier(control(), store, obj, adr, adr_idx, val, bt, use_precise);
return store;
@@ -3465,12 +3472,31 @@ void GraphKit::write_barrier_post(Node* oop_store,
}
// G1 pre/post barriers
-void GraphKit::g1_write_barrier_pre(Node* obj,
+void GraphKit::g1_write_barrier_pre(bool do_load,
+ Node* obj,
Node* adr,
uint alias_idx,
Node* val,
const TypeOopPtr* val_type,
+ Node* pre_val,
BasicType bt) {
+
+ // Some sanity checks
+ // Note: val is unused in this routine.
+
+ if (do_load) {
+ // We need to generate the load of the previous value
+ assert(obj != NULL, "must have a base");
+ assert(adr != NULL, "where are loading from?");
+ assert(pre_val == NULL, "loaded already?");
+ assert(val_type != NULL, "need a type");
+ } else {
+ // In this case both val_type and alias_idx are unused.
+ assert(pre_val != NULL, "must be loaded already");
+ assert(pre_val->bottom_type()->basic_type() == T_OBJECT, "or we shouldn't be here");
+ }
+ assert(bt == T_OBJECT, "or we shouldn't be here");
+
IdealKit ideal(gvn(), control(), merged_memory(), true);
Node* tls = __ thread(); // ThreadLocalStorage
@@ -3492,32 +3518,28 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
PtrQueue::byte_offset_of_index());
const int buffer_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 652
PtrQueue::byte_offset_of_buf());
- // Now the actual pointers into the thread
-
- // set_control( ctl);
+ // Now the actual pointers into the thread
Node* marking_adr = __ AddP(no_base, tls, __ ConX(marking_offset));
Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset));
Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset));
// Now some of the values
-
Node* marking = __ load(__ ctrl(), marking_adr, TypeInt::INT, active_type, Compile::AliasIdxRaw);
// if (!marking)
__ if_then(marking, BoolTest::ne, zero); {
Node* index = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
- const Type* t1 = adr->bottom_type();
- const Type* t2 = val->bottom_type();
-
- Node* orig = __ load(no_ctrl, adr, val_type, bt, alias_idx);
- // if (orig != NULL)
- __ if_then(orig, BoolTest::ne, null()); {
- Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
-
+ if (do_load) {
// load original value
// alias_idx correct??
+ pre_val = __ load(no_ctrl, adr, val_type, bt, alias_idx);
+ }
+
+ // if (pre_val != NULL)
+ __ if_then(pre_val, BoolTest::ne, null()); {
+ Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
// is the queue for this thread full?
__ if_then(index, BoolTest::ne, zero, likely); {
@@ -3531,10 +3553,9 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
next_indexX = _gvn.transform( new (C, 2) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) );
#endif
- // Now get the buffer location we will log the original value into and store it
+ // Now get the buffer location we will log the previous value into and store it
Node *log_addr = __ AddP(no_base, buffer, next_indexX);
- __ store(__ ctrl(), log_addr, orig, T_OBJECT, Compile::AliasIdxRaw);
-
+ __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw);
// update the index
__ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw);
@@ -3542,9 +3563,9 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
// logging buffer is full, call the runtime
const TypeFunc *tf = OptoRuntime::g1_wb_pre_Type();
- __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), "g1_wb_pre", orig, tls);
+ __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), "g1_wb_pre", pre_val, tls);
} __ end_if(); // (!index)
- } __ end_if(); // (orig != NULL)
+ } __ end_if(); // (pre_val != NULL)
} __ end_if(); // (!marking)
// Final sync IdealKit and GraphKit.
diff --git a/src/share/vm/opto/graphKit.hpp b/src/share/vm/opto/graphKit.hpp
index 2f7a7d5ab..91ab71965 100644
--- a/src/share/vm/opto/graphKit.hpp
+++ b/src/share/vm/opto/graphKit.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2011, 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
@@ -544,8 +544,10 @@ class GraphKit : public Phase {
BasicType bt);
// For the few case where the barriers need special help
- void pre_barrier(Node* ctl, Node* obj, Node* adr, uint adr_idx,
- Node* val, const TypeOopPtr* val_type, BasicType bt);
+ void pre_barrier(bool do_load, Node* ctl,
+ Node* obj, Node* adr, uint adr_idx, Node* val, const TypeOopPtr* val_type,
+ Node* pre_val,
+ BasicType bt);
void post_barrier(Node* ctl, Node* store, Node* obj, Node* adr, uint adr_idx,
Node* val, BasicType bt, bool use_precise);
@@ -669,11 +671,13 @@ class GraphKit : public Phase {
Node* adr, uint adr_idx, Node* val, bool use_precise);
// G1 pre/post barriers
- void g1_write_barrier_pre(Node* obj,
+ void g1_write_barrier_pre(bool do_load,
+ Node* obj,
Node* adr,
uint alias_idx,
Node* val,
const TypeOopPtr* val_type,
+ Node* pre_val,
BasicType bt);
void g1_write_barrier_post(Node* store,
diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
index 024955215..71a19501a 100644
--- a/src/share/vm/opto/library_call.cpp
+++ b/src/share/vm/opto/library_call.cpp
@@ -165,6 +165,10 @@ class LibraryCallKit : public GraphKit {
// This returns Type::AnyPtr, RawPtr, or OopPtr.
int classify_unsafe_addr(Node* &base, Node* &offset);
Node* make_unsafe_address(Node* base, Node* offset);
+ // 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);
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();
@@ -239,6 +243,8 @@ class LibraryCallKit : public GraphKit {
bool inline_numberOfTrailingZeros(vmIntrinsics::ID id);
bool inline_bitCount(vmIntrinsics::ID id);
bool inline_reverseBytes(vmIntrinsics::ID id);
+
+ bool inline_reference_get();
};
@@ -335,6 +341,14 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
if (!UsePopCountInstruction) return NULL;
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;
+ break;
+
default:
assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility");
assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?");
@@ -386,13 +400,22 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) {
tty->print_cr("Intrinsic %s", str);
}
#endif
+
if (kit.try_to_inline()) {
if (PrintIntrinsics || PrintInlining NOT_PRODUCT( || PrintOptoInlining) ) {
- tty->print("Inlining intrinsic %s%s at bci:%d in",
- vmIntrinsics::name_at(intrinsic_id()),
- (is_virtual() ? " (virtual)" : ""), kit.bci());
- kit.caller()->print_short_name(tty);
- tty->print_cr(" (%d bytes)", kit.caller()->code_size());
+ if (jvms->has_method()) {
+ // Not a root compile.
+ tty->print("Inlining intrinsic %s%s at bci:%d in",
+ vmIntrinsics::name_at(intrinsic_id()),
+ (is_virtual() ? " (virtual)" : ""), kit.bci());
+ kit.caller()->print_short_name(tty);
+ tty->print_cr(" (%d bytes)", kit.caller()->code_size());
+ } else {
+ // Root compile
+ tty->print_cr("Generating intrinsic %s%s at bci:%d",
+ vmIntrinsics::name_at(intrinsic_id()),
+ (is_virtual() ? " (virtual)" : ""), kit.bci());
+ }
}
C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_worked);
if (C->log()) {
@@ -405,11 +428,19 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms) {
}
if (PrintIntrinsics) {
- tty->print("Did not inline intrinsic %s%s at bci:%d in",
+ if (jvms->has_method()) {
+ // Not a root compile.
+ tty->print("Did not inline intrinsic %s%s at bci:%d in",
+ vmIntrinsics::name_at(intrinsic_id()),
+ (is_virtual() ? " (virtual)" : ""), kit.bci());
+ kit.caller()->print_short_name(tty);
+ tty->print_cr(" (%d bytes)", kit.caller()->code_size());
+ } else {
+ // Root compile
+ tty->print("Did not generate intrinsic %s%s at bci:%d in",
vmIntrinsics::name_at(intrinsic_id()),
(is_virtual() ? " (virtual)" : ""), kit.bci());
- kit.caller()->print_short_name(tty);
- tty->print_cr(" (%d bytes)", kit.caller()->code_size());
+ }
}
C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed);
return NULL;
@@ -421,6 +452,14 @@ bool LibraryCallKit::try_to_inline() {
const bool is_native_ptr = true;
const bool is_static = true;
+ if (!jvms()->has_method()) {
+ // Root JVMState has a null method.
+ assert(map()->memory()->Opcode() == Op_Parm, "");
+ // Insert the memory aliasing node
+ set_all_memory(reset_memory());
+ }
+ assert(merged_memory(), "");
+
switch (intrinsic_id()) {
case vmIntrinsics::_hashCode:
return inline_native_hashcode(intrinsic()->is_virtual(), !is_static);
@@ -661,6 +700,9 @@ bool LibraryCallKit::try_to_inline() {
case vmIntrinsics::_getCallerClass:
return inline_native_Reflection_getCallerClass();
+ case vmIntrinsics::_Reference_get:
+ return inline_reference_get();
+
default:
// If you get here, it may be that someone has added a new intrinsic
// to the list in vmSymbols.hpp without implementing it here.
@@ -2079,6 +2121,110 @@ 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");
+
+ // 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.
+
+ // Some compile time checks.
+
+ // If offset is a constant, is it java_lang_ref_Reference::_reference_offset?
+ const TypeX* otype = offset->find_intptr_t_type();
+ if (otype != NULL && otype->is_con() &&
+ otype->get_con() != java_lang_ref_Reference::referent_offset) {
+ // Constant offset but not the reference_offset so just return
+ return;
+ }
+
+ // We only need to generate the runtime guards for instances.
+ const TypeOopPtr* btype = base_oop->bottom_type()->isa_oopptr();
+ if (btype != NULL) {
+ if (btype->isa_aryptr()) {
+ // Array type so nothing to do
+ return;
+ }
+
+ 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?
+ ciKlass* klass = itype->klass();
+ if (klass->is_subtype_of(env()->Reference_klass()) &&
+ !env()->Reference_klass()->is_subtype_of(klass)) {
+ return;
+ }
+ }
+ }
+
+ // The compile time filters did not reject base_oop/offset so
+ // we need to generate the following runtime filters
+ //
+ // if (offset == java_lang_ref_Reference::_reference_offset) {
+ // if (base != null) {
+ // if (klass(base)->reference_type() != REF_NONE)) {
+ // pre_barrier(_, pre_val, ...);
+ // }
+ // }
+ // }
+
+ float likely = PROB_LIKELY(0.999);
+ float unlikely = PROB_UNLIKELY(0.999);
+
+ IdealKit ideal(gvn(), control(), merged_memory());
+#define __ ideal.
+
+ const int reference_type_offset = instanceKlass::reference_type_offset_in_bytes() +
+ sizeof(oopDesc);
+
+ Node* referent_off = __ ConI(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.
+ set_all_memory(__ merged_memory());
+ set_control(__ ctrl());
+
+ Node* ref_klass_con = makecon(TypeKlassPtr::make(env()->Reference_klass()));
+ Node* is_instof = gen_instanceof(base_oop, ref_klass_con);
+
+ // Update IdealKit memory and control from graphKit.
+ __ set_all_memory(merged_memory());
+ __ set_ctrl(control());
+
+ Node* one = __ ConI(1);
+
+ __ if_then(is_instof, BoolTest::eq, one, unlikely); {
+
+ // Update graphKit from IdeakKit.
+ set_all_memory(__ merged_memory());
+ set_control(__ ctrl());
+
+ // Use the pre-barrier to record the value in the referent field
+ pre_barrier(false /* do_load */,
+ __ ctrl(),
+ NULL /* obj */, NULL /* adr */, -1 /* alias_idx */, NULL /* val */, NULL /* val_type */,
+ pre_val /* pre_val */,
+ T_OBJECT);
+
+ // Update IdealKit from graphKit.
+ __ set_all_memory(merged_memory());
+ __ set_ctrl(control());
+
+ } __ end_if(); // _ref_type != ref_none
+ } __ end_if(); // base != NULL
+ } __ end_if(); // offset == referent_offset
+
+ // Final sync IdealKit and GraphKit.
+ sync_kit(ideal);
+#undef __
+}
+
+
// Interpret Unsafe.fieldOffset cookies correctly:
extern jlong Unsafe_field_offset_to_byte_offset(jlong field_offset);
@@ -2155,9 +2301,11 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
// Build address expression. See the code in inline_unsafe_prefetch.
Node *adr;
Node *heap_base_oop = top();
+ Node* offset = top();
+
if (!is_native_ptr) {
// The offset is a value produced by Unsafe.staticFieldOffset or Unsafe.objectFieldOffset
- Node* offset = pop_pair();
+ offset = pop_pair();
// The base is either a Java object or a value produced by Unsafe.staticFieldBase
Node* base = pop();
// We currently rely on the cookies produced by Unsafe.xxxFieldOffset
@@ -2198,6 +2346,13 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
// or Compile::must_alias will throw a diagnostic assert.)
bool need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM);
+ // If we are reading the value of the referent field of a Reference
+ // 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 &&
+ offset != top() && heap_base_oop != top();
+
if (!is_store && type == T_OBJECT) {
// Attempt to infer a sharper value type from the offset and base type.
ciKlass* sharpened_klass = NULL;
@@ -2281,8 +2436,13 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
case T_SHORT:
case T_INT:
case T_FLOAT:
+ push(p);
+ break;
case T_OBJECT:
- push( p );
+ if (need_read_barrier) {
+ insert_g1_pre_barrier(heap_base_oop, offset, p);
+ }
+ push(p);
break;
case T_ADDRESS:
// Cast to an int type.
@@ -2539,7 +2699,10 @@ bool LibraryCallKit::inline_unsafe_CAS(BasicType type) {
case T_OBJECT:
// reference stores need a store barrier.
// (They don't if CAS fails, but it isn't worth checking.)
- pre_barrier(control(), base, adr, alias_idx, newval, value_type->make_oopptr(), T_OBJECT);
+ pre_barrier(true /* do_load*/,
+ control(), base, adr, alias_idx, newval, value_type->make_oopptr(),
+ NULL /* pre_val*/,
+ T_OBJECT);
#ifdef _LP64
if (adr->bottom_type()->is_ptr_to_narrowoop()) {
Node *newval_enc = _gvn.transform(new (C, 2) EncodePNode(newval, newval->bottom_type()->make_narrowoop()));
@@ -5315,3 +5478,44 @@ LibraryCallKit::generate_unchecked_arraycopy(const TypePtr* adr_type,
copyfunc_addr, copyfunc_name, adr_type,
src_start, dest_start, copy_length XTOP);
}
+
+//----------------------------inline_reference_get----------------------------
+
+bool LibraryCallKit::inline_reference_get() {
+ const int nargs = 1; // self
+
+ guarantee(java_lang_ref_Reference::referent_offset > 0,
+ "should have already been set");
+
+ int referent_offset = java_lang_ref_Reference::referent_offset;
+
+ // Restore the stack and pop off the argument
+ _sp += nargs;
+ Node *reference_obj = pop();
+
+ // Null check on self without removing any arguments.
+ _sp += nargs;
+ reference_obj = do_null_check(reference_obj, T_OBJECT);
+ _sp -= nargs;;
+
+ if (stopped()) return true;
+
+ Node *adr = basic_plus_adr(reference_obj, reference_obj, referent_offset);
+
+ ciInstanceKlass* klass = env()->Object_klass();
+ const TypeOopPtr* object_type = TypeOopPtr::make_from_klass(klass);
+
+ Node* no_ctrl = NULL;
+ Node *result = make_load(no_ctrl, adr, object_type, T_OBJECT);
+
+ // Use the pre-barrier to record the value in the referent field
+ pre_barrier(false /* do_load */,
+ control(),
+ NULL /* obj */, NULL /* adr */, -1 /* alias_idx */, NULL /* val */, NULL /* val_type */,
+ result /* pre_val */,
+ T_OBJECT);
+
+ push(result);
+ return true;
+}
+
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index d77c7ce9e..56fa2e167 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -29,6 +29,9 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/linkResolver.hpp"
+#ifndef SERIALGC
+#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+#endif // SERIALGC
#include "memory/allocation.inline.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/oopFactory.hpp"
@@ -1724,6 +1727,26 @@ JNI_ENTRY(jobject, jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID
o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false);
}
jobject ret = JNIHandles::make_local(env, o->obj_field(offset));
+#ifndef SERIALGC
+ // If G1 is enabled and we are accessing the value of the referent
+ // field in a reference object then we need to register a non-null
+ // referent with the SATB barrier.
+ if (UseG1GC) {
+ bool needs_barrier = false;
+
+ if (ret != NULL &&
+ offset == java_lang_ref_Reference::referent_offset &&
+ instanceKlass::cast(k)->reference_type() != REF_NONE) {
+ assert(instanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
+ needs_barrier = true;
+ }
+
+ if (needs_barrier) {
+ oop referent = JNIHandles::resolve(ret);
+ G1SATBCardTableModRefBS::enqueue(referent);
+ }
+ }
+#endif // SERIALGC
DTRACE_PROBE1(hotspot_jni, GetObjectField__return, ret);
return ret;
JNI_END
diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp
index a4531e948..cde444f5e 100644
--- a/src/share/vm/prims/unsafe.cpp
+++ b/src/share/vm/prims/unsafe.cpp
@@ -24,6 +24,9 @@
#include "precompiled.hpp"
#include "classfile/vmSymbols.hpp"
+#ifndef SERIALGC
+#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+#endif // SERIALGC
#include "memory/allocation.inline.hpp"
#include "prims/jni.h"
#include "prims/jvm.h"
@@ -193,7 +196,32 @@ UNSAFE_ENTRY(jobject, Unsafe_GetObject140(JNIEnv *env, jobject unsafe, jobject o
UnsafeWrapper("Unsafe_GetObject");
if (obj == NULL) THROW_0(vmSymbols::java_lang_NullPointerException());
GET_OOP_FIELD(obj, offset, v)
- return JNIHandles::make_local(env, v);
+ jobject ret = JNIHandles::make_local(env, v);
+#ifndef SERIALGC
+ // We could be accessing the referent field in a reference
+ // object. If G1 is enabled then we need to register a non-null
+ // referent with the SATB barrier.
+ if (UseG1GC) {
+ bool needs_barrier = false;
+
+ if (ret != NULL) {
+ if (offset == java_lang_ref_Reference::referent_offset) {
+ oop o = JNIHandles::resolve_non_null(obj);
+ klassOop k = o->klass();
+ if (instanceKlass::cast(k)->reference_type() != REF_NONE) {
+ assert(instanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
+ needs_barrier = true;
+ }
+ }
+ }
+
+ if (needs_barrier) {
+ oop referent = JNIHandles::resolve(ret);
+ G1SATBCardTableModRefBS::enqueue(referent);
+ }
+ }
+#endif // SERIALGC
+ return ret;
UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_SetObject140(JNIEnv *env, jobject unsafe, jobject obj, jint offset, jobject x_h))
@@ -226,7 +254,32 @@ UNSAFE_END
UNSAFE_ENTRY(jobject, Unsafe_GetObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset))
UnsafeWrapper("Unsafe_GetObject");
GET_OOP_FIELD(obj, offset, v)
- return JNIHandles::make_local(env, v);
+ jobject ret = JNIHandles::make_local(env, v);
+#ifndef SERIALGC
+ // We could be accessing the referent field in a reference
+ // object. If G1 is enabled then we need to register non-null
+ // referent with the SATB barrier.
+ if (UseG1GC) {
+ bool needs_barrier = false;
+
+ if (ret != NULL) {
+ if (offset == java_lang_ref_Reference::referent_offset && obj != NULL) {
+ oop o = JNIHandles::resolve(obj);
+ klassOop k = o->klass();
+ if (instanceKlass::cast(k)->reference_type() != REF_NONE) {
+ assert(instanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
+ needs_barrier = true;
+ }
+ }
+ }
+
+ if (needs_barrier) {
+ oop referent = JNIHandles::resolve(ret);
+ G1SATBCardTableModRefBS::enqueue(referent);
+ }
+ }
+#endif // SERIALGC
+ return ret;
UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_SetObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h))