mod.rs 3.98 KB
Newer Older
qinsoon's avatar
qinsoon committed
1 2 3 4
use utils::Address;
use heap::immix;
use heap::gc;
use aligned_alloc;
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

use std::collections::LinkedList;
use std::sync::Arc;
use std::sync::RwLock;

pub struct FreeListSpace {
    current_nodes : LinkedList<Box<FreeListNode>>,
    
    node_id: usize,
    
    size       : usize,
    used_bytes : usize
}

impl FreeListSpace {
    pub fn new(size: usize) -> FreeListSpace {
        FreeListSpace {
            current_nodes: LinkedList::new(),
            node_id: 0,
            size: size,
            used_bytes: 0
        }
    }
    
    #[allow(unused_variables)]
    pub fn mark(&mut self, obj: Address) {
        
    }
    
    pub fn alloc(&mut self, size: usize, align: usize) -> Option<Address> {
        if self.used_bytes + size > self.size {
            None
        } else {
qinsoon's avatar
qinsoon committed
38
            let ret = aligned_alloc::aligned_alloc(size, align);
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
            
            let addr = Address::from_ptr::<()>(ret);
            
            self.current_nodes.push_front(Box::new(FreeListNode{id: self.node_id, start: addr, size: size, mark: NodeMark::FreshAlloc}));
            self.node_id += 1;
            self.used_bytes += size;
            
            Some(addr)
        }
    }
    
    pub fn sweep(&mut self) {
        let (new_nodes, new_used_bytes) = {
            let mut ret = LinkedList::new();
            let nodes = &mut self.current_nodes;
            let mut used_bytes = 0;
            
            while !nodes.is_empty() {
                let mut node = nodes.pop_front().unwrap();
                match node.mark {
                    NodeMark::Live => {
                        node.set_mark(NodeMark::PrevLive);
                        used_bytes += node.size;
                        ret.push_back(node);
                    },
                    NodeMark::PrevLive | NodeMark::FreshAlloc => {
                        let ptr = node.start.to_ptr::<()>() as *mut ();
                        // free the memory
qinsoon's avatar
qinsoon committed
67
                        unsafe {aligned_alloc::aligned_free(ptr);}
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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
                        // do not add this node into new linked list
                    }
                }
            }
            
            (ret, used_bytes)
        };
        
        self.current_nodes = new_nodes;
        self.used_bytes = new_used_bytes;        
    }
    
    pub fn current_nodes(&self) -> &LinkedList<Box<FreeListNode>> {
        &self.current_nodes
    }
    pub fn current_nodes_mut(&mut self) -> &mut LinkedList<Box<FreeListNode>> {
        &mut self.current_nodes
    }
}

pub struct FreeListNode {
    id: usize,
    start : Address,
    size  : usize,
    mark  : NodeMark
}

impl FreeListNode {
    pub fn set_mark(&mut self, mark: NodeMark) {
        self.mark = mark;
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum NodeMark {
    FreshAlloc,
    PrevLive,
    Live,
}
unsafe impl Sync for NodeMark {}

#[inline(never)]
pub fn alloc_large(size: usize, align: usize, mutator: &mut immix::ImmixMutatorLocal, space: Arc<RwLock<FreeListSpace>>) -> Address {
    loop {
        mutator.yieldpoint();
        
        let ret_addr = {
            let mut lo_space_lock = space.write().unwrap();            
            lo_space_lock.alloc(size, align)
        };
        
        match ret_addr {
            Some(addr) => {
                return addr;
            },
            None => {
                gc::trigger_gc();
            }
        }
    }
}

use std::fmt;

impl fmt::Display for FreeListSpace {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FreeListSpace\n").unwrap();
        write!(f, "{} used, {} total\n", self.used_bytes, self.size).unwrap();
        write!(f, "nodes:\n").unwrap();
        
        for node in self.current_nodes() {
            write!(f, "  {}\n", node).unwrap();
        }
        
        write!(f, "done\n")
    }
}

impl fmt::Display for FreeListNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FreeListNode#{}(start={:#X}, size={}, state={:?})", self.id, self.start, self.size, self.mark)
    }
}