--- a/src/hotspot/share/code/nmethod.cpp Thu Nov 22 09:44:02 2018 +0100
+++ b/src/hotspot/share/code/nmethod.cpp Thu Nov 22 09:46:24 2018 +0100
@@ -565,6 +565,7 @@
ByteSize basic_lock_sp_offset,
OopMapSet* oop_maps )
: CompiledMethod(method, "native nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false),
+ _is_unloading_state(0),
_native_receiver_sp_offset(basic_lock_owner_sp_offset),
_native_basic_lock_sp_offset(basic_lock_sp_offset)
{
@@ -609,6 +610,7 @@
code_buffer->copy_code_and_locs_to(this);
code_buffer->copy_values_to(this);
+ clear_unloading_state();
if (ScavengeRootsInCode) {
Universe::heap()->register_nmethod(this);
}
@@ -672,6 +674,7 @@
#endif
)
: CompiledMethod(method, "nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false),
+ _is_unloading_state(0),
_native_receiver_sp_offset(in_ByteSize(-1)),
_native_basic_lock_sp_offset(in_ByteSize(-1))
{
@@ -1505,6 +1508,74 @@
if (_method != NULL) f(_method);
}
+// The _is_unloading_state encodes a tuple comprising the unloading cycle
+// and the result of IsUnloadingBehaviour::is_unloading() fpr that cycle.
+// This is the bit layout of the _is_unloading_state byte: 00000CCU
+// CC refers to the cycle, which has 2 bits, and U refers to the result of
+// IsUnloadingBehaviour::is_unloading() for that unloading cycle.
+
+class IsUnloadingState: public AllStatic {
+ static const uint8_t _is_unloading_mask = 1;
+ static const uint8_t _is_unloading_shift = 0;
+ static const uint8_t _unloading_cycle_mask = 6;
+ static const uint8_t _unloading_cycle_shift = 1;
+
+ static uint8_t set_is_unloading(uint8_t state, bool value) {
+ state &= ~_is_unloading_mask;
+ if (value) {
+ state |= 1 << _is_unloading_shift;
+ }
+ assert(is_unloading(state) == value, "unexpected unloading cycle overflow");
+ return state;
+ }
+
+ static uint8_t set_unloading_cycle(uint8_t state, uint8_t value) {
+ state &= ~_unloading_cycle_mask;
+ state |= value << _unloading_cycle_shift;
+ assert(unloading_cycle(state) == value, "unexpected unloading cycle overflow");
+ return state;
+ }
+
+public:
+ static bool is_unloading(uint8_t state) { return (state & _is_unloading_mask) >> _is_unloading_shift == 1; }
+ static uint8_t unloading_cycle(uint8_t state) { return (state & _unloading_cycle_mask) >> _unloading_cycle_shift; }
+
+ static uint8_t create(bool is_unloading, uint8_t unloading_cycle) {
+ uint8_t state = 0;
+ state = set_is_unloading(state, is_unloading);
+ state = set_unloading_cycle(state, unloading_cycle);
+ return state;
+ }
+};
+
+bool nmethod::is_unloading() {
+ uint8_t state = RawAccess<MO_RELAXED>::load(&_is_unloading_state);
+ bool state_is_unloading = IsUnloadingState::is_unloading(state);
+ uint8_t state_unloading_cycle = IsUnloadingState::unloading_cycle(state);
+ if (state_is_unloading) {
+ return true;
+ }
+ if (state_unloading_cycle == CodeCache::unloading_cycle()) {
+ return false;
+ }
+
+ // The IsUnloadingBehaviour is responsible for checking if there are any dead
+ // oops in the CompiledMethod, by calling oops_do on it.
+ state_unloading_cycle = CodeCache::unloading_cycle();
+ state_is_unloading = IsUnloadingBehaviour::current()->is_unloading(this);
+
+ state = IsUnloadingState::create(state_is_unloading, state_unloading_cycle);
+
+ RawAccess<MO_RELAXED>::store(&_is_unloading_state, state);
+
+ return state_is_unloading;
+}
+
+void nmethod::clear_unloading_state() {
+ uint8_t state = IsUnloadingState::create(false, CodeCache::unloading_cycle());
+ RawAccess<MO_RELAXED>::store(&_is_unloading_state, state);
+}
+
// This is called at the end of the strong tracing/marking phase of a
// GC to unload an nmethod if it contains otherwise unreachable