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_starting_address() + ((data_addr >> log_bytes_in_region) >> shift)
25 } else {
26 metadata_spec.get_starting_address() + ((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_starting_address();
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 should_skip_spec_on_this_target(spec: &SideMetadataSpec) -> bool {
407 use layout::LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO;
408 log_data_meta_ratio(spec) < LOG_GLOBAL_SIDE_METADATA_WORST_CASE_RATIO
409 }
410
411 fn test_round_trip_conversion(spec: &SideMetadataSpec, test_data: &[Address]) {
412 if should_skip_spec_on_this_target(spec) {
413 eprintln!(
414 "Skipping {} on this target: spec ratio is outside global side metadata worst-case bound",
415 spec.name
416 );
417 return;
418 }
419
420 core_test_initialize_side_metadata();
421
422 for ref_addr in test_data {
423 let addr = *ref_addr;
424
425 {
427 assert!(addr.is_aligned_to(1 << spec.log_bytes_in_region));
428 let meta_addr = address_to_contiguous_meta_address(spec, addr);
429 let shift = meta_byte_lshift(spec, addr);
430 assert_eq!(
431 contiguous_meta_address_to_address(spec, meta_addr, shift),
432 addr
433 );
434 }
435
436 {
438 let next_addr = addr + 1usize;
439 let meta_addr = address_to_contiguous_meta_address(spec, next_addr);
440 let shift = meta_byte_lshift(spec, next_addr);
441 assert_eq!(
442 contiguous_meta_address_to_address(spec, meta_addr, shift),
443 addr
444 ); }
446 }
447 }
448
449 const TEST_ADDRESS_8B_REGION: [Address; 8] = [
450 unsafe { Address::from_usize(0x8000_0000) },
451 unsafe { Address::from_usize(0x8000_0008) },
452 unsafe { Address::from_usize(0x8000_0010) },
453 unsafe { Address::from_usize(0x8000_0018) },
454 unsafe { Address::from_usize(0x8000_0020) },
455 unsafe { Address::from_usize(0x8001_0000) },
456 unsafe { Address::from_usize(0x8001_0008) },
457 unsafe { Address::from_usize(0xd000_0000) },
458 ];
459
460 #[test]
461 fn test_contiguous_metadata_conversion_0_3() {
462 let spec = SideMetadataSpec {
463 name: "ContiguousMetadataTestSpec",
464 is_global: true,
465 offset: 0,
466 log_num_of_bits: 0,
467 log_bytes_in_region: 3,
468 };
469
470 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
471 }
472
473 #[test]
474 fn test_contiguous_metadata_conversion_1_3() {
475 let spec = SideMetadataSpec {
476 name: "ContiguousMetadataTestSpec",
477 is_global: true,
478 offset: 0,
479 log_num_of_bits: 1,
480 log_bytes_in_region: 3,
481 };
482
483 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
484 }
485
486 #[test]
487 fn test_contiguous_metadata_conversion_4_3() {
488 let spec = SideMetadataSpec {
489 name: "ContiguousMetadataTestSpec",
490 is_global: true,
491 offset: 0,
492 log_num_of_bits: 4,
493 log_bytes_in_region: 3,
494 };
495
496 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
497 }
498
499 #[test]
500 fn test_contiguous_metadata_conversion_5_3() {
501 let spec = SideMetadataSpec {
502 name: "ContiguousMetadataTestSpec",
503 is_global: true,
504 offset: 0,
505 log_num_of_bits: 5,
506 log_bytes_in_region: 3,
507 };
508
509 test_round_trip_conversion(&spec, &TEST_ADDRESS_8B_REGION);
510 }
511
512 const TEST_ADDRESS_4KB_REGION: [Address; 8] = [
513 unsafe { Address::from_usize(0x8000_0000) },
514 unsafe { Address::from_usize(0x8000_1000) },
515 unsafe { Address::from_usize(0x8000_2000) },
516 unsafe { Address::from_usize(0x8000_3000) },
517 unsafe { Address::from_usize(0x8000_4000) },
518 unsafe { Address::from_usize(0x8001_0000) },
519 unsafe { Address::from_usize(0x8001_1000) },
520 unsafe { Address::from_usize(0xd000_0000) },
521 ];
522
523 #[test]
524 fn test_contiguous_metadata_conversion_0_12() {
525 let spec = SideMetadataSpec {
526 name: "ContiguousMetadataTestSpec",
527 is_global: true,
528 offset: 0,
529 log_num_of_bits: 0,
530 log_bytes_in_region: 12, };
532
533 test_round_trip_conversion(&spec, &TEST_ADDRESS_4KB_REGION);
534 }
535
536 #[test]
537 fn test_find_last_non_zero_bit_in_u8() {
538 use super::find_last_non_zero_bit;
539 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 1);
540 assert_eq!(bit, Some(0));
541
542 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 3);
543 assert_eq!(bit, Some(2));
544
545 let bit = find_last_non_zero_bit::<u8>(0b100101, 0, 8);
546 assert_eq!(bit, Some(5));
547
548 let bit = find_last_non_zero_bit::<u8>(0b0, 0, 1);
549 assert_eq!(bit, None);
550 }
551
552 #[test]
553 fn test_align_metadata_address() {
554 let create_spec = |log_num_of_bits: usize| SideMetadataSpec {
555 name: "AlignMetadataBitTestSpec",
556 is_global: true,
557 offset: 0,
558 log_num_of_bits,
559 log_bytes_in_region: 3,
560 };
561
562 const ADDR_1000: Address = unsafe { Address::from_usize(0x1000) };
563 const ADDR_1001: Address = unsafe { Address::from_usize(0x1001) };
564 const ADDR_1002: Address = unsafe { Address::from_usize(0x1002) };
565 const ADDR_1003: Address = unsafe { Address::from_usize(0x1003) };
566 const ADDR_1004: Address = unsafe { Address::from_usize(0x1004) };
567 const ADDR_1005: Address = unsafe { Address::from_usize(0x1005) };
568 const ADDR_1006: Address = unsafe { Address::from_usize(0x1006) };
569 const ADDR_1007: Address = unsafe { Address::from_usize(0x1007) };
570 const ADDR_1008: Address = unsafe { Address::from_usize(0x1008) };
571 const ADDR_1009: Address = unsafe { Address::from_usize(0x1009) };
572
573 let metadata_2bits = create_spec(1);
574 assert_eq!(
575 align_metadata_address(&metadata_2bits, ADDR_1000, 0),
576 (ADDR_1000, 0)
577 );
578 assert_eq!(
579 align_metadata_address(&metadata_2bits, ADDR_1000, 1),
580 (ADDR_1000, 0)
581 );
582 assert_eq!(
583 align_metadata_address(&metadata_2bits, ADDR_1000, 2),
584 (ADDR_1000, 2)
585 );
586 assert_eq!(
587 align_metadata_address(&metadata_2bits, ADDR_1000, 3),
588 (ADDR_1000, 2)
589 );
590 assert_eq!(
591 align_metadata_address(&metadata_2bits, ADDR_1000, 4),
592 (ADDR_1000, 4)
593 );
594 assert_eq!(
595 align_metadata_address(&metadata_2bits, ADDR_1000, 5),
596 (ADDR_1000, 4)
597 );
598 assert_eq!(
599 align_metadata_address(&metadata_2bits, ADDR_1000, 6),
600 (ADDR_1000, 6)
601 );
602 assert_eq!(
603 align_metadata_address(&metadata_2bits, ADDR_1000, 7),
604 (ADDR_1000, 6)
605 );
606
607 let metadata_4bits = create_spec(2);
608 assert_eq!(
609 align_metadata_address(&metadata_4bits, ADDR_1000, 0),
610 (ADDR_1000, 0)
611 );
612 assert_eq!(
613 align_metadata_address(&metadata_4bits, ADDR_1000, 1),
614 (ADDR_1000, 0)
615 );
616 assert_eq!(
617 align_metadata_address(&metadata_4bits, ADDR_1000, 2),
618 (ADDR_1000, 0)
619 );
620 assert_eq!(
621 align_metadata_address(&metadata_4bits, ADDR_1000, 3),
622 (ADDR_1000, 0)
623 );
624 assert_eq!(
625 align_metadata_address(&metadata_4bits, ADDR_1000, 4),
626 (ADDR_1000, 4)
627 );
628 assert_eq!(
629 align_metadata_address(&metadata_4bits, ADDR_1000, 5),
630 (ADDR_1000, 4)
631 );
632 assert_eq!(
633 align_metadata_address(&metadata_4bits, ADDR_1000, 6),
634 (ADDR_1000, 4)
635 );
636 assert_eq!(
637 align_metadata_address(&metadata_4bits, ADDR_1000, 7),
638 (ADDR_1000, 4)
639 );
640
641 let metadata_8bits = create_spec(3);
642 assert_eq!(
643 align_metadata_address(&metadata_8bits, ADDR_1000, 0),
644 (ADDR_1000, 0)
645 );
646 assert_eq!(
647 align_metadata_address(&metadata_8bits, ADDR_1000, 1),
648 (ADDR_1000, 0)
649 );
650 assert_eq!(
651 align_metadata_address(&metadata_8bits, ADDR_1000, 2),
652 (ADDR_1000, 0)
653 );
654 assert_eq!(
655 align_metadata_address(&metadata_8bits, ADDR_1000, 3),
656 (ADDR_1000, 0)
657 );
658 assert_eq!(
659 align_metadata_address(&metadata_8bits, ADDR_1000, 4),
660 (ADDR_1000, 0)
661 );
662 assert_eq!(
663 align_metadata_address(&metadata_8bits, ADDR_1000, 5),
664 (ADDR_1000, 0)
665 );
666 assert_eq!(
667 align_metadata_address(&metadata_8bits, ADDR_1000, 6),
668 (ADDR_1000, 0)
669 );
670 assert_eq!(
671 align_metadata_address(&metadata_8bits, ADDR_1000, 7),
672 (ADDR_1000, 0)
673 );
674
675 let metadata_16bits = create_spec(4);
676 assert_eq!(
677 align_metadata_address(&metadata_16bits, ADDR_1000, 0),
678 (ADDR_1000, 0)
679 );
680 assert_eq!(
681 align_metadata_address(&metadata_16bits, ADDR_1000, 1),
682 (ADDR_1000, 0)
683 );
684 assert_eq!(
685 align_metadata_address(&metadata_16bits, ADDR_1000, 2),
686 (ADDR_1000, 0)
687 );
688 assert_eq!(
689 align_metadata_address(&metadata_16bits, ADDR_1000, 3),
690 (ADDR_1000, 0)
691 );
692 assert_eq!(
693 align_metadata_address(&metadata_16bits, ADDR_1000, 4),
694 (ADDR_1000, 0)
695 );
696 assert_eq!(
697 align_metadata_address(&metadata_16bits, ADDR_1000, 5),
698 (ADDR_1000, 0)
699 );
700 assert_eq!(
701 align_metadata_address(&metadata_16bits, ADDR_1000, 6),
702 (ADDR_1000, 0)
703 );
704 assert_eq!(
705 align_metadata_address(&metadata_16bits, ADDR_1000, 7),
706 (ADDR_1000, 0)
707 );
708 assert_eq!(
709 align_metadata_address(&metadata_16bits, ADDR_1001, 0),
710 (ADDR_1000, 0)
711 );
712 assert_eq!(
713 align_metadata_address(&metadata_16bits, ADDR_1001, 1),
714 (ADDR_1000, 0)
715 );
716 assert_eq!(
717 align_metadata_address(&metadata_16bits, ADDR_1001, 2),
718 (ADDR_1000, 0)
719 );
720 assert_eq!(
721 align_metadata_address(&metadata_16bits, ADDR_1001, 3),
722 (ADDR_1000, 0)
723 );
724 assert_eq!(
725 align_metadata_address(&metadata_16bits, ADDR_1001, 4),
726 (ADDR_1000, 0)
727 );
728 assert_eq!(
729 align_metadata_address(&metadata_16bits, ADDR_1001, 5),
730 (ADDR_1000, 0)
731 );
732 assert_eq!(
733 align_metadata_address(&metadata_16bits, ADDR_1001, 6),
734 (ADDR_1000, 0)
735 );
736 assert_eq!(
737 align_metadata_address(&metadata_16bits, ADDR_1001, 7),
738 (ADDR_1000, 0)
739 );
740 }
741}