1use super::ranges::BitOffset;
2use super::SideMetadataSpec;
3use crate::util::constants::LOG_BYTES_IN_PAGE;
4use crate::util::constants::{BITS_IN_WORD, BYTES_IN_PAGE, LOG_BITS_IN_BYTE};
5use crate::util::conversions::rshift_align_up;
6use crate::util::heap::layout::vm_layout::VMLayout;
7#[cfg(target_pointer_width = "32")]
8use crate::util::metadata::side_metadata::address_to_chunked_meta_address;
9use crate::util::os::*;
10use crate::util::Address;
11use crate::MMAPPER;
12
13pub(super) fn address_to_contiguous_meta_address(
15 metadata_spec: &SideMetadataSpec,
16 data_addr: Address,
17) -> Address {
18 let log_bits_num = metadata_spec.log_num_of_bits as i32;
19 let log_bytes_in_region = metadata_spec.log_bytes_in_region;
20
21 let shift = (LOG_BITS_IN_BYTE as i32) - log_bits_num;
22
23 if shift >= 0 {
24 metadata_spec.get_absolute_offset() + ((data_addr >> log_bytes_in_region) >> shift)
25 } else {
26 metadata_spec.get_absolute_offset() + ((data_addr >> log_bytes_in_region) << (-shift))
27 }
28}
29
30pub(super) fn contiguous_meta_address_to_address(
38 metadata_spec: &SideMetadataSpec,
39 metadata_addr: Address,
40 bit: u8,
41) -> Address {
42 debug_assert_eq!(
43 align_metadata_address(metadata_spec, metadata_addr, bit),
44 (metadata_addr, bit)
45 );
46 let shift = (LOG_BITS_IN_BYTE as i32) - metadata_spec.log_num_of_bits as i32;
47 let relative_meta_addr = metadata_addr - metadata_spec.get_absolute_offset();
48
49 let data_addr_intermediate = if shift >= 0 {
50 relative_meta_addr << shift
51 } else {
52 relative_meta_addr >> (-shift)
53 };
54 let data_addr_bit_shift = if shift >= 0 {
55 metadata_spec.log_bytes_in_region - metadata_spec.log_num_of_bits
56 } else {
57 metadata_spec.log_bytes_in_region
58 };
59
60 let data_addr = (data_addr_intermediate << metadata_spec.log_bytes_in_region)
61 + ((bit as usize) << data_addr_bit_shift);
62
63 unsafe { Address::from_usize(data_addr) }
64}
65
66pub(super) fn align_metadata_address(
72 spec: &SideMetadataSpec,
73 metadata_addr: Address,
74 bit: u8,
75) -> (Address, u8) {
76 if spec.log_num_of_bits >= LOG_BITS_IN_BYTE as usize {
77 (
78 metadata_addr.align_down(1 << (spec.log_num_of_bits - LOG_BITS_IN_BYTE as usize)),
79 0,
80 )
81 } else {
82 (
83 metadata_addr,
84 crate::util::conversions::raw_align_down(
85 bit as usize,
86 (1 << spec.log_num_of_bits) as usize,
87 ) as u8,
88 )
89 }
90}
91
92#[cfg(test)]
94pub(crate) fn ensure_munmap_metadata(start: Address, size: usize) {
95 trace!("ensure_munmap_metadata({}, 0x{:x})", start, size);
96
97 assert!(OS::munmap(start, size).is_ok())
98}
99
100#[cfg(test)]
103pub(crate) fn ensure_munmap_contiguous_metadata_space(
104 start: Address,
105 size: usize,
106 spec: &SideMetadataSpec,
107) -> usize {
108 let metadata_start = address_to_meta_address(spec, start);
110 let mmap_start = metadata_start.align_down(BYTES_IN_PAGE);
111 let metadata_size = data_to_meta_size_round_up(spec, size);
113 let mmap_size = (metadata_start + metadata_size).align_up(BYTES_IN_PAGE) - mmap_start;
114 if mmap_size > 0 {
115 ensure_munmap_metadata(mmap_start, mmap_size);
116 }
117 mmap_size
118}
119
120pub(super) fn try_mmap_contiguous_metadata_space(
124 start: Address,
125 size: usize,
126 spec: &SideMetadataSpec,
127 no_reserve: bool,
128 anno: &MmapAnnotation,
129) -> MmapResult<usize> {
130 debug_assert!(start.is_aligned_to(BYTES_IN_PAGE));
131 debug_assert!(size % BYTES_IN_PAGE == 0);
132
133 let metadata_start = address_to_meta_address(spec, start);
135 let mmap_start = metadata_start.align_down(BYTES_IN_PAGE);
136 let metadata_size = data_to_meta_size_round_up(spec, size);
138 let mmap_size = (metadata_start + metadata_size).align_up(BYTES_IN_PAGE) - mmap_start;
139 if mmap_size > 0 {
140 if !no_reserve {
141 MMAPPER.ensure_mapped(
142 mmap_start,
143 mmap_size >> LOG_BYTES_IN_PAGE,
144 HugePageSupport::No,
145 MmapProtection::ReadWrite,
146 anno,
147 )
148 } else {
149 MMAPPER.quarantine_address_range(
150 mmap_start,
151 mmap_size >> LOG_BYTES_IN_PAGE,
152 HugePageSupport::No,
153 anno,
154 )
155 }
156 .map(|_| mmap_size)
157 } else {
158 Ok(0)
159 }
160}
161
162pub(crate) fn address_to_meta_address(
164 metadata_spec: &SideMetadataSpec,
165 data_addr: Address,
166) -> Address {
167 #[cfg(target_pointer_width = "32")]
168 let res = {
169 if metadata_spec.is_global {
170 address_to_contiguous_meta_address(metadata_spec, data_addr)
171 } else {
172 address_to_chunked_meta_address(metadata_spec, data_addr)
173 }
174 };
175 #[cfg(target_pointer_width = "64")]
176 let res = { address_to_contiguous_meta_address(metadata_spec, data_addr) };
177
178 trace!(
179 "address_to_meta_address({:?}, addr: {}) -> 0x{:x}",
180 metadata_spec,
181 data_addr,
182 res
183 );
184
185 res
186}
187
188pub(super) const fn log_data_meta_ratio(metadata_spec: &SideMetadataSpec) -> usize {
196 let log_data_bits_in_region = (LOG_BITS_IN_BYTE as usize) + metadata_spec.log_bytes_in_region;
197 let log_meta_bits_in_region = metadata_spec.log_num_of_bits;
198
199 log_data_bits_in_region - log_meta_bits_in_region
203}
204
205pub(super) const fn data_to_meta_size_round_up(
209 metadata_spec: &SideMetadataSpec,
210 data_size: usize,
211) -> usize {
212 rshift_align_up(data_size, log_data_meta_ratio(metadata_spec))
213}
214
215pub(super) const fn meta_to_data_size(metadata_spec: &SideMetadataSpec, meta_size: usize) -> usize {
218 meta_size << log_data_meta_ratio(metadata_spec)
219}
220
221#[allow(dead_code)]
222pub(super) const fn metadata_address_range_size(metadata_spec: &SideMetadataSpec) -> usize {
223 1usize << (VMLayout::LOG_ARCH_ADDRESS_SPACE - log_data_meta_ratio(metadata_spec))
224}
225
226pub(super) fn meta_byte_lshift(metadata_spec: &SideMetadataSpec, data_addr: Address) -> u8 {
227 let bits_num_log = metadata_spec.log_num_of_bits as i32;
228 if bits_num_log >= 3 {
229 return 0;
230 }
231 let rem_shift = BITS_IN_WORD as i32 - ((LOG_BITS_IN_BYTE as i32) - bits_num_log);
232 ((((data_addr >> metadata_spec.log_bytes_in_region) << rem_shift) >> rem_shift) << bits_num_log)
233 as u8
234}
235
236pub(super) fn meta_byte_mask(metadata_spec: &SideMetadataSpec) -> u8 {
237 let bits_num_log = metadata_spec.log_num_of_bits;
238 ((1usize << (1usize << bits_num_log)) - 1) as u8
239}
240
241pub enum FindMetaBitResult {
243 Found { addr: Address, bit: u8 },
244 NotFound,
245 UnmappedMetadata,
246}
247
248pub fn find_last_non_zero_bit_in_metadata_bytes(
250 meta_start: Address,
251 meta_end: Address,
252) -> FindMetaBitResult {
253 use crate::util::constants::BYTES_IN_ADDRESS;
254
255 let mmap_granularity = MMAPPER.granularity();
256
257 let mut cur = meta_end;
258 let mut mapped_grain = Address::MAX;
262 while cur > meta_start {
263 let step = if cur.is_aligned_to(BYTES_IN_ADDRESS) && cur - BYTES_IN_ADDRESS >= meta_start {
265 BYTES_IN_ADDRESS
266 } else {
267 1
268 };
269 cur -= step;
271 debug_assert!(
273 cur >= meta_start && cur < meta_end,
274 "Check metadata value at meta address {}, which is not in the range of [{}, {})",
275 cur,
276 meta_start,
277 meta_end
278 );
279
280 if cur < mapped_grain {
282 if cur.is_mapped() {
283 mapped_grain = cur.align_down(mmap_granularity);
285 } else {
286 return FindMetaBitResult::UnmappedMetadata;
287 }
288 }
289
290 if step == BYTES_IN_ADDRESS {
291 let value = unsafe { cur.load::<usize>() };
293 if value != 0 {
294 let bit = find_last_non_zero_bit::<usize>(value, 0, usize::BITS as u8).unwrap();
295 let byte_offset = bit >> LOG_BITS_IN_BYTE;
296 let bit_offset = bit - ((byte_offset) << LOG_BITS_IN_BYTE);
297 return FindMetaBitResult::Found {
298 addr: cur + byte_offset as usize,
299 bit: bit_offset,
300 };
301 }
302 } else {
303 let value = unsafe { cur.load::<u8>() };
305 if let Some(bit) = find_last_non_zero_bit::<u8>(value, 0, 8) {
306 return FindMetaBitResult::Found { addr: cur, bit };
307 }
308 }
309 }
310 FindMetaBitResult::NotFound
311}
312
313pub fn find_last_non_zero_bit_in_metadata_bits(
315 addr: Address,
316 start_bit: u8,
317 end_bit: u8,
318) -> FindMetaBitResult {
319 if !addr.is_mapped() {
320 return FindMetaBitResult::UnmappedMetadata;
321 }
322 let byte = unsafe { addr.load::<u8>() };
323 if let Some(bit) = find_last_non_zero_bit::<u8>(byte, start_bit, end_bit) {
324 return FindMetaBitResult::Found { addr, bit };
325 }
326 FindMetaBitResult::NotFound
327}
328
329use num_traits::{CheckedShl, PrimInt};
330fn find_last_non_zero_bit<T>(value: T, start: u8, end: u8) -> Option<u8>
331where
332 T: PrimInt + CheckedShl,
333{
334 let mask = match T::one().checked_shl((end - start) as u32) {
335 Some(shl) => (shl - T::one()) << (start as u32),
336 None => T::max_value() << (start as u32),
337 };
338 let masked = value & mask;
339 if masked.is_zero() {
340 None
341 } else {
342 let leading_zeroes = masked.leading_zeros();
343 let total_bits = std::mem::size_of::<T>() * u8::BITS as usize;
344 Some(total_bits as u8 - leading_zeroes as u8 - 1)
345 }
346}
347
348pub fn scan_non_zero_bits_in_metadata_bytes(
349 meta_start: Address,
350 meta_end: Address,
351 visit_bit: &mut impl FnMut(Address, BitOffset),
352) {
353 use crate::util::constants::BYTES_IN_ADDRESS;
354
355 let mut cursor = meta_start;
356 while cursor < meta_end && !cursor.is_aligned_to(BYTES_IN_ADDRESS) {
357 let byte = unsafe { cursor.load::<u8>() };
358 scan_non_zero_bits_in_metadata_word(cursor, byte as usize, visit_bit);
359 cursor += 1usize;
360 }
361
362 while cursor + BYTES_IN_ADDRESS < meta_end {
363 let word = unsafe { cursor.load::<usize>() };
364 scan_non_zero_bits_in_metadata_word(cursor, word, visit_bit);
365 cursor += BYTES_IN_ADDRESS;
366 }
367
368 while cursor < meta_end {
369 let byte = unsafe { cursor.load::<u8>() };
370 scan_non_zero_bits_in_metadata_word(cursor, byte as usize, visit_bit);
371 cursor += 1usize;
372 }
373}
374
375fn scan_non_zero_bits_in_metadata_word(
376 meta_addr: Address,
377 mut word: usize,
378 visit_bit: &mut impl FnMut(Address, BitOffset),
379) {
380 while word != 0 {
381 let bit = word.trailing_zeros();
382 visit_bit(meta_addr, bit as u8);
383 word = word & (word - 1);
384 }
385}
386
387pub fn scan_non_zero_bits_in_metadata_bits(
388 meta_addr: Address,
389 bit_start: BitOffset,
390 bit_end: BitOffset,
391 visit_bit: &mut impl FnMut(Address, BitOffset),
392) {
393 let byte = unsafe { meta_addr.load::<u8>() };
394 for bit in bit_start..bit_end {
395 if byte & (1 << bit) != 0 {
396 visit_bit(meta_addr, bit);
397 }
398 }
399}
400
401#[cfg(test)]
402mod tests {
403 use super::*;
404 use crate::util::metadata::side_metadata::*;
405
406 fn test_round_trip_conversion(spec: &SideMetadataSpec, test_data: &[Address]) {
407 for ref_addr in test_data {
408 let addr = *ref_addr;
409
410 {
412 assert!(addr.is_aligned_to(1 << spec.log_bytes_in_region));
413 let meta_addr = address_to_contiguous_meta_address(spec, addr);
414 let shift = meta_byte_lshift(spec, addr);
415 assert_eq!(
416 contiguous_meta_address_to_address(spec, meta_addr, shift),
417 addr
418 );
419 }
420
421 {
423 let next_addr = addr + 1usize;
424 let meta_addr = address_to_contiguous_meta_address(spec, next_addr);
425 let shift = meta_byte_lshift(spec, next_addr);
426 assert_eq!(
427 contiguous_meta_address_to_address(spec, meta_addr, shift),
428 addr
429 ); }
431 }
432 }
433
434 const TEST_ADDRESS_8B_REGION: [Address; 8] = [
435 unsafe { Address::from_usize(0x8000_0000) },
436 unsafe { Address::from_usize(0x8000_0008) },
437 unsafe { Address::from_usize(0x8000_0010) },
438 unsafe { Address::from_usize(0x8000_0018) },
439 unsafe { Address::from_usize(0x8000_0020) },
440 unsafe { Address::from_usize(0x8001_0000) },
441 unsafe { Address::from_usize(0x8001_0008) },
442 unsafe { Address::from_usize(0xd000_0000) },
443 ];
444
445 #[test]
446 fn test_contiguous_metadata_conversion_0_3() {
447 let spec = SideMetadataSpec {
448 name: "ContiguousMetadataTestSpec",
449 is_global: true,
450 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
451 log_num_of_bits: 0,
452 log_bytes_in_region: 3,
453 };
454
455 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
456 }
457
458 #[test]
459 fn test_contiguous_metadata_conversion_1_3() {
460 let spec = SideMetadataSpec {
461 name: "ContiguousMetadataTestSpec",
462 is_global: true,
463 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
464 log_num_of_bits: 1,
465 log_bytes_in_region: 3,
466 };
467
468 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
469 }
470
471 #[test]
472 fn test_contiguous_metadata_conversion_4_3() {
473 let spec = SideMetadataSpec {
474 name: "ContiguousMetadataTestSpec",
475 is_global: true,
476 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
477 log_num_of_bits: 4,
478 log_bytes_in_region: 3,
479 };
480
481 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
482 }
483
484 #[test]
485 fn test_contiguous_metadata_conversion_5_3() {
486 let spec = SideMetadataSpec {
487 name: "ContiguousMetadataTestSpec",
488 is_global: true,
489 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
490 log_num_of_bits: 5,
491 log_bytes_in_region: 3,
492 };
493
494 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
495 }
496
497 const TEST_ADDRESS_4KB_REGION: [Address; 8] = [
498 unsafe { Address::from_usize(0x8000_0000) },
499 unsafe { Address::from_usize(0x8000_1000) },
500 unsafe { Address::from_usize(0x8000_2000) },
501 unsafe { Address::from_usize(0x8000_3000) },
502 unsafe { Address::from_usize(0x8000_4000) },
503 unsafe { Address::from_usize(0x8001_0000) },
504 unsafe { Address::from_usize(0x8001_1000) },
505 unsafe { Address::from_usize(0xd000_0000) },
506 ];
507
508 #[test]
509 fn test_contiguous_metadata_conversion_0_12() {
510 let spec = SideMetadataSpec {
511 name: "ContiguousMetadataTestSpec",
512 is_global: true,
513 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
514 log_num_of_bits: 0,
515 log_bytes_in_region: 12, };
517
518 test_round_trip_conversion(&spec, &TEST_ADDRESS_4KB_REGION);
519 }
520
521 #[test]
522 fn test_find_last_non_zero_bit_in_u8() {
523 use super::find_last_non_zero_bit;
524 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 1);
525 assert_eq!(bit, Some(0));
526
527 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 3);
528 assert_eq!(bit, Some(2));
529
530 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 8);
531 assert_eq!(bit, Some(5));
532
533 let bit = find_last_non_zero_bit::<u8>(0b0, 0, 1);
534 assert_eq!(bit, None);
535 }
536
537 #[test]
538 fn test_align_metadata_address() {
539 let create_spec = |log_num_of_bits: usize| SideMetadataSpec {
540 name: "AlignMetadataBitTestSpec",
541 is_global: true,
542 offset: SideMetadataOffset::addr(GLOBAL_SIDE_METADATA_BASE_ADDRESS),
543 log_num_of_bits,
544 log_bytes_in_region: 3,
545 };
546
547 const ADDR_1000: Address = unsafe { Address::from_usize(0x1000) };
548 const ADDR_1001: Address = unsafe { Address::from_usize(0x1001) };
549 const ADDR_1002: Address = unsafe { Address::from_usize(0x1002) };
550 const ADDR_1003: Address = unsafe { Address::from_usize(0x1003) };
551 const ADDR_1004: Address = unsafe { Address::from_usize(0x1004) };
552 const ADDR_1005: Address = unsafe { Address::from_usize(0x1005) };
553 const ADDR_1006: Address = unsafe { Address::from_usize(0x1006) };
554 const ADDR_1007: Address = unsafe { Address::from_usize(0x1007) };
555 const ADDR_1008: Address = unsafe { Address::from_usize(0x1008) };
556 const ADDR_1009: Address = unsafe { Address::from_usize(0x1009) };
557
558 let metadata_2bits = create_spec(1);
559 assert_eq!(
560 align_metadata_address(&metadata_2bits, ADDR_1000, 0),
561 (ADDR_1000, 0)
562 );
563 assert_eq!(
564 align_metadata_address(&metadata_2bits, ADDR_1000, 1),
565 (ADDR_1000, 0)
566 );
567 assert_eq!(
568 align_metadata_address(&metadata_2bits, ADDR_1000, 2),
569 (ADDR_1000, 2)
570 );
571 assert_eq!(
572 align_metadata_address(&metadata_2bits, ADDR_1000, 3),
573 (ADDR_1000, 2)
574 );
575 assert_eq!(
576 align_metadata_address(&metadata_2bits, ADDR_1000, 4),
577 (ADDR_1000, 4)
578 );
579 assert_eq!(
580 align_metadata_address(&metadata_2bits, ADDR_1000, 5),
581 (ADDR_1000, 4)
582 );
583 assert_eq!(
584 align_metadata_address(&metadata_2bits, ADDR_1000, 6),
585 (ADDR_1000, 6)
586 );
587 assert_eq!(
588 align_metadata_address(&metadata_2bits, ADDR_1000, 7),
589 (ADDR_1000, 6)
590 );
591
592 let metadata_4bits = create_spec(2);
593 assert_eq!(
594 align_metadata_address(&metadata_4bits, ADDR_1000, 0),
595 (ADDR_1000, 0)
596 );
597 assert_eq!(
598 align_metadata_address(&metadata_4bits, ADDR_1000, 1),
599 (ADDR_1000, 0)
600 );
601 assert_eq!(
602 align_metadata_address(&metadata_4bits, ADDR_1000, 2),
603 (ADDR_1000, 0)
604 );
605 assert_eq!(
606 align_metadata_address(&metadata_4bits, ADDR_1000, 3),
607 (ADDR_1000, 0)
608 );
609 assert_eq!(
610 align_metadata_address(&metadata_4bits, ADDR_1000, 4),
611 (ADDR_1000, 4)
612 );
613 assert_eq!(
614 align_metadata_address(&metadata_4bits, ADDR_1000, 5),
615 (ADDR_1000, 4)
616 );
617 assert_eq!(
618 align_metadata_address(&metadata_4bits, ADDR_1000, 6),
619 (ADDR_1000, 4)
620 );
621 assert_eq!(
622 align_metadata_address(&metadata_4bits, ADDR_1000, 7),
623 (ADDR_1000, 4)
624 );
625
626 let metadata_8bits = create_spec(3);
627 assert_eq!(
628 align_metadata_address(&metadata_8bits, ADDR_1000, 0),
629 (ADDR_1000, 0)
630 );
631 assert_eq!(
632 align_metadata_address(&metadata_8bits, ADDR_1000, 1),
633 (ADDR_1000, 0)
634 );
635 assert_eq!(
636 align_metadata_address(&metadata_8bits, ADDR_1000, 2),
637 (ADDR_1000, 0)
638 );
639 assert_eq!(
640 align_metadata_address(&metadata_8bits, ADDR_1000, 3),
641 (ADDR_1000, 0)
642 );
643 assert_eq!(
644 align_metadata_address(&metadata_8bits, ADDR_1000, 4),
645 (ADDR_1000, 0)
646 );
647 assert_eq!(
648 align_metadata_address(&metadata_8bits, ADDR_1000, 5),
649 (ADDR_1000, 0)
650 );
651 assert_eq!(
652 align_metadata_address(&metadata_8bits, ADDR_1000, 6),
653 (ADDR_1000, 0)
654 );
655 assert_eq!(
656 align_metadata_address(&metadata_8bits, ADDR_1000, 7),
657 (ADDR_1000, 0)
658 );
659
660 let metadata_16bits = create_spec(4);
661 assert_eq!(
662 align_metadata_address(&metadata_16bits, ADDR_1000, 0),
663 (ADDR_1000, 0)
664 );
665 assert_eq!(
666 align_metadata_address(&metadata_16bits, ADDR_1000, 1),
667 (ADDR_1000, 0)
668 );
669 assert_eq!(
670 align_metadata_address(&metadata_16bits, ADDR_1000, 2),
671 (ADDR_1000, 0)
672 );
673 assert_eq!(
674 align_metadata_address(&metadata_16bits, ADDR_1000, 3),
675 (ADDR_1000, 0)
676 );
677 assert_eq!(
678 align_metadata_address(&metadata_16bits, ADDR_1000, 4),
679 (ADDR_1000, 0)
680 );
681 assert_eq!(
682 align_metadata_address(&metadata_16bits, ADDR_1000, 5),
683 (ADDR_1000, 0)
684 );
685 assert_eq!(
686 align_metadata_address(&metadata_16bits, ADDR_1000, 6),
687 (ADDR_1000, 0)
688 );
689 assert_eq!(
690 align_metadata_address(&metadata_16bits, ADDR_1000, 7),
691 (ADDR_1000, 0)
692 );
693 assert_eq!(
694 align_metadata_address(&metadata_16bits, ADDR_1001, 0),
695 (ADDR_1000, 0)
696 );
697 assert_eq!(
698 align_metadata_address(&metadata_16bits, ADDR_1001, 1),
699 (ADDR_1000, 0)
700 );
701 assert_eq!(
702 align_metadata_address(&metadata_16bits, ADDR_1001, 2),
703 (ADDR_1000, 0)
704 );
705 assert_eq!(
706 align_metadata_address(&metadata_16bits, ADDR_1001, 3),
707 (ADDR_1000, 0)
708 );
709 assert_eq!(
710 align_metadata_address(&metadata_16bits, ADDR_1001, 4),
711 (ADDR_1000, 0)
712 );
713 assert_eq!(
714 align_metadata_address(&metadata_16bits, ADDR_1001, 5),
715 (ADDR_1000, 0)
716 );
717 assert_eq!(
718 align_metadata_address(&metadata_16bits, ADDR_1001, 6),
719 (ADDR_1000, 0)
720 );
721 assert_eq!(
722 align_metadata_address(&metadata_16bits, ADDR_1001, 7),
723 (ADDR_1000, 0)
724 );
725 }
726}