< prev index next >
src/share/vm/opto/graphKit.cpp
Print this page
@@ -39,10 +39,11 @@
#include "opto/machnode.hpp"
#include "opto/opaquenode.hpp"
#include "opto/parse.hpp"
#include "opto/rootnode.hpp"
#include "opto/runtime.hpp"
+#include "opto/shenandoahSupport.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/sharedRuntime.hpp"
//----------------------------GraphKit-----------------------------------------
// Main utility constructor.
@@ -813,11 +814,11 @@
#endif //ASSERT
// Helper function for enforcing certain bytecodes to reexecute if
// deoptimization happens
static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarray) {
- ciMethod* cur_method = jvms->method();
+ ciMethod* cur_method = jvms->has_method() ? jvms->method() : NULL;
int cur_bci = jvms->bci();
if (cur_method != NULL && cur_bci != InvocationEntryBci) {
Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci);
return Interpreter::bytecode_should_reexecute(code) ||
is_anewarray && code == Bytecodes::_multianewarray;
@@ -1151,20 +1152,27 @@
//-------------------------load_object_klass-----------------------------------
Node* GraphKit::load_object_klass(Node* obj) {
// Special-case a fresh allocation to avoid building nodes:
Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
if (akls != NULL) return akls;
+ if (ShenandoahVerifyReadsToFromSpace) {
+ obj = shenandoah_read_barrier(obj);
+ }
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS));
}
//-------------------------load_array_length-----------------------------------
Node* GraphKit::load_array_length(Node* array) {
// Special-case a fresh allocation to avoid building nodes:
AllocateArrayNode* alloc = AllocateArrayNode::Ideal_array_allocation(array, &_gvn);
Node *alen;
if (alloc == NULL) {
+ if (ShenandoahVerifyReadsToFromSpace) {
+ array = shenandoah_read_barrier(array);
+ }
+
Node *r_adr = basic_plus_adr(array, arrayOopDesc::length_offset_in_bytes());
alen = _gvn.transform( new LoadRangeNode(0, immutable_memory(), r_adr, TypeInt::POS));
} else {
alen = alloc->Ideal_length();
Node* ccast = alloc->make_ideal_length(_gvn.type(array)->is_oopptr(), &_gvn);
@@ -1517,10 +1525,11 @@
BarrierSet* bs = Universe::heap()->barrier_set();
set_control(ctl);
switch (bs->kind()) {
case BarrierSet::G1SATBCTLogging:
+ case BarrierSet::ShenandoahBarrierSet:
g1_write_barrier_pre(do_load, obj, adr, adr_idx, val, val_type, pre_val, bt);
break;
case BarrierSet::CardTableForRS:
case BarrierSet::CardTableExtension:
@@ -1535,10 +1544,11 @@
bool GraphKit::can_move_pre_barrier() const {
BarrierSet* bs = Universe::heap()->barrier_set();
switch (bs->kind()) {
case BarrierSet::G1SATBCTLogging:
+ case BarrierSet::ShenandoahBarrierSet:
return true; // Can move it if no safepoint
case BarrierSet::CardTableForRS:
case BarrierSet::CardTableExtension:
case BarrierSet::ModRef:
@@ -1569,10 +1579,11 @@
case BarrierSet::CardTableExtension:
write_barrier_post(store, obj, adr, adr_idx, val, use_precise);
break;
case BarrierSet::ModRef:
+ case BarrierSet::ShenandoahBarrierSet:
break;
default :
ShouldNotReachHere();
@@ -1676,10 +1687,13 @@
void GraphKit::set_arguments_for_java_call(CallJavaNode* call) {
// Add the call arguments:
uint nargs = call->method()->arg_size();
for (uint i = 0; i < nargs; i++) {
Node* arg = argument(i);
+ if (ShenandoahVerifyReadsToFromSpace && call->is_CallDynamicJava() && i == 0) {
+ arg = shenandoah_read_barrier(arg);
+ }
call->init_req(i + TypeFunc::Parms, arg);
}
}
//---------------------------set_edges_for_java_call---------------------------
@@ -2917,10 +2931,14 @@
not_null_obj = cast_obj;
}
}
}
+ if (ShenandoahVerifyReadsToFromSpace) {
+ not_null_obj = shenandoah_read_barrier(not_null_obj);
+ }
+
// Load the object's klass
Node* obj_klass = load_object_klass(not_null_obj);
// Generate the subtype check
Node* not_subtype_ctrl = gen_subtype_check(obj_klass, superklass);
@@ -2998,10 +3016,14 @@
// Null check; get casted pointer; set region slot 3
Node* null_ctl = top();
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
+ if (ShenandoahVerifyReadsToFromSpace) {
+ not_null_obj = shenandoah_read_barrier(not_null_obj);
+ }
+
// If not_null_obj is dead, only null-path is taken
if (stopped()) { // Doing instance-of on a NULL?
set_control(null_ctl);
return null();
}
@@ -3147,10 +3169,12 @@
if (stopped()) // Dead monitor?
return NULL;
assert(dead_locals_are_killed(), "should kill locals before sync. point");
+ obj = shenandoah_write_barrier(obj);
+
// Box the stack location
Node* box = _gvn.transform(new BoxLockNode(next_monitor()));
Node* mem = reset_memory();
FastLockNode * flock = _gvn.transform(new FastLockNode(0, obj, box) )->as_FastLock();
@@ -3620,10 +3644,14 @@
// Given an oop pointer or raw pointer, see if it feeds from an AllocateNode.
AllocateNode* AllocateNode::Ideal_allocation(Node* ptr, PhaseTransform* phase) {
if (ptr == NULL) { // reduce dumb test in callers
return NULL;
}
+
+ // Attempt to see through Shenandoah barriers.
+ ptr = ShenandoahBarrierNode::skip_through_barrier(ptr);
+
if (ptr->is_CheckCastPP()) { // strip only one raw-to-oop cast
ptr = ptr->in(1);
if (ptr == NULL) return NULL;
}
// Return NULL for allocations with several casts:
@@ -4272,10 +4300,13 @@
int offset_offset = java_lang_String::offset_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* offset_field_type = string_type->add_offset(offset_offset);
int offset_field_idx = C->get_alias_index(offset_field_type);
+
+ str = shenandoah_read_barrier(str);
+
return make_load(ctrl,
basic_plus_adr(str, str, offset_offset),
TypeInt::INT, T_INT, offset_field_idx, MemNode::unordered);
} else {
return intcon(0);
@@ -4287,10 +4318,13 @@
int count_offset = java_lang_String::count_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* count_field_type = string_type->add_offset(count_offset);
int count_field_idx = C->get_alias_index(count_field_type);
+
+ str = shenandoah_read_barrier(str);
+
return make_load(ctrl,
basic_plus_adr(str, str, count_offset),
TypeInt::INT, T_INT, count_field_idx, MemNode::unordered);
} else {
return load_array_length(load_String_value(ctrl, str));
@@ -4304,10 +4338,13 @@
const TypePtr* value_field_type = string_type->add_offset(value_offset);
const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull,
TypeAry::make(TypeInt::CHAR,TypeInt::POS),
ciTypeArrayKlass::make(T_CHAR), true, 0);
int value_field_idx = C->get_alias_index(value_field_type);
+
+ str = shenandoah_read_barrier(str);
+
Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset),
value_type, T_OBJECT, value_field_idx, MemNode::unordered);
// String.value field is known to be @Stable.
if (UseImplicitStableValues) {
load = cast_array_to_stable(load, value_type);
@@ -4319,34 +4356,238 @@
int offset_offset = java_lang_String::offset_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* offset_field_type = string_type->add_offset(offset_offset);
int offset_field_idx = C->get_alias_index(offset_field_type);
- store_to_memory(ctrl, basic_plus_adr(str, offset_offset),
+
+ // TODO: Use incoming ctrl.
+ str = shenandoah_write_barrier(str);
+
+ store_to_memory(UseShenandoahGC ? control() : ctrl, basic_plus_adr(str, offset_offset),
value, T_INT, offset_field_idx, MemNode::unordered);
}
void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) {
int value_offset = java_lang_String::value_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* value_field_type = string_type->add_offset(value_offset);
- store_oop_to_object(ctrl, str, basic_plus_adr(str, value_offset), value_field_type,
+ // TODO: Use incoming ctrl.
+ str = shenandoah_write_barrier(str);
+ value = shenandoah_read_barrier_nomem(value);
+
+ store_oop_to_object(UseShenandoahGC ? control() : ctrl, str, basic_plus_adr(str, value_offset), value_field_type,
value, TypeAryPtr::CHARS, T_OBJECT, MemNode::unordered);
}
void GraphKit::store_String_length(Node* ctrl, Node* str, Node* value) {
int count_offset = java_lang_String::count_offset_in_bytes();
const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
false, NULL, 0);
const TypePtr* count_field_type = string_type->add_offset(count_offset);
int count_field_idx = C->get_alias_index(count_field_type);
- store_to_memory(ctrl, basic_plus_adr(str, count_offset),
+
+ // TODO: Use incoming ctrl.
+ str = shenandoah_write_barrier(str);
+
+ store_to_memory(UseShenandoahGC ? control() : ctrl, basic_plus_adr(str, count_offset),
value, T_INT, count_field_idx, MemNode::unordered);
}
Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) {
// Reify the property as a CastPP node in Ideal graph to comply with monotonicity
// assumption of CCP analysis.
return _gvn.transform(new CastPPNode(ary, ary_type->cast_to_stable(true)));
}
+
+Node* GraphKit::shenandoah_read_barrier(Node* obj) {
+ return shenandoah_read_barrier_impl(obj, false, true);
+}
+
+Node* GraphKit::shenandoah_read_barrier_nomem(Node* obj) {
+ return shenandoah_read_barrier_impl(obj, false, false);
+}
+
+Node* GraphKit::shenandoah_read_barrier_impl(Node* obj, bool use_ctrl, bool use_mem) {
+
+ if (UseShenandoahGC && ShenandoahReadBarrier) {
+ const Type* obj_type = obj->bottom_type();
+ if (obj_type->higher_equal(TypePtr::NULL_PTR)) {
+ // tty->print_cr("killed barrier for NULL object");
+ return obj;
+ }
+ const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8);
+ Node* mem = use_mem ? memory(adr_type) : immutable_memory();
+
+ if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, mem)) {
+ // We know it is null, no barrier needed.
+ return obj;
+ }
+
+
+ if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) {
+
+ // We don't know if it's null or not. Need null-check.
+ enum { _not_null_path = 1, _null_path, PATH_LIMIT };
+ RegionNode* region = new RegionNode(PATH_LIMIT);
+ Node* phi = new PhiNode(region, obj_type);
+ Node* null_ctrl = top();
+ Node* not_null_obj = null_check_oop(obj, &null_ctrl);
+
+ region->init_req(_null_path, null_ctrl);
+ phi ->init_req(_null_path, obj);
+
+ Node* ctrl = use_ctrl ? control() : NULL;
+ ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, not_null_obj);
+ Node* n = _gvn.transform(rb);
+
+ region->init_req(_not_null_path, control());
+ phi ->init_req(_not_null_path, n);
+
+ set_control(_gvn.transform(region));
+ record_for_igvn(region);
+ return _gvn.transform(phi);
+
+ } else {
+ // We know it is not null. Simple barrier is sufficient.
+ Node* ctrl = use_ctrl ? control() : NULL;
+ ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj);
+ Node* n = _gvn.transform(rb);
+ record_for_igvn(n);
+ return n;
+ }
+
+ } else {
+ return obj;
+ }
+}
+
+Node* GraphKit::shenandoah_write_barrier(Node* obj) {
+
+ if (UseShenandoahGC && ShenandoahWriteBarrier) {
+
+ if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, NULL)) {
+ return obj;
+ }
+ const Type* obj_type = obj->bottom_type();
+ const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8);
+ // tty->print_cr("memory at:");
+ // adr_type->dump();
+ // tty->print_cr("\n");
+ // memory(adr_type)->dump();
+ if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) {
+ // We don't know if it's null or not. Need null-check.
+ enum { _not_null_path = 1, _null_path, PATH_LIMIT };
+ RegionNode* region = new RegionNode(PATH_LIMIT);
+ Node* phi = new PhiNode(region, obj_type);
+ Node* memphi = PhiNode::make(region, memory(adr_type), Type::MEMORY, C->alias_type(adr_type)->adr_type());
+
+ Node* prev_mem = memory(adr_type);
+ Node* null_ctrl = top();
+ Node* not_null_obj = null_check_oop(obj, &null_ctrl);
+
+ region->init_req(_null_path, null_ctrl);
+ phi ->init_req(_null_path, null());
+ memphi->init_req(_null_path, prev_mem);
+
+ ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), not_null_obj);
+ Node* n = _gvn.transform(wb);
+ if (n == wb) { // New barrier needs memory projection.
+ Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(n));
+ set_memory(proj, adr_type);
+ }
+
+ region->init_req(_not_null_path, control());
+ phi ->init_req(_not_null_path, n);
+ memphi->init_req(_not_null_path, memory(adr_type));
+
+ set_control(_gvn.transform(region));
+ record_for_igvn(region);
+ set_memory(_gvn.transform(memphi), adr_type);
+
+ Node* res_val = _gvn.transform(phi);
+ // replace_in_map(obj, res_val);
+ return res_val;
+ } else {
+ // We know it is not null. Simple barrier is sufficient.
+ ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), obj);
+ Node* n = _gvn.transform(wb);
+ if (n == wb) {
+ Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(wb));
+ set_memory(proj, adr_type);
+ }
+ // replace_in_map(obj, n);
+ record_for_igvn(n);
+ return n;
+ }
+
+ } else {
+ return obj;
+ }
+}
+
+void GraphKit::shenandoah_acmp_barrier(Node*& a, Node*& b) {
+ if (UseShenandoahGC) {
+ const Type* a_type = a->bottom_type();
+ const Type* b_type = b->bottom_type();
+ if (a_type->higher_equal(TypePtr::NULL_PTR) || b_type->higher_equal(TypePtr::NULL_PTR)) {
+ // We know one arg is gonna be null. No need for barriers.
+ // tty->print_cr("eliminate acmp barrier on null");
+ return;
+ }
+ /*
+ if ((!a_type->isa_oopptr()) || (!b_type->isa_oopptr())) {
+ a_type->dump();
+ b_type->dump();
+ }
+ */
+ if (a_type->is_oopptr()->const_oop() != NULL && b_type->is_oopptr()->const_oop() != NULL ) {
+ // We know one arg is inlined constant. No need for barriers.
+ // tty->print_cr("eliminate acmp barrier on constant");
+ return;
+ }
+ if (a->Opcode() == Op_ShenandoahWriteBarrier && b->Opcode() == Op_ShenandoahWriteBarrier) {
+ // We know one arg is already write-barrier'd. No need for barriers.
+ // tty->print_cr("eliminate acmp barrier on write barrier");
+ return;
+ }
+ if (AllocateNode::Ideal_allocation(a, &_gvn) != NULL || AllocateNode::Ideal_allocation(b, &_gvn) != NULL) {
+ // We know one arg is already in to-space. No need for barriers.
+ // tty->print_cr("eliminate acmp barrier on new obj");
+ return;
+ }
+
+ enum { _equal = 1, _not_equal, PATH_LIMIT };
+ RegionNode* region = new RegionNode(PATH_LIMIT);
+ PhiNode* phiA = PhiNode::make(region, a);
+ PhiNode* phiB = PhiNode::make(region, b);
+
+ Node* cmp = _gvn.transform(new CmpPNode(b, a));
+ Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+
+ // TODO: Use profiling data.
+ IfNode* iff = create_and_map_if(control(), tst, PROB_FAIR, COUNT_UNKNOWN);
+ Node* iftrue = _gvn.transform(new IfTrueNode(iff));
+ Node* iffalse = _gvn.transform(new IfFalseNode(iff));
+
+ // Equal path: Use original values.
+ region->init_req(_equal, iftrue);
+ phiA->init_req(_equal, a);
+ phiB->init_req(_equal, b);
+
+ // Unequal path: retry after read barriers.
+ set_control(iffalse);
+ a = shenandoah_read_barrier_impl(a, true, true);
+ b = shenandoah_read_barrier_impl(b, true, true);
+
+ region->init_req(_not_equal, control());
+ phiA->init_req(_not_equal, a);
+ phiB->init_req(_not_equal, b);
+
+ set_control(_gvn.transform(region));
+ record_for_igvn(region);
+
+ a = _gvn.transform(phiA);
+ b = _gvn.transform(phiB);
+ }
+}
< prev index next >