1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause

//! Contains a generic implementation of `BitmapSlice`.

use std::fmt::{self, Debug};
use std::ops::Deref;
use std::sync::Arc;

use crate::bitmap::{Bitmap, BitmapSlice, WithBitmapSlice};

/// Represents a slice into a `Bitmap` object, starting at `base_offset`.
#[derive(Clone, Copy)]
pub struct BaseSlice<B> {
    inner: B,
    base_offset: usize,
}

impl<B> BaseSlice<B> {
    /// Create a new `BitmapSlice`, starting at the specified `offset`.
    pub fn new(inner: B, offset: usize) -> Self {
        BaseSlice {
            inner,
            base_offset: offset,
        }
    }
}

impl<'a, B> WithBitmapSlice<'a> for BaseSlice<B>
where
    B: Clone + Deref,
    B::Target: Bitmap,
{
    type S = Self;
}

impl<B> BitmapSlice for BaseSlice<B>
where
    B: Clone + Deref,
    B::Target: Bitmap,
{
}

impl<B> Bitmap for BaseSlice<B>
where
    B: Clone + Deref,
    B::Target: Bitmap,
{
    /// Mark the memory range specified by the given `offset` (relative to the base offset of
    /// the slice) and `len` as dirtied.
    fn mark_dirty(&self, offset: usize, len: usize) {
        // The `Bitmap` operations are supposed to accompany guest memory accesses defined by the
        // same parameters (i.e. offset & length), so we use simple wrapping arithmetic instead of
        // performing additional checks. If an overflow would occur, we simply end up marking some
        // other region as dirty (which is just a false positive) instead of a region that could
        // not have been accessed to begin with.
        self.inner
            .mark_dirty(self.base_offset.wrapping_add(offset), len)
    }

    fn dirty_at(&self, offset: usize) -> bool {
        self.inner.dirty_at(self.base_offset.wrapping_add(offset))
    }

    /// Create a new `BitmapSlice` starting from the specified `offset` into the current slice.
    fn slice_at(&self, offset: usize) -> Self {
        BaseSlice {
            inner: self.inner.clone(),
            base_offset: self.base_offset.wrapping_add(offset),
        }
    }
}

impl<B> Debug for BaseSlice<B> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Dummy impl for now.
        write!(f, "(bitmap slice)")
    }
}

impl<B: Default> Default for BaseSlice<B> {
    fn default() -> Self {
        BaseSlice {
            inner: B::default(),
            base_offset: 0,
        }
    }
}

/// A `BitmapSlice` implementation that wraps a reference to a `Bitmap` object.
pub type RefSlice<'a, B> = BaseSlice<&'a B>;

/// A `BitmapSlice` implementation that uses an `Arc` handle to a `Bitmap` object.
pub type ArcSlice<B> = BaseSlice<Arc<B>>;

#[cfg(test)]
mod tests {
    use super::*;

    use crate::bitmap::tests::{range_is_clean, range_is_dirty, test_bitmap};
    use crate::bitmap::AtomicBitmap;
    use std::num::NonZeroUsize;

    #[test]
    fn test_slice() {
        let bitmap_size = 0x1_0000;
        let dirty_offset = 0x1000;
        let dirty_len = 0x100;

        {
            let bitmap = AtomicBitmap::new(bitmap_size, NonZeroUsize::MIN);
            let slice1 = bitmap.slice_at(0);
            let slice2 = bitmap.slice_at(dirty_offset);

            assert!(range_is_clean(&slice1, 0, bitmap_size));
            assert!(range_is_clean(&slice2, 0, dirty_len));

            bitmap.mark_dirty(dirty_offset, dirty_len);

            assert!(range_is_dirty(&slice1, dirty_offset, dirty_len));
            assert!(range_is_dirty(&slice2, 0, dirty_len));
        }

        {
            let bitmap = AtomicBitmap::new(bitmap_size, NonZeroUsize::MIN);
            let slice = bitmap.slice_at(0);
            test_bitmap(&slice);
        }
    }
}