--- a/hotspot/src/share/vm/opto/library_call.cpp Tue Apr 05 19:14:03 2011 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp Thu Apr 07 09:53:20 2011 -0700
@@ -165,6 +165,10 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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;
+}
+