Skip to content

Commit 161f5d0

Browse files
committed
[simple] Use bit-magic to implement RawMarkState::resolve
This is pretty darn cool :)
1 parent 0680201 commit 161f5d0

File tree

1 file changed

+48
-18
lines changed

1 file changed

+48
-18
lines changed

libs/simple/src/lib.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -881,27 +881,45 @@ enum RawMarkState {
881881
/// Normally this marks the white state
882882
///
883883
/// If we're inverted, this marks black
884-
Red,
884+
Red = 0,
885885
/// This always marks the grey state
886886
///
887887
/// Inverting the mark bit doesn't affect the
888888
/// grey state
889-
Grey,
889+
Grey = 3,
890890
/// Normally this marks the blue state
891891
///
892892
/// If we're inverted, this marks white
893-
Blue
893+
Blue = 1
894894
}
895895
impl RawMarkState {
896896
#[inline]
897897
fn resolve(self, inverted_mark: bool) -> MarkState {
898-
match (self, inverted_mark) {
899-
(RawMarkState::Red, false) => MarkState::White,
900-
(RawMarkState::Red, true) => MarkState::Black,
901-
(RawMarkState::Grey, _) => MarkState::Grey,
902-
(RawMarkState::Blue, false) => MarkState::Black,
903-
(RawMarkState::Blue, true) => MarkState::White
898+
let expected: MarkState;
899+
#[cfg(debug_assertions)] {
900+
expected = match (self, inverted_mark) {
901+
(RawMarkState::Red, false) => MarkState::White,
902+
(RawMarkState::Red, true) => MarkState::Black,
903+
(RawMarkState::Grey, _) => MarkState::Grey,
904+
(RawMarkState::Blue, false) => MarkState::Black,
905+
(RawMarkState::Blue, true) => MarkState::White
906+
};
907+
}
908+
/*
909+
* Bit magic works as expected (both ways):
910+
* (self as u8) ^ (inverted_mark as u8) => (res_bits as MarkState)
911+
* (Red => 0u8) ^ (false as 0u8) => (0u8 as White)
912+
* (Red => 0u8) ^ (true as 1u8) => (1u8 as Black)
913+
* (Grey => 3u8) ^ (false as 0u8) => (3u8 as Grey)
914+
* (Grey => 3u8) ^ (true as 1u8) => (3u8 as Grey)
915+
* (Blue => 1u8) ^ (false as 0u8) => (1u8 as Black)
916+
* (Blue => 1u8) ^ (true as 1u8) => (0u8 as White)
917+
*/
918+
let bits = (self as u8) ^ (inverted_mark as u8);
919+
#[cfg(debug_assertions)] {
920+
debug_assert_eq!(expected as u8, bits);
904921
}
922+
unsafe { std::mem::transmute::<u8, MarkState>(bits) }
905923
}
906924
}
907925

@@ -915,25 +933,37 @@ enum MarkState {
915933
///
916934
/// Once all the objects have been marked,
917935
/// all remaining white objects will be freed.
918-
White,
936+
White = 0,
919937
/// The object is in the gray set and needs to be traversed to look for reachable memory
920938
///
921939
/// After being scanned this object will end up in the black set.
922-
Grey,
940+
Grey = 3,
923941
/// The object is in the black set and is reachable from the roots.
924942
///
925943
/// This object cannot be freed.
926-
Black
944+
Black = 1
927945
}
928946
impl MarkState {
929947
#[inline]
930948
fn to_raw(self, inverted_mark: bool) -> RawMarkState {
931-
match (self, inverted_mark) {
932-
(MarkState::White, false) => RawMarkState::Red,
933-
(MarkState::White, true) => RawMarkState::Blue,
934-
(MarkState::Grey, _) => RawMarkState::Grey,
935-
(MarkState::Black, false) => RawMarkState::Blue,
936-
(MarkState::Black, true) => RawMarkState::Red,
949+
let expected: RawMarkState;
950+
#[cfg(debug_assertions)] {
951+
expected = match (self, inverted_mark) {
952+
(MarkState::White, false) => RawMarkState::Red,
953+
(MarkState::White, true) => RawMarkState::Blue,
954+
(MarkState::Grey, _) => RawMarkState::Grey,
955+
(MarkState::Black, false) => RawMarkState::Blue,
956+
(MarkState::Black, true) => RawMarkState::Red,
957+
};
958+
}
959+
/*
960+
* Bit magic is reverse of `RawMarkState::resolved`
961+
* The justification there works two ways
962+
*/
963+
let bits = (self as u8) ^ (inverted_mark as u8);
964+
#[cfg(debug_assertions)] {
965+
debug_assert_eq!(expected as u8, bits);
937966
}
967+
unsafe { std::mem::transmute::<u8, RawMarkState>(bits) }
938968
}
939969
}

0 commit comments

Comments
 (0)