1use atomic::Ordering;
4use std::fmt;
5use std::sync::atomic::AtomicU8;
6
7use crate::util::constants::{BITS_IN_BYTE, LOG_BITS_IN_BYTE};
8use crate::util::metadata::metadata_val_traits::*;
9use crate::util::Address;
10use num_traits::FromPrimitive;
11
12const LOG_BITS_IN_U16: usize = 4;
13const BITS_IN_U16: usize = 1 << LOG_BITS_IN_U16;
14const LOG_BITS_IN_U32: usize = 5;
15const BITS_IN_U32: usize = 1 << LOG_BITS_IN_U32;
16const LOG_BITS_IN_U64: usize = 6;
17const BITS_IN_U64: usize = 1 << LOG_BITS_IN_U64;
18
19#[derive(Clone, Copy, PartialEq, Eq, Hash)]
24pub struct HeaderMetadataSpec {
25 pub bit_offset: isize,
32 pub num_of_bits: usize,
40}
41
42impl HeaderMetadataSpec {
43 #[cfg(debug_assertions)]
49 fn assert_mask<T: MetadataValue>(&self, mask: Option<T>) {
50 debug_assert!(mask.is_none() || self.num_of_bits >= 8, "optional_mask is only supported for 8X-bits in-header metadata. Problematic MetadataSpec: ({:?})", self);
51 }
52
53 #[cfg(debug_assertions)]
55 fn assert_spec<T: MetadataValue>(&self) {
56 if self.num_of_bits == 0 {
57 panic!("Metadata of 0 bits is not allowed.");
58 } else if self.num_of_bits < 8 {
59 debug_assert!(
60 (self.bit_offset >> LOG_BITS_IN_BYTE)
61 == ((self.bit_offset + self.num_of_bits as isize - 1) >> LOG_BITS_IN_BYTE),
62 "Metadata << 8-bits: ({:?}) stretches over two bytes!",
63 self
64 );
65 } else if self.num_of_bits >= 8 && self.num_of_bits <= 64 {
66 debug_assert!(
67 self.bit_offset.trailing_zeros() >= T::LOG2,
68 "{:?}: bit_offset must be aligned to {}",
69 self,
70 1 << T::LOG2
71 );
72 } else {
73 unreachable!("Metadata that is larger than 64-bits is not supported")
75 }
76 }
77
78 fn byte_offset(&self) -> isize {
79 self.bit_offset >> LOG_BITS_IN_BYTE
80 }
81
82 fn meta_addr(&self, header: Address) -> Address {
83 header + self.byte_offset()
84 }
85
86 fn get_shift_and_mask_for_bits(&self) -> (isize, u8) {
91 debug_assert!(self.num_of_bits < BITS_IN_BYTE);
92 let byte_offset = self.byte_offset();
93 let bit_shift = self.bit_offset - (byte_offset << LOG_BITS_IN_BYTE);
94 let mask = ((1u8 << self.num_of_bits) - 1) << bit_shift;
95 (bit_shift, mask)
96 }
97
98 fn get_bits_from_u8(&self, raw_byte: u8) -> u8 {
100 debug_assert!(self.num_of_bits < BITS_IN_BYTE);
101 let (bit_shift, mask) = self.get_shift_and_mask_for_bits();
102 (raw_byte & mask) >> bit_shift
103 }
104
105 fn set_bits_to_u8(&self, raw_byte: u8, set_val: u8) -> u8 {
107 debug_assert!(self.num_of_bits < BITS_IN_BYTE);
108 debug_assert!(
109 set_val < (1 << self.num_of_bits),
110 "{:b} exceeds the maximum value of {} bits in the spec",
111 set_val,
112 self.num_of_bits
113 );
114 let (bit_shift, mask) = self.get_shift_and_mask_for_bits();
115 (raw_byte & !mask) | (set_val << bit_shift)
116 }
117
118 fn truncate_bits_in_u8(&self, val: u8) -> u8 {
120 debug_assert!(self.num_of_bits < BITS_IN_BYTE);
121 val & ((1 << self.num_of_bits) - 1)
122 }
123
124 pub unsafe fn load<T: MetadataValue>(&self, header: Address, optional_mask: Option<T>) -> T {
129 self.load_inner::<T>(header, optional_mask, None)
130 }
131
132 pub fn load_atomic<T: MetadataValue>(
134 &self,
135 header: Address,
136 optional_mask: Option<T>,
137 ordering: Ordering,
138 ) -> T {
139 self.load_inner::<T>(header, optional_mask, Some(ordering))
140 }
141
142 fn load_inner<T: MetadataValue>(
143 &self,
144 header: Address,
145 optional_mask: Option<T>,
146 atomic_ordering: Option<Ordering>,
147 ) -> T {
148 #[cfg(debug_assertions)]
149 {
150 self.assert_mask::<T>(optional_mask);
151 self.assert_spec::<T>();
152 }
153
154 let res: T = if self.num_of_bits < 8 {
156 let byte_val = unsafe {
157 if let Some(order) = atomic_ordering {
158 (self.meta_addr(header)).atomic_load::<AtomicU8>(order)
159 } else {
160 (self.meta_addr(header)).load::<u8>()
161 }
162 };
163
164 FromPrimitive::from_u8(self.get_bits_from_u8(byte_val)).unwrap()
165 } else {
166 unsafe {
167 if let Some(order) = atomic_ordering {
168 T::load_atomic(self.meta_addr(header), order)
169 } else {
170 (self.meta_addr(header)).load::<T>()
171 }
172 }
173 };
174
175 if let Some(mask) = optional_mask {
176 res.bitand(mask)
177 } else {
178 res
179 }
180 }
181
182 pub unsafe fn store<T: MetadataValue>(
189 &self,
190 header: Address,
191 val: T,
192 optional_mask: Option<T>,
193 ) {
194 self.store_inner::<T>(header, val, optional_mask, None)
195 }
196
197 pub fn store_atomic<T: MetadataValue>(
201 &self,
202 header: Address,
203 val: T,
204 optional_mask: Option<T>,
205 ordering: Ordering,
206 ) {
207 self.store_inner::<T>(header, val, optional_mask, Some(ordering))
208 }
209
210 fn store_inner<T: MetadataValue>(
211 &self,
212 header: Address,
213 val: T,
214 optional_mask: Option<T>,
215 atomic_ordering: Option<Ordering>,
216 ) {
217 #[cfg(debug_assertions)]
218 {
219 self.assert_mask::<T>(optional_mask);
220 self.assert_spec::<T>();
221 }
222
223 if self.num_of_bits < 8 {
225 let val_u8 = val.to_u8().unwrap();
226 let byte_addr = self.meta_addr(header);
227 if let Some(order) = atomic_ordering {
228 let _ = unsafe {
229 <u8 as MetadataValue>::fetch_update(byte_addr, order, order, |old_val: u8| {
230 Some(self.set_bits_to_u8(old_val, val_u8))
231 })
232 };
233 } else {
234 unsafe {
235 let old_byte_val = byte_addr.load::<u8>();
236 let new_byte_val = self.set_bits_to_u8(old_byte_val, val_u8);
237 byte_addr.store::<u8>(new_byte_val);
238 }
239 }
240 } else {
241 let addr = self.meta_addr(header);
242 unsafe {
243 if let Some(order) = atomic_ordering {
244 if let Some(mask) = optional_mask {
246 let _ = T::fetch_update(addr, order, order, |old_val: T| {
247 Some(old_val.bitand(mask.inv()).bitor(val.bitand(mask)))
248 });
249 } else {
250 T::store_atomic(addr, val, order);
251 }
252 } else {
253 let val = if let Some(mask) = optional_mask {
254 let old_val = T::load(addr);
255 old_val.bitand(mask.inv()).bitor(val.bitand(mask))
256 } else {
257 val
258 };
259 T::store(addr, val);
260 }
261 }
262 }
263 }
264
265 pub fn compare_exchange<T: MetadataValue>(
269 &self,
270 header: Address,
271 old_metadata: T,
272 new_metadata: T,
273 optional_mask: Option<T>,
274 success_order: Ordering,
275 failure_order: Ordering,
276 ) -> Result<T, T> {
277 #[cfg(debug_assertions)]
278 self.assert_spec::<T>();
279 if self.num_of_bits < 8 {
281 let byte_addr = self.meta_addr(header);
282 unsafe {
283 let real_old_byte = byte_addr.atomic_load::<AtomicU8>(success_order);
284 let expected_old_byte =
285 self.set_bits_to_u8(real_old_byte, old_metadata.to_u8().unwrap());
286 let expected_new_byte =
287 self.set_bits_to_u8(expected_old_byte, new_metadata.to_u8().unwrap());
288 byte_addr
289 .compare_exchange::<AtomicU8>(
290 expected_old_byte,
291 expected_new_byte,
292 success_order,
293 failure_order,
294 )
295 .map(|x| FromPrimitive::from_u8(x).unwrap())
296 .map_err(|x| FromPrimitive::from_u8(x).unwrap())
297 }
298 } else {
299 let addr = self.meta_addr(header);
300 let (old_metadata, new_metadata) = if let Some(mask) = optional_mask {
301 let old_byte = unsafe { T::load_atomic(addr, success_order) };
302 let expected_new_byte = old_byte.bitand(mask.inv()).bitor(new_metadata);
303 let expected_old_byte = old_byte.bitand(mask.inv()).bitor(old_metadata);
304 (expected_old_byte, expected_new_byte)
305 } else {
306 (old_metadata, new_metadata)
307 };
308
309 unsafe {
310 T::compare_exchange(
311 addr,
312 old_metadata,
313 new_metadata,
314 success_order,
315 failure_order,
316 )
317 }
318 }
319 }
320
321 fn fetch_ops_on_bits<F: Fn(u8) -> u8>(
324 &self,
325 header: Address,
326 set_order: Ordering,
327 fetch_order: Ordering,
328 update: F,
329 ) -> u8 {
330 let byte_addr = self.meta_addr(header);
331 let old_raw_byte = unsafe {
332 <u8 as MetadataValue>::fetch_update(
333 byte_addr,
334 set_order,
335 fetch_order,
336 |raw_byte: u8| {
337 let old_metadata = self.get_bits_from_u8(raw_byte);
338 let new_metadata = self.truncate_bits_in_u8(update(old_metadata));
339 let new_byte = self.set_bits_to_u8(raw_byte, new_metadata);
340 Some(new_byte)
341 },
342 )
343 }
344 .unwrap();
345 self.get_bits_from_u8(old_raw_byte)
346 }
347
348 pub fn fetch_add<T: MetadataValue>(&self, header: Address, val: T, order: Ordering) -> T {
350 #[cfg(debug_assertions)]
351 self.assert_spec::<T>();
352 if self.num_of_bits < 8 {
353 FromPrimitive::from_u8(self.fetch_ops_on_bits(header, order, order, |x: u8| {
354 x.wrapping_add(val.to_u8().unwrap())
355 }))
356 .unwrap()
357 } else {
358 unsafe { T::fetch_add(self.meta_addr(header), val, order) }
359 }
360 }
361
362 pub fn fetch_sub<T: MetadataValue>(&self, header: Address, val: T, order: Ordering) -> T {
364 #[cfg(debug_assertions)]
365 self.assert_spec::<T>();
366 if self.num_of_bits < 8 {
367 FromPrimitive::from_u8(self.fetch_ops_on_bits(header, order, order, |x: u8| {
368 x.wrapping_sub(val.to_u8().unwrap())
369 }))
370 .unwrap()
371 } else {
372 unsafe { T::fetch_sub(self.meta_addr(header), val, order) }
373 }
374 }
375
376 pub fn fetch_and<T: MetadataValue>(&self, header: Address, val: T, order: Ordering) -> T {
378 #[cfg(debug_assertions)]
379 self.assert_spec::<T>();
380 if self.num_of_bits < 8 {
381 let (lshift, mask) = self.get_shift_and_mask_for_bits();
382 let new_val = (val.to_u8().unwrap() << lshift) | !mask;
383 let old_raw_byte =
385 unsafe { <u8 as MetadataValue>::fetch_and(self.meta_addr(header), new_val, order) };
386 let old_val = self.get_bits_from_u8(old_raw_byte);
387 FromPrimitive::from_u8(old_val).unwrap()
388 } else {
389 unsafe { T::fetch_and(self.meta_addr(header), val, order) }
390 }
391 }
392
393 pub fn fetch_or<T: MetadataValue>(&self, header: Address, val: T, order: Ordering) -> T {
395 #[cfg(debug_assertions)]
396 self.assert_spec::<T>();
397 if self.num_of_bits < 8 {
398 let (lshift, mask) = self.get_shift_and_mask_for_bits();
399 let new_val = (val.to_u8().unwrap() << lshift) & mask;
400 let old_raw_byte =
402 unsafe { <u8 as MetadataValue>::fetch_or(self.meta_addr(header), new_val, order) };
403 let old_val = self.get_bits_from_u8(old_raw_byte);
404 FromPrimitive::from_u8(old_val).unwrap()
405 } else {
406 unsafe { T::fetch_or(self.meta_addr(header), val, order) }
407 }
408 }
409
410 pub fn fetch_update<T: MetadataValue, F: FnMut(T) -> Option<T> + Copy>(
413 &self,
414 header: Address,
415 set_order: Ordering,
416 fetch_order: Ordering,
417 mut f: F,
418 ) -> std::result::Result<T, T> {
419 #[cfg(debug_assertions)]
420 self.assert_spec::<T>();
421 if self.num_of_bits < 8 {
422 let byte_addr = self.meta_addr(header);
423 unsafe {
424 <u8 as MetadataValue>::fetch_update(
425 byte_addr,
426 set_order,
427 fetch_order,
428 |raw_byte: u8| {
429 let old_metadata = self.get_bits_from_u8(raw_byte);
430 f(FromPrimitive::from_u8(old_metadata).unwrap()).map(|new_val| {
431 let new_metadata = self.truncate_bits_in_u8(new_val.to_u8().unwrap());
432 self.set_bits_to_u8(raw_byte, new_metadata)
433 })
434 },
435 )
436 }
437 .map(|raw_byte| FromPrimitive::from_u8(self.get_bits_from_u8(raw_byte)).unwrap())
438 .map_err(|raw_byte| FromPrimitive::from_u8(self.get_bits_from_u8(raw_byte)).unwrap())
439 } else {
440 unsafe { T::fetch_update(self.meta_addr(header), set_order, fetch_order, f) }
441 }
442 }
443}
444
445impl fmt::Debug for HeaderMetadataSpec {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 f.write_fmt(format_args!(
448 "HeaderMetadataSpec {{ \
449 **bit_offset: 0x{:x} \
450 **num_of_bits: 0x{:x} \
451 }}",
452 self.bit_offset, self.num_of_bits
453 ))
454 }
455}
456
457#[cfg(all(test, debug_assertions))]
458mod tests {
459 use super::*;
460 use crate::util::address::Address;
461
462 #[test]
463 fn test_valid_specs() {
464 let spec = HeaderMetadataSpec {
465 bit_offset: 0,
466 num_of_bits: 1,
467 };
468 spec.assert_spec::<u8>();
469
470 let spec = HeaderMetadataSpec {
471 bit_offset: 99,
472 num_of_bits: 1,
473 };
474 spec.assert_spec::<u8>();
475
476 let spec = HeaderMetadataSpec {
477 bit_offset: 0,
478 num_of_bits: 8,
479 };
480 spec.assert_spec::<u8>();
481
482 let spec = HeaderMetadataSpec {
483 bit_offset: 8,
484 num_of_bits: 8,
485 };
486 spec.assert_spec::<u8>();
487
488 let spec = HeaderMetadataSpec {
489 bit_offset: 32,
490 num_of_bits: 8,
491 };
492 spec.assert_spec::<u8>();
493 }
494
495 #[test]
496 #[should_panic]
497 fn test_spec_at_unaligned_offset() {
498 let spec = HeaderMetadataSpec {
499 bit_offset: 8,
500 num_of_bits: 16,
501 };
502 spec.assert_spec::<u16>();
503 }
504
505 #[test]
506 #[should_panic]
507 fn test_bits_spec_across_byte() {
508 let spec = HeaderMetadataSpec {
510 bit_offset: 7,
511 num_of_bits: 2,
512 };
513 spec.assert_spec::<u8>();
514 }
515
516 #[test]
517 fn test_negative_bit_offset() {
518 let spec = HeaderMetadataSpec {
519 bit_offset: -1,
520 num_of_bits: 1,
521 };
522 spec.assert_spec::<u8>();
523 assert_eq!(spec.get_shift_and_mask_for_bits(), (7, 0b1000_0000));
524 assert_eq!(spec.byte_offset(), -1);
525 assert_eq!(spec.get_bits_from_u8(0b1000_0000), 1);
526 assert_eq!(spec.get_bits_from_u8(0b0111_1111), 0);
527
528 let spec = HeaderMetadataSpec {
529 bit_offset: -2,
530 num_of_bits: 1,
531 };
532 spec.assert_spec::<u8>();
533 assert_eq!(spec.get_shift_and_mask_for_bits(), (6, 0b0100_0000));
534 assert_eq!(spec.byte_offset(), -1);
535 assert_eq!(spec.get_bits_from_u8(0b0100_0000), 1);
536 assert_eq!(spec.get_bits_from_u8(0b1011_1111), 0);
537
538 let spec = HeaderMetadataSpec {
539 bit_offset: -7,
540 num_of_bits: 1,
541 };
542 spec.assert_spec::<u8>();
543 assert_eq!(spec.get_shift_and_mask_for_bits(), (1, 0b0000_0010));
544 assert_eq!(spec.byte_offset(), -1);
545 assert_eq!(spec.get_bits_from_u8(0b0000_0010), 1);
546 assert_eq!(spec.get_bits_from_u8(0b1111_1101), 0);
547
548 let spec = HeaderMetadataSpec {
549 bit_offset: -8,
550 num_of_bits: 1,
551 };
552 spec.assert_spec::<u8>();
553 assert_eq!(spec.get_shift_and_mask_for_bits(), (0, 0b0000_0001));
554 assert_eq!(spec.byte_offset(), -1);
555 assert_eq!(spec.get_bits_from_u8(0b0000_0001), 1);
556 assert_eq!(spec.get_bits_from_u8(0b1111_1110), 0);
557
558 let spec = HeaderMetadataSpec {
559 bit_offset: -9,
560 num_of_bits: 1,
561 };
562 spec.assert_spec::<u8>();
563 assert_eq!(spec.get_shift_and_mask_for_bits(), (7, 0b1000_0000));
564 assert_eq!(spec.byte_offset(), -2);
565 assert_eq!(spec.get_bits_from_u8(0b1000_0000), 1);
566 assert_eq!(spec.get_bits_from_u8(0b0111_1111), 0);
567 }
568
569 #[test]
570 fn test_get_bits_from_u8() {
571 let spec = HeaderMetadataSpec {
573 bit_offset: 0,
574 num_of_bits: 1,
575 };
576 assert_eq!(spec.get_shift_and_mask_for_bits(), (0, 0b1));
577 assert_eq!(spec.byte_offset(), 0);
578 assert_eq!(spec.get_bits_from_u8(0b0000_0001), 1);
579 assert_eq!(spec.get_bits_from_u8(0b1111_1110), 0);
580
581 let spec = HeaderMetadataSpec {
582 bit_offset: 1,
583 num_of_bits: 1,
584 };
585 assert_eq!(spec.get_shift_and_mask_for_bits(), (1, 0b10));
586 assert_eq!(spec.get_bits_from_u8(0b0000_0010), 1);
587 assert_eq!(spec.get_bits_from_u8(0b1111_1101), 0);
588
589 let spec = HeaderMetadataSpec {
590 bit_offset: 7,
591 num_of_bits: 1,
592 };
593 assert_eq!(spec.get_shift_and_mask_for_bits(), (7, 0b1000_0000));
594 assert_eq!(spec.get_bits_from_u8(0b1000_0000), 1);
595 assert_eq!(spec.get_bits_from_u8(0b0111_1111), 0);
596
597 let spec = HeaderMetadataSpec {
599 bit_offset: 8,
600 num_of_bits: 1,
601 };
602 assert_eq!(spec.get_shift_and_mask_for_bits(), (0, 0b1));
603 assert_eq!(spec.get_bits_from_u8(0b0000_0001), 1);
604 assert_eq!(spec.get_bits_from_u8(0b1111_1110), 0);
605
606 let spec = HeaderMetadataSpec {
608 bit_offset: 0,
609 num_of_bits: 2,
610 };
611 assert_eq!(spec.get_shift_and_mask_for_bits(), (0, 0b11));
612 assert_eq!(spec.get_bits_from_u8(0b0000_0011), 0b11);
613 assert_eq!(spec.get_bits_from_u8(0b0000_0010), 0b10);
614 assert_eq!(spec.get_bits_from_u8(0b1111_1110), 0b10);
615
616 let spec = HeaderMetadataSpec {
617 bit_offset: 6,
618 num_of_bits: 2,
619 };
620 assert_eq!(spec.get_shift_and_mask_for_bits(), (6, 0b1100_0000));
621 assert_eq!(spec.get_bits_from_u8(0b1100_0000), 0b11);
622 assert_eq!(spec.get_bits_from_u8(0b1000_0000), 0b10);
623 assert_eq!(spec.get_bits_from_u8(0b1011_1111), 0b10);
624
625 let spec = HeaderMetadataSpec {
627 bit_offset: 8,
628 num_of_bits: 2,
629 };
630 assert_eq!(spec.get_shift_and_mask_for_bits(), (0, 0b0000_0011));
631 assert_eq!(spec.get_bits_from_u8(0b0000_0011), 0b11);
632 assert_eq!(spec.get_bits_from_u8(0b0000_0010), 0b10);
633 assert_eq!(spec.get_bits_from_u8(0b1111_1110), 0b10);
634 }
635
636 #[test]
637 fn test_set_bits_to_u8() {
638 let spec = HeaderMetadataSpec {
640 bit_offset: 0,
641 num_of_bits: 1,
642 };
643 assert_eq!(spec.set_bits_to_u8(0b0000_0000, 1), 0b0000_0001);
644 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 1), 0b1111_1111);
645 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 0), 0b1111_1110);
646
647 let spec = HeaderMetadataSpec {
648 bit_offset: 1,
649 num_of_bits: 1,
650 };
651 assert_eq!(spec.set_bits_to_u8(0b0000_0000, 1), 0b0000_0010);
652 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 1), 0b1111_1111);
653 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 0), 0b1111_1101);
654
655 let spec = HeaderMetadataSpec {
657 bit_offset: 0,
658 num_of_bits: 2,
659 };
660 assert_eq!(spec.set_bits_to_u8(0b0000_0000, 0b11), 0b0000_0011);
661 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 0b11), 0b1111_1111);
662 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 0b10), 0b1111_1110);
663 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 0b01), 0b1111_1101);
664 assert_eq!(spec.set_bits_to_u8(0b1111_1111, 0b00), 0b1111_1100);
665 }
666
667 #[test]
668 #[should_panic]
669 fn test_set_bits_to_u8_exceeds_bits() {
670 let spec = HeaderMetadataSpec {
671 bit_offset: 0,
672 num_of_bits: 1,
673 };
674 spec.set_bits_to_u8(0, 0b11);
675 }
676
677 use paste::paste;
678
679 macro_rules! impl_with_object {
680 ($type: ty) => {
681 paste!{
682 fn [<with_ $type _obj>]<F>(f: F) where F: FnOnce(Address, *mut $type) + std::panic::UnwindSafe {
683 let ty_size = ($type::BITS >> LOG_BITS_IN_BYTE) as usize;
685 let layout = std::alloc::Layout::from_size_align(ty_size * 3, ty_size).unwrap();
686 let (obj, ptr) = {
687 let ptr_raw: *mut $type = unsafe { std::alloc::alloc_zeroed(layout) as *mut $type };
688 let ptr_mid: *mut $type = unsafe { ptr_raw.offset(1) };
690 assert_eq!(unsafe { *(ptr_mid.offset(-1)) }, 0, "memory at offset -1 is not zero");
692 assert_eq!(unsafe { *ptr_mid }, 0, "memory at offset 0 is not zero");
693 assert_eq!(unsafe { *(ptr_mid.offset(1)) }, 0, "memory at offset 1 is not zero");
694 (Address::from_ptr(ptr_mid), ptr_mid)
695 };
696 crate::util::test_util::with_cleanup(
697 || f(obj, ptr),
698 || {
699 unsafe { std::alloc::dealloc(ptr.offset(-1) as *mut u8, layout); }
700 }
701 )
702 }
703 }
704 }
705 }
706
707 impl_with_object!(u8);
708 impl_with_object!(u16);
709 impl_with_object!(u32);
710 impl_with_object!(u64);
711 impl_with_object!(usize);
712
713 fn max_value(n_bits: usize) -> u64 {
714 (0..n_bits).fold(0, |accum, x| accum + (1 << x))
715 }
716
717 macro_rules! test_header_metadata_access {
718 ($tname: ident, $type: ty, $num_of_bits: expr) => {
719 paste!{
720 #[test]
721 fn [<$tname _load>]() {
722 [<with_ $type _obj>](|obj, ptr| {
723 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
724 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
725 let max_value = max_value($num_of_bits) as $type;
726 unsafe { *ptr = max_value };
727 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
728 });
729 }
730
731 #[test]
732 fn [<$tname _load_atomic>]() {
733 [<with_ $type _obj>](|obj, ptr| {
734 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
735 assert_eq!(spec.load_atomic::<$type>(obj, None, Ordering::SeqCst), 0);
736 let max_value = max_value($num_of_bits) as $type;
737 unsafe { *ptr = max_value };
738 assert_eq!(spec.load_atomic::<$type>(obj, None, Ordering::SeqCst), max_value);
739 });
740 }
741
742 #[test]
743 fn [<$tname _load_next>]() {
744 [<with_ $type _obj>](|obj, ptr| {
745 let spec = HeaderMetadataSpec { bit_offset: $num_of_bits, num_of_bits: $num_of_bits };
746 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
747 let max_value = max_value($num_of_bits) as $type;
748 if $num_of_bits < 8 {
749 unsafe { *ptr = max_value << spec.bit_offset}
750 } else {
751 unsafe { *(ptr.offset(1)) = max_value };
752 }
753 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
754 });
755 }
756
757 #[test]
758 fn [<$tname _load_prev>]() {
759 [<with_ $type _obj>](|obj, ptr| {
760 let spec = HeaderMetadataSpec { bit_offset: -$num_of_bits, num_of_bits: $num_of_bits };
761 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
762 let max_value = max_value($num_of_bits) as $type;
763 if $num_of_bits < 8 {
764 unsafe { *(ptr.offset(-1)) = max_value << (BITS_IN_BYTE as isize + spec.bit_offset)}
765 } else {
766 unsafe { *(ptr.offset(-1)) = max_value };
767 }
768 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
769 });
770 }
771
772 #[test]
773 fn [<$tname _load_mask>]() {
774 [<with_ $type _obj>](|obj, ptr| {
775 if $num_of_bits < 8 {
777 return;
778 }
779
780 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
781 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
782 let max_value = max_value($num_of_bits) as $type;
783 unsafe { *ptr = max_value };
784 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
785 assert_eq!(unsafe { spec.load::<$type>(obj, Some(0)) }, 0);
786 assert_eq!(unsafe { spec.load::<$type>(obj, Some(0b101)) }, 0b101);
787 });
788 }
789
790 #[test]
791 fn [<$tname _store>]() {
792 [<with_ $type _obj>](|obj, ptr| {
793 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
794 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
795 let max_value = max_value($num_of_bits) as $type;
796 unsafe { spec.store::<$type>(obj, max_value, None) };
797 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
798 assert_eq!(unsafe { *ptr }, max_value);
799 });
800 }
801
802 #[test]
803 fn [<$tname _store_atomic>]() {
804 [<with_ $type _obj>](|obj, ptr| {
805 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
806 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
807 let max_value = max_value($num_of_bits) as $type;
808 spec.store_atomic::<$type>(obj, max_value, None, Ordering::SeqCst);
809 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
810 assert_eq!(unsafe { *ptr }, max_value);
811 });
812 }
813
814 #[test]
815 fn [<$tname _store_next>]() {
816 [<with_ $type _obj>](|obj, ptr| {
817 let spec = HeaderMetadataSpec { bit_offset: $num_of_bits, num_of_bits: $num_of_bits };
818 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
819 let max_value = max_value($num_of_bits) as $type;
820 unsafe { spec.store::<$type>(obj, max_value, None) };
821 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
822 if $num_of_bits < 8 {
823 assert_eq!(unsafe { *ptr }, max_value << spec.bit_offset);
824 } else {
825 assert_eq!(unsafe { *(ptr.offset(1)) }, max_value);
826 }
827 });
828 }
829
830 #[test]
831 fn [<$tname _store_prev>]() {
832 [<with_ $type _obj>](|obj, ptr| {
833 let spec = HeaderMetadataSpec { bit_offset: -$num_of_bits, num_of_bits: $num_of_bits };
834 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
835 let max_value = max_value($num_of_bits) as $type;
836 unsafe { spec.store::<$type>(obj, max_value, None) };
837 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
838 if $num_of_bits < 8 {
839 assert_eq!(unsafe { *ptr.offset(-1) }, max_value << (BITS_IN_BYTE as isize + spec.bit_offset));
840 } else {
841 assert_eq!(unsafe { *(ptr.offset(-1)) }, max_value);
842 }
843 });
844 }
845
846 #[test]
847 fn [<$tname _store_mask>]() {
848 [<with_ $type _obj>](|obj, ptr| {
849 if $num_of_bits < 8 {
851 return;
852 }
853
854 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
855 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
856 let max_value = max_value($num_of_bits) as $type;
857
858 unsafe { spec.store::<$type>(obj, max_value, Some(max_value)) };
860 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
861
862 unsafe { spec.store::<$type>(obj, 0, None) };
864
865 unsafe { spec.store::<$type>(obj, max_value, Some(0b10)) };
867 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0b10);
868 assert_eq!(unsafe { *ptr }, 0b10);
869 });
870 }
871
872 #[test]
873 fn [<$tname _compare_exchange_success>]() {
874 [<with_ $type _obj>](|obj, _| {
875 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
876 let old_val = unsafe { spec.load::<$type>(obj, None) };
877 assert_eq!(old_val, 0);
878
879 let max_value = max_value($num_of_bits) as $type;
880 let res = spec.compare_exchange::<$type>(obj, old_val, max_value, None, Ordering::SeqCst, Ordering::SeqCst);
881 assert!(res.is_ok());
882 assert_eq!(res.unwrap(), old_val);
883 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
884 })
885 }
886
887 #[test]
888 fn [<$tname _compare_exchange_fail>]() {
889 [<with_ $type _obj>](|obj, _| {
890 let spec = HeaderMetadataSpec { bit_offset: 0, num_of_bits: $num_of_bits };
891 let old_val = unsafe { spec.load::<$type>(obj, None) };
892 assert_eq!(old_val, 0);
893
894 unsafe { spec.store::<$type>(obj, 1, None) };
896
897 let max_value = max_value($num_of_bits) as $type;
898 let res = spec.compare_exchange::<$type>(obj, old_val, max_value, None, Ordering::SeqCst, Ordering::SeqCst);
899 assert!(res.is_err());
900 assert_eq!(res.err().unwrap(), 1);
901 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 1);
902 })
903 }
904
905 #[test]
906 fn [<$tname _fetch_add>]() {
907 [<with_ $type _obj>](|obj, _| {
908 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
909 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
910 let max_value = max_value($num_of_bits) as $type;
911
912 let old_val = unsafe { spec.load::<$type>(obj, None) };
913 assert_eq!(old_val, 0);
914
915 let old_val_from_fetch = spec.fetch_add::<$type>(obj, max_value, Ordering::SeqCst);
916 assert_eq!(old_val, old_val_from_fetch);
917 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
918 }
919 })
920 }
921
922 #[test]
923 fn [<$tname _fetch_add_overflow>]() {
924 [<with_ $type _obj>](|obj, ptr| {
925 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
926 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
927 let max_value = max_value($num_of_bits) as $type;
928
929 unsafe { spec.store::<$type>(obj, max_value, None) };
930 let old_val = unsafe { spec.load::<$type>(obj, None) };
931
932 let old_val_from_fetch = spec.fetch_add::<$type>(obj, 1, Ordering::SeqCst);
934 assert_eq!(old_val, old_val_from_fetch);
935 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
936 assert_eq!(unsafe { *ptr }, 0); }
938 })
939 }
940
941 #[test]
942 fn [<$tname _fetch_sub>]() {
943 [<with_ $type _obj>](|obj, _| {
944 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
945 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
946
947 unsafe { spec.store::<$type>(obj, 1, None) };
948 let old_val = unsafe { spec.load::<$type>(obj, None) };
949 assert_eq!(old_val, 1);
950
951 let old_val_from_fetch = spec.fetch_sub::<$type>(obj, 1, Ordering::SeqCst);
952 assert_eq!(old_val, old_val_from_fetch);
953 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
954 }
955 })
956 }
957
958 #[test]
959 fn [<$tname _fetch_sub_overflow>]() {
960 [<with_ $type _obj>](|obj, _| {
961 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
962 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
963 let max_value = max_value($num_of_bits) as $type;
964
965 let old_val = unsafe { spec.load::<$type>(obj, None) };
966 assert_eq!(old_val, 0);
967
968 let old_val_from_fetch = spec.fetch_sub::<$type>(obj, 1, Ordering::SeqCst);
969 assert_eq!(old_val, old_val_from_fetch);
970 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
971 }
972 })
973 }
974
975 #[test]
976 fn [<$tname _fetch_and>]() {
977 [<with_ $type _obj>](|obj, _| {
978 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
979 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
980 let max_value = max_value($num_of_bits) as $type;
981
982 let old_val = unsafe { spec.load::<$type>(obj, None) };
983 assert_eq!(old_val, 0);
984
985 let old_val_from_fetch = spec.fetch_and::<$type>(obj, max_value, Ordering::SeqCst);
986 assert_eq!(old_val, old_val_from_fetch);
987 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
988 }
989 })
990 }
991
992 #[test]
993 fn [<$tname _fetch_or>]() {
994 [<with_ $type _obj>](|obj, _| {
995 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
996 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
997 let max_value = max_value($num_of_bits) as $type;
998
999 let old_val = unsafe { spec.load::<$type>(obj, None) };
1000 assert_eq!(old_val, 0);
1001
1002 let old_val_from_fetch = spec.fetch_or::<$type>(obj, max_value, Ordering::SeqCst);
1003 assert_eq!(old_val, old_val_from_fetch);
1004 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
1005 }
1006 })
1007 }
1008
1009 #[test]
1010 fn [<$tname _fetch_update_success>]() {
1011 [<with_ $type _obj>](|obj, _| {
1012 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
1013 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
1014 let max_value = max_value($num_of_bits) as $type;
1015
1016 let old_val = unsafe { spec.load::<$type>(obj, None) };
1017 assert_eq!(old_val, 0);
1018
1019 let update_res = spec.fetch_update(obj, Ordering::SeqCst, Ordering::SeqCst, |_x: $type| Some(max_value));
1020 assert!(update_res.is_ok());
1021 assert_eq!(old_val, update_res.unwrap());
1022 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, max_value);
1023 }
1024 })
1025 }
1026
1027 #[test]
1028 fn [<$tname _fetch_update_fail>]() {
1029 [<with_ $type _obj>](|obj, _| {
1030 for bit_offset in (0isize..($type::BITS as isize)).step_by($num_of_bits) {
1031 let spec = HeaderMetadataSpec { bit_offset, num_of_bits: $num_of_bits };
1032
1033 let old_val = unsafe { spec.load::<$type>(obj, None) };
1034 assert_eq!(old_val, 0);
1035
1036 let update_res = spec.fetch_update(obj, Ordering::SeqCst, Ordering::SeqCst, |_x: $type| None);
1037 assert!(update_res.is_err());
1038 assert_eq!(old_val, update_res.err().unwrap());
1039 assert_eq!(unsafe { spec.load::<$type>(obj, None) }, 0);
1040 }
1041 })
1042 }
1043 }
1044 }
1045 }
1046
1047 test_header_metadata_access!(test_u1, u8, 1);
1048 test_header_metadata_access!(test_u2, u8, 2);
1049 test_header_metadata_access!(test_u4, u8, 4);
1050 test_header_metadata_access!(test_u8, u8, 8);
1051 test_header_metadata_access!(test_u16, u16, 16);
1052 test_header_metadata_access!(test_u32, u32, 32);
1053 test_header_metadata_access!(test_u64, u64, 64);
1054 test_header_metadata_access!(
1055 test_usize,
1056 usize,
1057 if cfg!(target_pointer_width = "64") {
1058 64
1059 } else if cfg!(target_pointer_width = "32") {
1060 32
1061 } else {
1062 unreachable!()
1063 }
1064 );
1065}