544 |
544 |
545 // Check that the metadata embedded in the nmethod is alive |
545 // Check that the metadata embedded in the nmethod is alive |
546 DEBUG_ONLY(metadata_do(check_class)); |
546 DEBUG_ONLY(metadata_do(check_class)); |
547 } |
547 } |
548 |
548 |
549 // The IsUnloadingStruct represents a tuple comprising a result of |
549 // The _is_unloading_state encodes a tuple comprising the unloading cycle |
550 // IsUnloadingBehaviour::is_unloading() for a given unloading cycle. |
550 // and the result of IsUnloadingBehaviour::is_unloading() fpr that cycle. |
551 struct IsUnloadingStruct { |
551 // This is the bit layout of the _is_unloading_state byte: 00000CCU |
552 unsigned int _is_unloading:1; |
552 // CC refers to the cycle, which has 2 bits, and U refers to the result of |
553 unsigned int _unloading_cycle:2; |
553 // IsUnloadingBehaviour::is_unloading() for that unloading cycle. |
|
554 |
|
555 class IsUnloadingState: public AllStatic { |
|
556 static const uint8_t _is_unloading_mask = 1; |
|
557 static const uint8_t _is_unloading_shift = 0; |
|
558 static const uint8_t _unloading_cycle_mask = 6; |
|
559 static const uint8_t _unloading_cycle_shift = 1; |
|
560 |
|
561 static uint8_t set_is_unloading(uint8_t state, bool value) { |
|
562 state &= ~_is_unloading_mask; |
|
563 if (value) { |
|
564 state |= 1 << _is_unloading_shift; |
|
565 } |
|
566 assert(is_unloading(state) == value, "unexpected unloading cycle overflow"); |
|
567 return state; |
|
568 } |
|
569 |
|
570 static uint8_t set_unloading_cycle(uint8_t state, uint8_t value) { |
|
571 state &= ~_unloading_cycle_mask; |
|
572 state |= value << _unloading_cycle_shift; |
|
573 assert(unloading_cycle(state) == value, "unexpected unloading cycle overflow"); |
|
574 return state; |
|
575 } |
|
576 |
|
577 public: |
|
578 static bool is_unloading(uint8_t state) { return (state & _is_unloading_mask) >> _is_unloading_shift == 1; } |
|
579 static uint8_t unloading_cycle(uint8_t state) { return (state & _unloading_cycle_mask) >> _unloading_cycle_shift; } |
|
580 |
|
581 static uint8_t create(bool is_unloading, uint8_t unloading_cycle) { |
|
582 uint8_t state = 0; |
|
583 state = set_is_unloading(state, is_unloading); |
|
584 state = set_unloading_cycle(state, unloading_cycle); |
|
585 return state; |
|
586 } |
554 }; |
587 }; |
555 |
588 |
556 // The IsUnloadingUnion allows treating the tuple of the IsUnloadingStruct |
|
557 // like a uint8_t, making it possible to read and write the tuple atomically. |
|
558 union IsUnloadingUnion { |
|
559 IsUnloadingStruct _inflated; |
|
560 uint8_t _value; |
|
561 }; |
|
562 |
|
563 bool CompiledMethod::is_unloading() { |
589 bool CompiledMethod::is_unloading() { |
564 IsUnloadingUnion state; |
590 uint8_t state = RawAccess<MO_RELAXED>::load(&_is_unloading_state); |
565 state._value = RawAccess<MO_RELAXED>::load(&_is_unloading_state); |
591 bool state_is_unloading = IsUnloadingState::is_unloading(state); |
566 if (state._inflated._is_unloading == 1) { |
592 uint8_t state_unloading_cycle = IsUnloadingState::unloading_cycle(state); |
|
593 if (state_is_unloading) { |
567 return true; |
594 return true; |
568 } |
595 } |
569 if (state._inflated._unloading_cycle == CodeCache::unloading_cycle()) { |
596 if (state_unloading_cycle == CodeCache::unloading_cycle()) { |
570 return state._inflated._is_unloading == 1; |
597 return false; |
571 } |
598 } |
572 |
599 |
573 // The IsUnloadingBehaviour is responsible for checking if there are any dead |
600 // The IsUnloadingBehaviour is responsible for checking if there are any dead |
574 // oops in the CompiledMethod, by calling oops_do on it. |
601 // oops in the CompiledMethod, by calling oops_do on it. |
575 bool result = IsUnloadingBehaviour::current()->is_unloading(this); |
602 state_unloading_cycle = CodeCache::unloading_cycle(); |
576 |
603 state_is_unloading = IsUnloadingBehaviour::current()->is_unloading(this); |
577 state._inflated._unloading_cycle = CodeCache::unloading_cycle(); |
604 |
578 state._inflated._is_unloading = result ? 1 : 0; |
605 state = IsUnloadingState::create(state_is_unloading, state_unloading_cycle); |
579 |
606 |
580 RawAccess<MO_RELAXED>::store(&_is_unloading_state, state._value); |
607 RawAccess<MO_RELAXED>::store(&_is_unloading_state, state); |
581 |
608 |
582 return result; |
609 return state_is_unloading; |
583 } |
610 } |
584 |
611 |
585 void CompiledMethod::clear_unloading_state() { |
612 void CompiledMethod::clear_unloading_state() { |
586 IsUnloadingUnion state; |
613 uint8_t state = IsUnloadingState::create(false, CodeCache::unloading_cycle()); |
587 state._inflated._unloading_cycle = CodeCache::unloading_cycle(); |
614 RawAccess<MO_RELAXED>::store(&_is_unloading_state, state); |
588 state._inflated._is_unloading = 0; |
|
589 RawAccess<MO_RELAXED>::store(&_is_unloading_state, state._value); |
|
590 } |
615 } |
591 |
616 |
592 // Called to clean up after class unloading for live nmethods and from the sweeper |
617 // Called to clean up after class unloading for live nmethods and from the sweeper |
593 // for all methods. |
618 // for all methods. |
594 void CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { |
619 void CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { |