< prev index next > src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp
Print this page
* questions.
*
*/
+ #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
#include "gc/shenandoah/shenandoahClosures.inline.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahNMethod.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/continuation.hpp"
#include "runtime/safepointVerifiers.hpp"
- ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray<oop*>& oops, bool non_immediate_oops) :
- _nm(nm), _oops(nullptr), _oops_count(0), _unregistered(false), _lock(), _ic_lock() {
+ ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray<oop*>& oops, bool non_immediate_oops, GrowableArray<ShenandoahNMethodBarrier>& barriers) :
+ _nm(nm), _oops(nullptr), _oops_count(0), _barriers(nullptr), _barriers_count(0), _unregistered(false), _lock(), _ic_lock() {
if (!oops.is_empty()) {
_oops_count = oops.length();
_oops = NEW_C_HEAP_ARRAY(oop*, _oops_count, mtGC);
for (int c = 0; c < _oops_count; c++) {
}
}
_has_non_immed_oops = non_immediate_oops;
assert_same_oops();
+
+ if (!barriers.is_empty()) {
+ _barriers_count = barriers.length();
+ _barriers = NEW_C_HEAP_ARRAY(ShenandoahNMethodBarrier, _barriers_count, mtGC);
+ for (int c = 0; c < _barriers_count; c++) {
+ _barriers[c] = barriers.at(c);
+ }
+ }
}
ShenandoahNMethod::~ShenandoahNMethod() {
if (_oops != nullptr) {
FREE_C_HEAP_ARRAY(oop*, _oops);
}
+ if (_barriers != nullptr) {
+ FREE_C_HEAP_ARRAY(ShenandoahNMethodBarrier, _barriers);
+ }
}
void ShenandoahNMethod::update() {
ResourceMark rm;
bool non_immediate_oops = false;
GrowableArray<oop*> oops;
+ GrowableArray<ShenandoahNMethodBarrier> barriers;
- detect_reloc_oops(nm(), oops, non_immediate_oops);
+ parse(nm(), oops, non_immediate_oops, barriers);
if (oops.length() != _oops_count) {
if (_oops != nullptr) {
FREE_C_HEAP_ARRAY(oop*, _oops);
_oops = nullptr;
}
_has_non_immed_oops = non_immediate_oops;
assert_same_oops();
}
- void ShenandoahNMethod::detect_reloc_oops(nmethod* nm, GrowableArray<oop*>& oops, bool& has_non_immed_oops) {
+ void ShenandoahNMethod::parse(nmethod* nm, GrowableArray<oop*>& oops, bool& has_non_immed_oops, GrowableArray<ShenandoahNMethodBarrier>& barriers) {
has_non_immed_oops = false;
- // Find all oops relocations
RelocIterator iter(nm);
while (iter.next()) {
- if (iter.type() != relocInfo::oop_type) {
- // Not an oop
- continue;
- }
-
- oop_Relocation* r = iter.oop_reloc();
- if (!r->oop_is_immediate()) {
- // Non-immediate oop found
- has_non_immed_oops = true;
- continue;
- }
-
- oop value = r->oop_value();
- if (value != nullptr) {
- oop* addr = r->oop_addr();
- shenandoah_assert_correct(addr, value);
- shenandoah_assert_not_in_cset_except(addr, value, ShenandoahHeap::heap()->cancelled_gc());
- shenandoah_assert_not_forwarded(addr, value);
- // Non-null immediate oop found. null oops can safely be
- // ignored since the method will be re-registered if they
- // are later patched to be non-null.
- oops.push(addr);
+ switch (iter.type()) {
+ case relocInfo::oop_type: {
+ oop_Relocation* r = iter.oop_reloc();
+ if (!r->oop_is_immediate()) {
+ // Non-immediate oop found
+ has_non_immed_oops = true;
+ break;
+ }
+
+ oop value = r->oop_value();
+ if (value != nullptr) {
+ oop* addr = r->oop_addr();
+ shenandoah_assert_correct(addr, value);
+ shenandoah_assert_not_in_cset_except(addr, value, ShenandoahHeap::heap()->cancelled_gc());
+ shenandoah_assert_not_forwarded(addr, value);
+ // Non-null immediate oop found. null oops can safely be
+ // ignored since the method will be re-registered if they
+ // are later patched to be non-null.
+ oops.push(addr);
+ }
+ break;
+ }
+ #ifdef COMPILER2
+ case relocInfo::barrier_type: {
+ assert(ShenandoahGCStateCheckHotpatch, "Who emits these?");
+ barrier_Relocation* r = iter.barrier_reloc();
+
+ ShenandoahNMethodBarrier b;
+ b._pc = r->addr();
+ b._stub_addr = ShenandoahBarrierSetAssembler::parse_stub_address(b._pc);
+ // TODO: Can technically figure out which GC state we care about in this reloc.
+ // b._gc_state_fast_bit = r->format();
+ barriers.push(b);
+ break;
+ }
+ #endif
+ default:
+ // We do not care about other relocations.
+ break;
}
}
}
ShenandoahNMethod* ShenandoahNMethod::for_nmethod(nmethod* nm) {
ResourceMark rm;
bool non_immediate_oops = false;
GrowableArray<oop*> oops;
+ GrowableArray<ShenandoahNMethodBarrier> barriers;
- detect_reloc_oops(nm, oops, non_immediate_oops);
- return new ShenandoahNMethod(nm, oops, non_immediate_oops);
+ parse(nm, oops, non_immediate_oops, barriers);
+ return new ShenandoahNMethod(nm, oops, non_immediate_oops, barriers);
}
void ShenandoahNMethod::heal_nmethod(nmethod* nm) {
ShenandoahNMethod* data = gc_data(nm);
assert(data != nullptr, "Sanity");
// In this case, concurrent root phase is skipped and degenerated GC should be
// followed, where nmethods are disarmed.
}
}
+ void ShenandoahNMethod::update_barriers() {
+ #ifdef COMPILER2
+ if (!ShenandoahGCStateCheckHotpatch) {
+ return;
+ }
+
+ ShenandoahHeap* heap = ShenandoahHeap::heap();
+
+ for (int c = 0; c < _barriers_count; c++) {
+ address pc = _barriers[c]._pc;
+ address stub_addr = _barriers[c]._stub_addr;
+ if (heap->is_idle()) {
+ ShenandoahBarrierSetAssembler::patch_branch_to_nop(pc);
+ } else {
+ ShenandoahBarrierSetAssembler::patch_nop_to_branch(pc, stub_addr);
+ }
+ }
+ #endif
+ }
+
#ifdef ASSERT
void ShenandoahNMethod::assert_correct() {
ShenandoahHeap* heap = ShenandoahHeap::heap();
for (int c = 0; c < _oops_count; c++) {
oop *loc = _oops[c];
debug_stream.print_cr("recorded oops: %d", _oops_count);
for (int i = 0; i < _oops_count; i++) {
debug_stream.print_cr("-> " PTR_FORMAT, p2i(_oops[i]));
}
GrowableArray<oop*> check;
+ GrowableArray<ShenandoahNMethodBarrier> barriers;
bool non_immed;
- detect_reloc_oops(nm(), check, non_immed);
+ parse(nm(), check, non_immed, barriers);
debug_stream.print_cr("check oops: %d", check.length());
for (int i = 0; i < check.length(); i++) {
debug_stream.print_cr("-> " PTR_FORMAT, p2i(check.at(i)));
}
fatal("Must match #detected: %d, #recorded: %d, #total: %d, begin: " PTR_FORMAT ", end: " PTR_FORMAT "\n%s",
assert(nm == data->nm(), "Must be same nmethod");
// Prevent updating a nmethod while concurrent iteration is in progress.
wait_until_concurrent_iteration_done();
ShenandoahNMethodLocker data_locker(data->lock());
data->update();
+ data->update_barriers();
} else {
// For a new nmethod, we can safely append it to the list, because
// concurrent iteration will not touch it.
data = ShenandoahNMethod::for_nmethod(nm);
assert(data != nullptr, "Sanity");
ShenandoahNMethod::attach_gc_data(nm, data);
ShenandoahLocker locker(&_lock);
log_register_nmethod(nm);
append(data);
+ data->update_barriers();
}
// Disarm new nmethod
ShenandoahNMethod::disarm_nmethod(nm);
}
< prev index next >