< prev index next >
src/share/vm/opto/graphKit.cpp
Print this page
rev 8961 : [mq]: diff-shenandoah.patch
*** 39,48 ****
--- 39,49 ----
#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,823 ****
#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();
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;
--- 814,824 ----
#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->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,1170 ****
--- 1152,1178 ----
//-------------------------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,1526 ****
--- 1525,1535 ----
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,1544 ****
--- 1544,1554 ----
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,1578 ****
--- 1579,1589 ----
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,1685 ****
--- 1687,1699 ----
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,2926 ****
--- 2931,2944 ----
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,3007 ****
--- 3016,3029 ----
// 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,3156 ****
--- 3169,3180 ----
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,3629 ****
--- 3644,3657 ----
// 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,4281 ****
--- 4300,4312 ----
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,4296 ****
--- 4318,4330 ----
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,4313 ****
--- 4338,4350 ----
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,4352 ****
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),
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,
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),
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)));
}
--- 4356,4593 ----
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);
!
! // 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);
! // 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);
!
! // 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 >