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
pub mod block;
pub mod defrag;
pub mod immixspace;
pub mod line;

pub use immixspace::*;

use crate::policy::immix::block::Block;
use crate::util::linear_scan::Region;

/// The max object size for immix: half of a block
pub const MAX_IMMIX_OBJECT_SIZE: usize = Block::BYTES >> 1;

/// Mark/sweep memory for block-level only
pub const BLOCK_ONLY: bool = false;

/// Do we allow Immix to do defragmentation?
pub const DEFRAG: bool = !cfg!(feature = "immix_non_moving"); // defrag if we are allowed to move.

// STRESS COPYING: Set the feature 'immix_stress_copying' so that Immix will copy as many objects as possible.
// Useful for debugging copying GC if you cannot use SemiSpace.
//
// | constant                  | when    | value   | comment                                                              |
// |---------------------------|---------|---------|----------------------------------------------------------------------|
// | `STRESS_DEFRAG`           | default | `false` | By default, Immix only does defrag GC when necessary.                |
// | `STRESS_DEFRAG`           | stress  | `true`  | Set to `true` to force every GC to be defrag GC.                     |
// |                           |         |         |                                                                      |
// | `DEFRAG_EVERY_BLOCK`      | default | `false` | By default, Immix only defrags the most heavily fragmented blocks.   |
// | `DEFRAG_EVERY_BLOCK`      | stress  | `true`  | Set to `true` to make every block a defrag source.                   |
// |                           |         |         |                                                                      |
// | `DEFRAG_HEADROOM_PERCENT` | default | `2`     | Immix stops copying when space exhausted.                            |
// | `DEFRAG_HEADROOM_PERCENT` | stress  | `50`    | Reserve enough headroom to copy all objects.  50% is like SemiSpace. |

/// Make every GC a defragment GC. (for debugging)
pub const STRESS_DEFRAG: bool = cfg!(feature = "immix_stress_copying");

/// Mark every allocated block as defragmentation source before GC. (for debugging)
pub const DEFRAG_EVERY_BLOCK: bool = cfg!(feature = "immix_stress_copying");

/// Percentage of heap size reserved for defragmentation.
/// According to [this paper](https://doi.org/10.1145/1375581.1375586), Immix works well with
/// headroom between 1% to 3% of the heap size.
pub const DEFRAG_HEADROOM_PERCENT: usize = if cfg!(feature = "immix_stress_copying") {
    50
} else {
    2
};

/// If Immix is used as a nursery space, do we prefer copy?
pub const PREFER_COPY_ON_NURSERY_GC: bool =
    !cfg!(feature = "immix_non_moving") && !cfg!(feature = "sticky_immix_non_moving_nursery"); // copy nursery objects if we are allowed to move.

/// In some cases/settings, Immix may never move objects.
/// Currently we only have two cases where we move objects: 1. defrag, 2. nursery copy.
/// If we do neither, we will not move objects.
/// If we have other reasons to move objects, we need to add them here.
pub const NEVER_MOVE_OBJECTS: bool = !DEFRAG && !PREFER_COPY_ON_NURSERY_GC;

/// Mark lines when scanning objects.
/// Otherwise, do it at mark time.
pub const MARK_LINE_AT_SCAN_TIME: bool = true;

macro_rules! validate {
    ($x: expr) => { assert!($x, stringify!($x)) };
    ($x: expr => $y: expr) => { if $x { assert!($y, stringify!($x implies $y)) } };
}

fn validate_features() {
    // Block-only immix cannot do defragmentation
    validate!(DEFRAG => !BLOCK_ONLY);
    // Number of lines in a block should not exceed BlockState::MARK_MARKED
    assert!(Block::LINES / 2 <= u8::MAX as usize - 2);
}