< prev index next > src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp
Print this page
* questions.
*
*/
#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() {
!
- 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++) {
- _oops[c] = oops.at(c);
- }
- }
- _has_non_immed_oops = non_immediate_oops;
-
- assert_same_oops();
}
ShenandoahNMethod::~ShenandoahNMethod() {
if (_oops != nullptr) {
FREE_C_HEAP_ARRAY(_oops);
}
}
void ShenandoahNMethod::update() {
ResourceMark rm;
bool non_immediate_oops = false;
GrowableArray<oop*> oops;
! detect_reloc_oops(nm(), oops, non_immediate_oops);
! if (oops.length() != _oops_count) {
if (_oops != nullptr) {
FREE_C_HEAP_ARRAY(_oops);
- _oops = nullptr;
}
! _oops_count = oops.length();
! if (_oops_count > 0) {
! _oops = NEW_C_HEAP_ARRAY(oop*, _oops_count, mtGC);
}
}
!
! for (int index = 0; index < _oops_count; index ++) {
- _oops[index] = oops.at(index);
}
- _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) {
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);
}
}
}
ShenandoahNMethod* ShenandoahNMethod::for_nmethod(nmethod* nm) {
! ResourceMark rm;
- bool non_immediate_oops = false;
- GrowableArray<oop*> oops;
-
- detect_reloc_oops(nm, oops, non_immediate_oops);
- return new ShenandoahNMethod(nm, oops, non_immediate_oops);
}
void ShenandoahNMethod::heal_nmethod(nmethod* nm) {
ShenandoahNMethod* data = gc_data(nm);
assert(data != nullptr, "Sanity");
* 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) :
! _nm(nm), _oops(nullptr), _oops_count(0), _barriers(nullptr), _barriers_count(0), _unregistered(false), _lock(), _ic_lock() {
! init_from(nm);
}
ShenandoahNMethod::~ShenandoahNMethod() {
if (_oops != nullptr) {
FREE_C_HEAP_ARRAY(_oops);
}
+ if (_barriers != nullptr) {
+ FREE_C_HEAP_ARRAY(_barriers);
+ }
}
void ShenandoahNMethod::update() {
+ init_from(nm());
+ }
+
+ void ShenandoahNMethod::init_from(nmethod* nm) {
ResourceMark rm;
bool non_immediate_oops = false;
GrowableArray<oop*> oops;
+ GrowableArray<ShenandoahNMethodBarrier> barriers;
! parse(nm, oops, non_immediate_oops, barriers);
!
+ if (_oops_count != oops.length()) {
+ _oops_count = oops.length();
if (_oops != nullptr) {
FREE_C_HEAP_ARRAY(_oops);
}
+ _oops = NEW_C_HEAP_ARRAY(oop*, _oops_count, mtGC);
+ }
+ for (int c = 0; c < _oops_count; c++) {
+ _oops[c] = oops.at(c);
+ }
+ assert_same_oops();
! if (_barriers_count != barriers.length()) {
! _barriers_count = barriers.length();
! if (_barriers != nullptr) {
+ FREE_C_HEAP_ARRAY(_barriers);
}
+ _barriers = NEW_C_HEAP_ARRAY(ShenandoahNMethodBarrier, _barriers_count, mtGC);
}
! for (int c = 0; c < _barriers_count; c++) {
! _barriers[c] = barriers.at(c);
}
! _has_non_immed_oops = non_immediate_oops;
}
! void ShenandoahNMethod::parse(nmethod* nm, GrowableArray<oop*>& oops, bool& has_non_immed_oops, GrowableArray<ShenandoahNMethodBarrier>& barriers) {
has_non_immed_oops = false;
! address code_begin = nm->code_begin();
RelocIterator iter(nm);
while (iter.next()) {
! 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::patchable_barrier_type: {
+ patchable_barrier_Relocation* r = iter.patchable_barrier_reloc();
+
+ ShenandoahNMethodBarrier b;
+ b._rel_pc = pointer_delta(r->addr(), code_begin, 1);
+ b._rel_target = r->target_offset();
+ b._metadata = r->metadata();
+ barriers.push(b);
+ break;
+ }
+ #endif
+ default:
+ // We do not care about other relocations.
+ break;
}
}
}
ShenandoahNMethod* ShenandoahNMethod::for_nmethod(nmethod* nm) {
! return new ShenandoahNMethod(nm);
}
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.
}
}
+ bool ShenandoahNMethod::update_barriers(nmethod* nm) {
+ bool changed = false;
+ #ifdef COMPILER2
+ ShenandoahNMethod* data = gc_data(nm);
+ assert(data != nullptr, "Sanity");
+ assert(data->lock()->owned_by_self(), "Must hold the lock");
+
+ char gc_state = ShenandoahHeap::heap()->gc_state();
+ address code_begin = nm->code_begin();
+ for (int c = 0; c < data->_barriers_count; c++) {
+ address pc = code_begin + data->_barriers[c]._rel_pc;
+ address target = pc + data->_barriers[c]._rel_target;
+ char trigger_state = decode_reloc_gc_state(data->_barriers[c]._metadata);
+ bool inverted = decode_reloc_inverted(data->_barriers[c]._metadata);
+ bool active = ((gc_state & trigger_state) != 0) ^ inverted;
+ if (active) {
+ changed |= ShenandoahBarrierSetAssembler::patch_nop_to_branch(pc, target);
+ } else {
+ changed |= ShenandoahBarrierSetAssembler::patch_branch_to_nop(pc);
+ }
+ }
+ #endif
+ return changed;
+ }
+
#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;
bool non_immed;
! detect_reloc_oops(nm(), check, non_immed);
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",
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;
! 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();
+ ShenandoahNMethod::update_barriers(nm);
} 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);
+ ShenandoahNMethodLocker data_locker(data->lock());
+ ShenandoahNMethod::update_barriers(nm);
}
// Disarm new nmethod
ShenandoahNMethod::disarm_nmethod(nm);
}
< prev index next >