<commit_before>use crate::stream::{Fuse, FuturesUnordered};
use futures_core::future::Future;
use futures_core::stream::Stream;
use futures_core::task::{LocalWaker, Poll};
use futures_sink::Sink;
use pin_utils::{unsafe_pinned, unsafe_unpinned};
use std::fmt;
use std::marker::Unpin;
use std::pin::Pin;

/// An adaptor for a stream of futures to execute the futures concurrently, if
/// possible, delivering results as they become available.
///
/// This adaptor will buffer up a list of pending futures, and then return their
/// results in the order that they complete. This is created by the
/// `Stream::buffer_unordered` method.
#[must_use = "streams do nothing unless polled"]
pub struct BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    stream: Fuse<St>,
    in_progress_queue: FuturesUnordered<St::Item>,
    max: usize,
}

impl<St> Unpin for BufferUnordered<St>
where
    St: Stream + Unpin,
    St::Item: Future,
{}

impl<St> fmt::Debug for BufferUnordered<St>
where
    St: Stream + fmt::Debug,
    St::Item: Future,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("BufferUnordered")
            .field("stream", &self.stream)
            .field("in_progress_queue", &self.in_progress_queue)
            .field("max", &self.max)
            .finish()
    }
}

impl<St> BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    unsafe_pinned!(stream: Fuse<St>);
    unsafe_unpinned!(in_progress_queue: FuturesUnordered<St::Item>);

    pub(super) fn new(stream: St, n: usize) -> BufferUnordered<St>
    where
        St: Stream,
        St::Item: Future,
    {
        BufferUnordered {
            stream: super::Fuse::new(stream),
            in_progress_queue: FuturesUnordered::new(),
            max: n,
        }
    }

    /// Acquires a reference to the underlying stream that this combinator is
    /// pulling from.
    pub fn get_ref(&self) -> &St {
        self.stream.get_ref()
    }

    /// Acquires a mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    pub fn get_mut(&mut self) -> &mut St {
        self.stream.get_mut()
    }

    /// Acquires a pinned mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    #[allow(clippy::needless_lifetimes)] // https://github.com/rust-lang/rust/issues/52675
    pub fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut St> {
        unsafe { Pin::map_unchecked_mut(self, |x| x.get_mut()) }
    }

    /// Consumes this combinator, returning the underlying stream.
    ///
    /// Note that this may discard intermediate state of this combinator, so
    /// care should be taken to avoid losing resources when this is called.
    pub fn into_inner(self) -> St {
        self.stream.into_inner()
    }
}

impl<St> Stream for BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    type Item = <St::Item as Future>::Output;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<Self::Item>> {
        // First up, try to spawn off as many futures as possible by filling up
        // our slab of futures.
        while self.in_progress_queue.len() < self.max {
            match self.stream().poll_next(lw) {
                Poll::Ready(Some(fut)) => self.in_progress_queue().push(fut),
                Poll::Ready(None) | Poll::Pending => break,
            }
        }

        // Attempt to pull the next value from the in_progress_queue
        match Pin::new(self.in_progress_queue()).poll_next(lw) {
            x @ Poll::Pending | x @ Poll::Ready(Some(_)) => return x,
            Poll::Ready(None) => {}
        }

        // If more values are still coming from the stream, we're not done yet
        if self.stream.is_done() {
            Poll::Ready(None)
        } else {
            Poll::Pending
        }
    }
}

// Forwarding impl of Sink from the underlying stream
impl<S> Sink for BufferUnordered<S>
where
    S: Stream + Sink,
    S::Item: Future,
{
    type SinkItem = S::SinkItem;
    type SinkError = S::SinkError;

    delegate_sink!(stream);
}
<commit_msg>Readd FusedStream for BufferUnordered<commit_after>use crate::stream::{Fuse, FuturesUnordered};
use futures_core::future::Future;
use futures_core::stream::{Stream, FusedStream};
use futures_core::task::{LocalWaker, Poll};
use futures_sink::Sink;
use pin_utils::{unsafe_pinned, unsafe_unpinned};
use std::fmt;
use std::marker::Unpin;
use std::pin::Pin;

/// An adaptor for a stream of futures to execute the futures concurrently, if
/// possible, delivering results as they become available.
///
/// This adaptor will buffer up a list of pending futures, and then return their
/// results in the order that they complete. This is created by the
/// `Stream::buffer_unordered` method.
#[must_use = "streams do nothing unless polled"]
pub struct BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    stream: Fuse<St>,
    in_progress_queue: FuturesUnordered<St::Item>,
    max: usize,
}

impl<St> Unpin for BufferUnordered<St>
where
    St: Stream + Unpin,
    St::Item: Future,
{}

impl<St> fmt::Debug for BufferUnordered<St>
where
    St: Stream + fmt::Debug,
    St::Item: Future,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("BufferUnordered")
            .field("stream", &self.stream)
            .field("in_progress_queue", &self.in_progress_queue)
            .field("max", &self.max)
            .finish()
    }
}

impl<St> BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    unsafe_pinned!(stream: Fuse<St>);
    unsafe_unpinned!(in_progress_queue: FuturesUnordered<St::Item>);

    pub(super) fn new(stream: St, n: usize) -> BufferUnordered<St>
    where
        St: Stream,
        St::Item: Future,
    {
        BufferUnordered {
            stream: super::Fuse::new(stream),
            in_progress_queue: FuturesUnordered::new(),
            max: n,
        }
    }

    /// Acquires a reference to the underlying stream that this combinator is
    /// pulling from.
    pub fn get_ref(&self) -> &St {
        self.stream.get_ref()
    }

    /// Acquires a mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    pub fn get_mut(&mut self) -> &mut St {
        self.stream.get_mut()
    }

    /// Acquires a pinned mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    #[allow(clippy::needless_lifetimes)] // https://github.com/rust-lang/rust/issues/52675
    pub fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut St> {
        unsafe { Pin::map_unchecked_mut(self, |x| x.get_mut()) }
    }

    /// Consumes this combinator, returning the underlying stream.
    ///
    /// Note that this may discard intermediate state of this combinator, so
    /// care should be taken to avoid losing resources when this is called.
    pub fn into_inner(self) -> St {
        self.stream.into_inner()
    }
}

impl<St> Stream for BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    type Item = <St::Item as Future>::Output;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<Self::Item>> {
        // First up, try to spawn off as many futures as possible by filling up
        // our slab of futures.
        while self.in_progress_queue.len() < self.max {
            match self.stream().poll_next(lw) {
                Poll::Ready(Some(fut)) => self.in_progress_queue().push(fut),
                Poll::Ready(None) | Poll::Pending => break,
            }
        }

        // Attempt to pull the next value from the in_progress_queue
        match Pin::new(self.in_progress_queue()).poll_next(lw) {
            x @ Poll::Pending | x @ Poll::Ready(Some(_)) => return x,
            Poll::Ready(None) => {}
        }

        // If more values are still coming from the stream, we're not done yet
        if self.stream.is_done() {
            Poll::Ready(None)
        } else {
            Poll::Pending
        }
    }
}

impl<St> FusedStream for BufferUnordered<St>
where
    St: Stream,
    St::Item: Future,
{
    fn is_terminated(&self) -> bool {
        self.in_progress_queue.is_terminated() && self.stream.is_terminated()
    }
}

// Forwarding impl of Sink from the underlying stream
impl<S> Sink for BufferUnordered<S>
where
    S: Stream + Sink,
    S::Item: Future,
{
    type SinkItem = S::SinkItem;
    type SinkError = S::SinkError;

    delegate_sink!(stream);
}
<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

mod rc_collector;
mod immix_collector;

use self::rc_collector::RCCollector;
use self::immix_collector::ImmixCollector;

use spaces::immix_space::BlockInfo;
use spaces::immix_space::ImmixSpace;
use spaces::large_object_space::LargeObjectSpace;

use std::collections::{HashSet, VecMap};

use constants::{NUM_LINES_PER_BLOCK, USE_RC_COLLECTOR, USE_EVACUATION,
                EVAC_HEADROOM, CICLE_TRIGGER_THRESHHOLD, EVAC_TRIGGER_THRESHHOLD};
use gc_object::GCObjectRef;
use spaces::CollectionType;

/// The `Collector` is a composition of the collection implementations
/// `RCCollector` and `ImmixCollector`.
///
/// It manages performs common tasks and manages the cooperation between the
/// two collectors.
pub struct Collector {
    /// The reference counting collector.
    rc_collector: RCCollector,

    /// A buffer to store all managed blocks during collection.
    all_blocks: Vec<*mut BlockInfo>,

    /// A global backup of the object map.
    ///
    /// This is only used, if the library is compiled with `Valgrind` support
    /// and needed for accurate marking of addresses as `malloclike_block` and
    /// `freelike_block`.
    object_map_backup: HashSet<GCObjectRef>,

    /// The mark histogram used during collection to calculate the required
    /// space for evacuation.
    mark_histogram: VecMap<usize>,
}

impl Collector {
    /// Create a new `Collector`.
    pub fn new() -> Collector {
        return Collector {
            rc_collector: RCCollector::new(),
            all_blocks: Vec::new(),
            object_map_backup: HashSet::new(),
            mark_histogram: VecMap::with_capacity(NUM_LINES_PER_BLOCK),
        };
    }

    /// A write barrier for the given `object` used with the `RCCollector`.
    pub fn write_barrier(&mut self, object: GCObjectRef) {
        if USE_RC_COLLECTOR {
            self.rc_collector.write_barrier(object);
        }
    }

    /// Store the given blocks into the buffer for use during the collection.
    pub fn extend_all_blocks(&mut self, blocks: Vec<*mut BlockInfo>) {
        self.all_blocks.extend(blocks.into_iter());
    }

    /// Prepare a collection.
    ///
    /// This function decides if a evacuating and/or cycle collecting
    /// collection will be performed. If `evacuation` is set the collectors
    /// will try to evacuate. If `cycle_collect` is set the immix tracing
    /// collector will be used.
    pub fn prepare_collection(&mut self, evacuation: bool, cycle_collect: bool,
                              available_blocks: usize, total_blocks: usize,
                              evac_headroom: usize) -> CollectionType {
        let mut perform_evac = evacuation;

        let evac_threshhold = ((total_blocks as f32) * EVAC_TRIGGER_THRESHHOLD) as usize;
        let available_evac_blocks = available_blocks + evac_headroom;
        if evacuation || available_evac_blocks < evac_threshhold {
            let hole_threshhold = self.establish_hole_threshhold(evac_headroom);
            perform_evac = USE_EVACUATION && hole_threshhold > 0
                                          && hole_threshhold < NUM_LINES_PER_BLOCK;
            if perform_evac {
                debug!("Performing evacuation with hole_threshhold={} and evac_headroom={}",
                       hole_threshhold, evac_headroom);
                for block in self.all_blocks.iter_mut() {
                    unsafe{ (**block).set_evacuation_candidate(hole_threshhold); }
                }
            }
        }

        let perform_cycle_collect = if !cycle_collect {
            let cycle_theshold = ((total_blocks as f32) * CICLE_TRIGGER_THRESHHOLD) as usize;
            available_blocks < cycle_theshold
        } else { true };

        return match (USE_RC_COLLECTOR, perform_evac, perform_cycle_collect) {
            (true, false, false) => CollectionType::RCCollection,
            (true, true, false) => CollectionType::RCEvacCollection,
            (true, false, true) => CollectionType::ImmixCollection,
            (true, true, true) => CollectionType::ImmixEvacCollection,
            (false, false, _) => CollectionType::ImmixCollection,
            (false, true, _) => CollectionType::ImmixEvacCollection,
        }
    }

    /// Perform the collection.
    ///
    /// See `Spaces.collect() how it is called.`
    pub fn collect(&mut self, collection_type: &CollectionType,
                   roots: &[GCObjectRef], immix_space: &mut ImmixSpace,
                   large_object_space: &mut LargeObjectSpace, next_live_mark: bool) {

        if USE_RC_COLLECTOR {
            self.perform_rc_collection(collection_type, roots, immix_space,
                                       large_object_space);
        }

        if collection_type.is_immix() {
            self.perform_immix_collection(collection_type, roots,
                                          immix_space, next_live_mark);
        }
    }

    /// Perform the reference counting collection.
    fn perform_rc_collection(&mut self, collection_type: &CollectionType,
                             roots: &[GCObjectRef],
                             immix_space: &mut ImmixSpace,
                             large_object_space: &mut LargeObjectSpace) {
        if cfg!(feature = "valgrind") {
            for block in self.all_blocks.iter_mut() {
                let block_new_objects = unsafe{ (**block).get_new_objects() };
                self.object_map_backup.extend(block_new_objects.into_iter());
            }
        }

        for block in self.all_blocks.iter_mut() {
            unsafe{ (**block).remove_new_objects_from_map(); }
        }

        self.rc_collector.collect(collection_type, roots, immix_space, large_object_space);

        large_object_space.proccess_free_buffer();

        if cfg!(feature = "valgrind") {
            let mut object_map = HashSet::new();
            for block in self.all_blocks.iter_mut() {
                let block_object_map = unsafe{ (**block).get_object_map() };
                object_map.extend(block_object_map.into_iter());
            }
            for &object in self.object_map_backup.difference(&object_map) {
                valgrind_freelike!(object);
            }
            self.object_map_backup.clear();
        }
    }

    /// Perform the immix tracing collection.
    pub fn perform_immix_collection(&mut self, collection_type: &CollectionType,
                                    roots: &[GCObjectRef],
                                    immix_space: &mut ImmixSpace,
                                    next_live_mark: bool) {
        if cfg!(feature = "valgrind") {
            for block in self.all_blocks.iter_mut() {
                let block_object_map = unsafe{ (**block).get_object_map() };
                self.object_map_backup.extend(block_object_map.into_iter());
            }
        }

        for block in self.all_blocks.iter_mut() {
            unsafe{ (**block).clear_line_counts(); }
            unsafe{ (**block).clear_object_map(); }
        }

        ImmixCollector::collect(collection_type, roots, immix_space, next_live_mark);

        if cfg!(feature = "valgrind") {
            let mut object_map = HashSet::new();
            for block in self.all_blocks.iter_mut() {
                let block_object_map = unsafe{ (**block).get_object_map() };
                object_map.extend(block_object_map.into_iter());
            }
            for &object in self.object_map_backup.difference(&object_map) {
                valgrind_freelike!(object);
            }
            self.object_map_backup.clear();
        }
    }

    /// Complete the collection.
    pub fn complete_collection(&mut self, collection_type: &CollectionType,
                               immix_space: &mut ImmixSpace,
                               large_object_space: &mut LargeObjectSpace) {
        self.mark_histogram.clear();
        let (recyclable_blocks, free_blocks) = self.sweep_all_blocks();
        immix_space.set_recyclable_blocks(recyclable_blocks);

        // XXX We should not use a constant here, but something that
        // XXX changes dynamically (see rcimmix: MAX heuristic).
        let evac_headroom = if USE_EVACUATION {
            EVAC_HEADROOM - immix_space.evac_headroom() } else { 0 };
        immix_space.extend_evac_headroom(free_blocks.iter().take(evac_headroom)
                                                    .map(|&b| b).collect());
        immix_space.return_blocks(free_blocks.iter().skip(evac_headroom)
                                             .map(|&b| b).collect());

        if collection_type.is_immix() {
            large_object_space.sweep()
        }
    }
}

impl Collector {
    /// Sweep all blocks in the buffer after the collection.
    ///
    /// This function returns a list of recyclable blocks and a list of free
    /// blocks.
    fn sweep_all_blocks(&mut self) -> (Vec<*mut BlockInfo>, Vec<*mut BlockInfo>){
        let mut unavailable_blocks = Vec::new();
        let mut recyclable_blocks = Vec::new();
        let mut free_blocks = Vec::new();
        for block in self.all_blocks.drain() {
            if unsafe{ (*block).is_empty() } {
                if cfg!(feature = "valgrind") {
                    let block_object_map = unsafe{ (*block).get_object_map() };
                    for &object in block_object_map.iter() {
                        valgrind_freelike!(object);
                    }
                }
                unsafe{ (*block).reset() ;}
                debug!("Push block {:p} into free_blocks", block);
                free_blocks.push(block);
            } else {
                unsafe{ (*block).count_holes(); }
                let (holes, marked_lines) = unsafe{ (*block).count_holes_and_marked_lines() };
                if self.mark_histogram.contains_key(&(holes as usize)) {
                    if let Some(val) = self.mark_histogram.get_mut(&(holes as usize)) {
                        *val += marked_lines;
                    }
                } else { self.mark_histogram.insert(holes as usize, marked_lines); }
                debug!("Found {} holes and {} marked lines in block {:p}",
                       holes, marked_lines, block);
                match holes {
                    0 => {
                        debug!("Push block {:p} into unavailable_blocks", block);
                        unavailable_blocks.push(block);
                    },
                    _ => {
                        debug!("Push block {:p} into recyclable_blocks", block);
                        recyclable_blocks.push(block);
                    }
                }
            }
        }
        self.all_blocks = unavailable_blocks;
        return (recyclable_blocks, free_blocks);
    }

    /// Calculate how many holes a block needs to have to be selected as a
    /// evacuation candidate.
    fn establish_hole_threshhold(&self, evac_headroom: usize) -> usize {
        let mut available_histogram : VecMap<usize> = VecMap::with_capacity(NUM_LINES_PER_BLOCK);
        for block in self.all_blocks.iter() {
            let (holes, free_lines) = unsafe{ (**block).count_holes_and_available_lines() };
            if available_histogram.contains_key(&(holes as usize)) {
                if let Some(val) = available_histogram.get_mut(&(holes as usize)) {
                    *val += free_lines;
                }
            } else { available_histogram.insert(holes as usize, free_lines); }
        }
        let mut required_lines = 0;
        let mut available_lines = evac_headroom * (NUM_LINES_PER_BLOCK - 1);

        for threshold in (0..NUM_LINES_PER_BLOCK) {
            required_lines += *self.mark_histogram.get(&threshold).unwrap_or(&0);
            available_lines -= *available_histogram.get(&threshold).unwrap_or(&0);
            if available_lines <= required_lines {
                return threshold;
            }
        }
        return NUM_LINES_PER_BLOCK;
    }
}
<commit_msg>Fix arithmetic underflow<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

mod rc_collector;
mod immix_collector;

use self::rc_collector::RCCollector;
use self::immix_collector::ImmixCollector;

use spaces::immix_space::BlockInfo;
use spaces::immix_space::ImmixSpace;
use spaces::large_object_space::LargeObjectSpace;

use std::collections::{HashSet, VecMap};
use std::num::Int;

use constants::{NUM_LINES_PER_BLOCK, USE_RC_COLLECTOR, USE_EVACUATION,
                EVAC_HEADROOM, CICLE_TRIGGER_THRESHHOLD, EVAC_TRIGGER_THRESHHOLD};
use gc_object::GCObjectRef;
use spaces::CollectionType;

/// The `Collector` is a composition of the collection implementations
/// `RCCollector` and `ImmixCollector`.
///
/// It manages performs common tasks and manages the cooperation between the
/// two collectors.
pub struct Collector {
    /// The reference counting collector.
    rc_collector: RCCollector,

    /// A buffer to store all managed blocks during collection.
    all_blocks: Vec<*mut BlockInfo>,

    /// A global backup of the object map.
    ///
    /// This is only used, if the library is compiled with `Valgrind` support
    /// and needed for accurate marking of addresses as `malloclike_block` and
    /// `freelike_block`.
    object_map_backup: HashSet<GCObjectRef>,

    /// The mark histogram used during collection to calculate the required
    /// space for evacuation.
    mark_histogram: VecMap<usize>,
}

impl Collector {
    /// Create a new `Collector`.
    pub fn new() -> Collector {
        return Collector {
            rc_collector: RCCollector::new(),
            all_blocks: Vec::new(),
            object_map_backup: HashSet::new(),
            mark_histogram: VecMap::with_capacity(NUM_LINES_PER_BLOCK),
        };
    }

    /// A write barrier for the given `object` used with the `RCCollector`.
    pub fn write_barrier(&mut self, object: GCObjectRef) {
        if USE_RC_COLLECTOR {
            self.rc_collector.write_barrier(object);
        }
    }

    /// Store the given blocks into the buffer for use during the collection.
    pub fn extend_all_blocks(&mut self, blocks: Vec<*mut BlockInfo>) {
        self.all_blocks.extend(blocks.into_iter());
    }

    /// Prepare a collection.
    ///
    /// This function decides if a evacuating and/or cycle collecting
    /// collection will be performed. If `evacuation` is set the collectors
    /// will try to evacuate. If `cycle_collect` is set the immix tracing
    /// collector will be used.
    pub fn prepare_collection(&mut self, evacuation: bool, cycle_collect: bool,
                              available_blocks: usize, total_blocks: usize,
                              evac_headroom: usize) -> CollectionType {
        let mut perform_evac = evacuation;

        let evac_threshhold = ((total_blocks as f32) * EVAC_TRIGGER_THRESHHOLD) as usize;
        let available_evac_blocks = available_blocks + evac_headroom;
        if evacuation || available_evac_blocks < evac_threshhold {
            let hole_threshhold = self.establish_hole_threshhold(evac_headroom);
            perform_evac = USE_EVACUATION && hole_threshhold > 0
                                          && hole_threshhold < NUM_LINES_PER_BLOCK;
            if perform_evac {
                debug!("Performing evacuation with hole_threshhold={} and evac_headroom={}",
                       hole_threshhold, evac_headroom);
                for block in self.all_blocks.iter_mut() {
                    unsafe{ (**block).set_evacuation_candidate(hole_threshhold); }
                }
            }
        }

        let perform_cycle_collect = if !cycle_collect {
            let cycle_theshold = ((total_blocks as f32) * CICLE_TRIGGER_THRESHHOLD) as usize;
            available_blocks < cycle_theshold
        } else { true };

        return match (USE_RC_COLLECTOR, perform_evac, perform_cycle_collect) {
            (true, false, false) => CollectionType::RCCollection,
            (true, true, false) => CollectionType::RCEvacCollection,
            (true, false, true) => CollectionType::ImmixCollection,
            (true, true, true) => CollectionType::ImmixEvacCollection,
            (false, false, _) => CollectionType::ImmixCollection,
            (false, true, _) => CollectionType::ImmixEvacCollection,
        }
    }

    /// Perform the collection.
    ///
    /// See `Spaces.collect() how it is called.`
    pub fn collect(&mut self, collection_type: &CollectionType,
                   roots: &[GCObjectRef], immix_space: &mut ImmixSpace,
                   large_object_space: &mut LargeObjectSpace, next_live_mark: bool) {

        if USE_RC_COLLECTOR {
            self.perform_rc_collection(collection_type, roots, immix_space,
                                       large_object_space);
        }

        if collection_type.is_immix() {
            self.perform_immix_collection(collection_type, roots,
                                          immix_space, next_live_mark);
        }
    }

    /// Perform the reference counting collection.
    fn perform_rc_collection(&mut self, collection_type: &CollectionType,
                             roots: &[GCObjectRef],
                             immix_space: &mut ImmixSpace,
                             large_object_space: &mut LargeObjectSpace) {
        if cfg!(feature = "valgrind") {
            for block in self.all_blocks.iter_mut() {
                let block_new_objects = unsafe{ (**block).get_new_objects() };
                self.object_map_backup.extend(block_new_objects.into_iter());
            }
        }

        for block in self.all_blocks.iter_mut() {
            unsafe{ (**block).remove_new_objects_from_map(); }
        }

        self.rc_collector.collect(collection_type, roots, immix_space, large_object_space);

        large_object_space.proccess_free_buffer();

        if cfg!(feature = "valgrind") {
            let mut object_map = HashSet::new();
            for block in self.all_blocks.iter_mut() {
                let block_object_map = unsafe{ (**block).get_object_map() };
                object_map.extend(block_object_map.into_iter());
            }
            for &object in self.object_map_backup.difference(&object_map) {
                valgrind_freelike!(object);
            }
            self.object_map_backup.clear();
        }
    }

    /// Perform the immix tracing collection.
    pub fn perform_immix_collection(&mut self, collection_type: &CollectionType,
                                    roots: &[GCObjectRef],
                                    immix_space: &mut ImmixSpace,
                                    next_live_mark: bool) {
        if cfg!(feature = "valgrind") {
            for block in self.all_blocks.iter_mut() {
                let block_object_map = unsafe{ (**block).get_object_map() };
                self.object_map_backup.extend(block_object_map.into_iter());
            }
        }

        for block in self.all_blocks.iter_mut() {
            unsafe{ (**block).clear_line_counts(); }
            unsafe{ (**block).clear_object_map(); }
        }

        ImmixCollector::collect(collection_type, roots, immix_space, next_live_mark);

        if cfg!(feature = "valgrind") {
            let mut object_map = HashSet::new();
            for block in self.all_blocks.iter_mut() {
                let block_object_map = unsafe{ (**block).get_object_map() };
                object_map.extend(block_object_map.into_iter());
            }
            for &object in self.object_map_backup.difference(&object_map) {
                valgrind_freelike!(object);
            }
            self.object_map_backup.clear();
        }
    }

    /// Complete the collection.
    pub fn complete_collection(&mut self, collection_type: &CollectionType,
                               immix_space: &mut ImmixSpace,
                               large_object_space: &mut LargeObjectSpace) {
        self.mark_histogram.clear();
        let (recyclable_blocks, free_blocks) = self.sweep_all_blocks();
        immix_space.set_recyclable_blocks(recyclable_blocks);

        // XXX We should not use a constant here, but something that
        // XXX changes dynamically (see rcimmix: MAX heuristic).
        let evac_headroom = if USE_EVACUATION {
            EVAC_HEADROOM - immix_space.evac_headroom() } else { 0 };
        immix_space.extend_evac_headroom(free_blocks.iter().take(evac_headroom)
                                                    .map(|&b| b).collect());
        immix_space.return_blocks(free_blocks.iter().skip(evac_headroom)
                                             .map(|&b| b).collect());

        if collection_type.is_immix() {
            large_object_space.sweep()
        }
    }
}

impl Collector {
    /// Sweep all blocks in the buffer after the collection.
    ///
    /// This function returns a list of recyclable blocks and a list of free
    /// blocks.
    fn sweep_all_blocks(&mut self) -> (Vec<*mut BlockInfo>, Vec<*mut BlockInfo>){
        let mut unavailable_blocks = Vec::new();
        let mut recyclable_blocks = Vec::new();
        let mut free_blocks = Vec::new();
        for block in self.all_blocks.drain() {
            if unsafe{ (*block).is_empty() } {
                if cfg!(feature = "valgrind") {
                    let block_object_map = unsafe{ (*block).get_object_map() };
                    for &object in block_object_map.iter() {
                        valgrind_freelike!(object);
                    }
                }
                unsafe{ (*block).reset() ;}
                debug!("Push block {:p} into free_blocks", block);
                free_blocks.push(block);
            } else {
                unsafe{ (*block).count_holes(); }
                let (holes, marked_lines) = unsafe{ (*block).count_holes_and_marked_lines() };
                if self.mark_histogram.contains_key(&(holes as usize)) {
                    if let Some(val) = self.mark_histogram.get_mut(&(holes as usize)) {
                        *val += marked_lines;
                    }
                } else { self.mark_histogram.insert(holes as usize, marked_lines); }
                debug!("Found {} holes and {} marked lines in block {:p}",
                       holes, marked_lines, block);
                match holes {
                    0 => {
                        debug!("Push block {:p} into unavailable_blocks", block);
                        unavailable_blocks.push(block);
                    },
                    _ => {
                        debug!("Push block {:p} into recyclable_blocks", block);
                        recyclable_blocks.push(block);
                    }
                }
            }
        }
        self.all_blocks = unavailable_blocks;
        return (recyclable_blocks, free_blocks);
    }

    /// Calculate how many holes a block needs to have to be selected as a
    /// evacuation candidate.
    fn establish_hole_threshhold(&self, evac_headroom: usize) -> usize {
        let mut available_histogram : VecMap<usize> = VecMap::with_capacity(NUM_LINES_PER_BLOCK);
        for block in self.all_blocks.iter() {
            let (holes, free_lines) = unsafe{ (**block).count_holes_and_available_lines() };
            if available_histogram.contains_key(&(holes as usize)) {
                if let Some(val) = available_histogram.get_mut(&(holes as usize)) {
                    *val += free_lines;
                }
            } else { available_histogram.insert(holes as usize, free_lines); }
        }
        let mut required_lines = 0;
        let mut available_lines = evac_headroom * (NUM_LINES_PER_BLOCK - 1);

        for threshold in (0..NUM_LINES_PER_BLOCK) {
            required_lines += *self.mark_histogram.get(&threshold).unwrap_or(&0);
            available_lines = available_lines.saturating_sub(*available_histogram.get(&threshold).unwrap_or(&0));
            if available_lines <= required_lines {
                return threshold;
            }
        }
        return NUM_LINES_PER_BLOCK;
    }
}
<|endoftext|>


<commit_before>use super::{Function, Parameterised, Linear, QFunction};

use ndarray::{arr1, Array1, Array2};
use geometry::{Span, Space, RegularSpace};
use geometry::dimensions::{Partition, Continuous};

/// Linearly partitioned function representation.
pub struct Partitions {
    weights: Array2<f64>,
    input_space: RegularSpace<Partition>,
}

impl Partitions {
    pub fn new(input_space: RegularSpace<Partition>,
               n_outputs: usize) -> Self
    {
        let n_features = match input_space.span() {
            Span::Finite(s) => s,
            _ => panic!("`Partitions` function approximator only supports \
                         finite input spaces.")
        };

        Partitions {
            weights: Array2::<f64>::zeros((n_features, n_outputs)),
            input_space: input_space,
        }
    }

    fn hash(&self, input: &[f64]) -> usize {
        let mut in_it = input.iter().rev();
        let mut d_it = self.input_space.iter().rev();

        let acc = d_it.next().unwrap().to_partition(in_it.next().unwrap());

        in_it.zip(d_it).fold(acc, |acc, (v, d)| {
            let i = d.to_partition(v);

            i + d.density() * acc
        })
    }
}

impl Function<Vec<f64>, f64> for Partitions {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        // Hash the input down to an index:
        self.weights[[self.hash(input), 0]]
    }
}

impl Function<Vec<f64>, Vec<f64>> for Partitions {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and convert to a Vec<f64>:
        self.weights.row(ri).to_vec()
    }
}

impl Parameterised<Vec<f64>, f64> for Partitions {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, 0)) += error
        }
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for Partitions {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and perform update via memcpy:
        self.weights.row_mut(ri).scaled_add(1.0, &arr1(&errors));
    }
}

impl Linear<RegularSpace<Continuous>> for Partitions
{
    fn phi(&self, input: &Vec<f64>) -> Array1<f64> {
        let mut p = Array1::<f64>::zeros(self.weights.len());
        p[self.hash(input)] = 1.0;

        p
    }
}

impl QFunction<RegularSpace<Continuous>> for Partitions
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        self.weights[[ri, action]]
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, action)) += error
        }
    }
}

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

    use fa::{Function, Parameterised};
    use geometry::RegularSpace;
    use geometry::dimensions::Partition;

    #[test]
    fn test_update_eval() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_collisions() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        t.update(&vec![0.5], vec![1.2]);

        for value in vec![0.2, 0.5, 0.8] {
            let out: f64 = t.evaluate(&vec![value]);
            assert_eq!(out, 1.2);
        }
    }

    #[test]
    fn test_1d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        for i in 0..10 {
            let input: Vec<f64> = vec![i as u32 as f64];

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 0.0);

            t.update(&input, vec![1.0]);

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 1.0);
        }
    }

    #[test]
    fn test_2d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64];

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 0.0);

                t.update(&input, vec![1.0]);

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 1.0);
            }
        }
    }

    #[test]
    fn test_3d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));
        ds = ds.push(Partition::new(0.0, 9.0, 10));
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                for k in 0..10 {
                    let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64, k as u32 as f64];

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 0.0);

                    t.update(&input, vec![1.0]);

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 1.0);
                }
            }
        }
    }
}
<commit_msg>Implemented VFunction for Partitions<commit_after>use super::{Function, Parameterised, Linear, VFunction, QFunction};

use utils::dot;
use ndarray::{arr1, Array1, Array2};
use geometry::{Span, Space, RegularSpace};
use geometry::dimensions::{Partition, Continuous};

/// Linearly partitioned function representation.
pub struct Partitions {
    weights: Array2<f64>,
    input_space: RegularSpace<Partition>,
}

impl Partitions {
    pub fn new(input_space: RegularSpace<Partition>,
               n_outputs: usize) -> Self
    {
        let n_features = match input_space.span() {
            Span::Finite(s) => s,
            _ => panic!("`Partitions` function approximator only supports \
                         finite input spaces.")
        };

        Partitions {
            weights: Array2::<f64>::zeros((n_features, n_outputs)),
            input_space: input_space,
        }
    }

    fn hash(&self, input: &[f64]) -> usize {
        let mut in_it = input.iter().rev();
        let mut d_it = self.input_space.iter().rev();

        let acc = d_it.next().unwrap().to_partition(in_it.next().unwrap());

        in_it.zip(d_it).fold(acc, |acc, (v, d)| {
            let i = d.to_partition(v);

            i + d.density() * acc
        })
    }
}

impl Function<Vec<f64>, f64> for Partitions {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        // Hash the input down to an index:
        self.weights[[self.hash(input), 0]]
    }
}

impl Function<Vec<f64>, Vec<f64>> for Partitions {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and convert to a Vec<f64>:
        self.weights.row(ri).to_vec()
    }
}

impl Parameterised<Vec<f64>, f64> for Partitions {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, 0)) += error
        }
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for Partitions {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        // Get the row slice and perform update via memcpy:
        self.weights.row_mut(ri).scaled_add(1.0, &arr1(&errors));
    }
}

impl Linear<RegularSpace<Continuous>> for Partitions
{
    fn phi(&self, input: &Vec<f64>) -> Array1<f64> {
        let mut p = Array1::<f64>::zeros(self.weights.len());
        p[self.hash(input)] = 1.0;

        p
    }
}

impl VFunction<RegularSpace<Continuous>> for Partitions
{
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        dot(self.weights.column(0).as_slice().unwrap(),
            phi.as_slice().unwrap())
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        self.weights.column_mut(0).scaled_add(error, phi);
    }
}

impl QFunction<RegularSpace<Continuous>> for Partitions
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        // Hash the input down to a row index:
        let ri = self.hash(input);

        self.weights[[ri, action]]
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        let index = self.hash(input);

        unsafe {
            *self.weights.uget_mut((index, action)) += error
        }
    }
}

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

    use fa::{Function, Parameterised};
    use geometry::RegularSpace;
    use geometry::dimensions::Partition;

    #[test]
    fn test_update_eval() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_collisions() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        t.update(&vec![0.5], vec![1.2]);

        for value in vec![0.2, 0.5, 0.8] {
            let out: f64 = t.evaluate(&vec![value]);
            assert_eq!(out, 1.2);
        }
    }

    #[test]
    fn test_1d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        for i in 0..10 {
            let input: Vec<f64> = vec![i as u32 as f64];

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 0.0);

            t.update(&input, vec![1.0]);

            let out: f64 = t.evaluate(&input);
            assert_eq!(out, 1.0);
        }
    }

    #[test]
    fn test_2d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64];

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 0.0);

                t.update(&input, vec![1.0]);

                let out: f64 = t.evaluate(&input);
                assert_eq!(out, 1.0);
            }
        }
    }

    #[test]
    fn test_3d() {
        let mut ds = RegularSpace::new();
        ds = ds.push(Partition::new(0.0, 9.0, 10));
        ds = ds.push(Partition::new(0.0, 9.0, 10));
        ds = ds.push(Partition::new(0.0, 9.0, 10));

        let mut t = Partitions::new(ds, 1);

        for i in 0..10 {
            for j in 0..10 {
                for k in 0..10 {
                    let input: Vec<f64> = vec![i as u32 as f64, j as u32 as f64, k as u32 as f64];

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 0.0);

                    t.update(&input, vec![1.0]);

                    let out: f64 = t.evaluate(&input);
                    assert_eq!(out, 1.0);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! This provides a simple networking substrate between a client and server. It is assumed that all
//! operations are blocking and return only complete blocks of data. The intended use case has the
//! server blocking on read.  Upon receiving a payload during a read, the server should process the
//! payload, write a response, and then block on read again. The client should block on read after
//! performing a write. Note: if the server will attempt to accept or acquire a new client if one
//! does not exist prior to performing any operations.
//!
//! Internally both the client and server leverage a NetworkStream that communications in blocks
//! where a block is a length prefixed array of bytes.

use anyhow::{anyhow, ensure, Result};
use std::{
    io::{Read, Write},
    net::{SocketAddr, TcpListener, TcpStream},
    thread, time,
};

pub struct NetworkClient {
    stream: NetworkStream,
}

impl NetworkClient {
    pub fn connect(server: SocketAddr) -> Result<Self> {
        let mut stream = TcpStream::connect(server);

        let mut attempts = 0;
        let sleeptime = time::Duration::from_millis(100);

        while stream.is_err() && attempts < 5 {
            thread::sleep(sleeptime);
            attempts += 1;
            stream = TcpStream::connect(server);
        }
        let stream = stream?;
        stream.set_nodelay(true)?;

        Ok(Self {
            stream: NetworkStream::new(stream),
        })
    }

    /// Blocking read until able to successfully read an entire message
    pub fn read(&mut self) -> Result<Vec<u8>> {
        self.stream.read()
    }

    /// Blocking read until able to successfully read an entire message
    pub fn write(&mut self, data: &[u8]) -> Result<()> {
        self.stream.write(data)
    }
}

pub struct NetworkServer {
    listener: TcpListener,
    stream: Option<NetworkStream>,
}

impl NetworkServer {
    pub fn new(listen: SocketAddr) -> Self {
        let listener = TcpListener::bind(listen).unwrap();
        Self {
            listener,
            stream: None,
        }
    }

    /// If there isn't already a downstream client, it accepts. Otherwise it
    /// blocks until able to successfully read an entire message
    pub fn read(&mut self) -> Result<Vec<u8>> {
        let stream = self.client()?;
        stream.read()
    }

    pub fn write(&mut self, data: &[u8]) -> Result<()> {
        let stream = self.client()?;
        stream.write(data)
    }

    fn client(&mut self) -> Result<&mut NetworkStream> {
        if self.stream.is_none() {
            let (stream, _stream_addr) = self.listener.accept()?;
            stream.set_nodelay(true)?;
            self.stream = Some(NetworkStream::new(stream));
        }

        self.stream
            .as_mut()
            .ok_or_else(|| anyhow!("Unable to retrieve a stream"))
    }
}

struct NetworkStream {
    stream: TcpStream,
    buffer: Vec<u8>,
    temp_buffer: [u8; 1024],
}

impl NetworkStream {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            stream,
            buffer: Vec::new(),
            temp_buffer: [0; 1024],
        }
    }

    /// Blocking read until able to successfully read an entire message
    pub fn read(&mut self) -> Result<Vec<u8>> {
        let result = self.read_buffer();
        if !result.is_empty() {
            return Ok(result);
        }

        loop {
            let read = self.stream.read(&mut self.temp_buffer)?;
            self.buffer.extend(self.temp_buffer[0..read].to_vec());
            let result = self.read_buffer();
            if !result.is_empty() {
                return Ok(result);
            }
        }
    }

    /// Blocking write until able to successfully send an entire message
    pub fn write(&mut self, data: &[u8]) -> Result<()> {
        let u32_max = u32::max_value() as usize;
        ensure!(
            data.len() <= u32_max,
            "Found data that is too large to decode: {}",
            data.len()
        );
        let data_len = data.len() as u32;
        self.write_all(&data_len.to_le_bytes())?;
        self.write_all(data)?;
        Ok(())
    }

    /// Data sent on a TCP socket may not necessarily be delivered at the exact time. So a read may
    /// only include a subset of what was sent. This wraps around the TCP read buffer to ensure
    /// that only full messages are received.
    fn read_buffer(&mut self) -> Vec<u8> {
        if self.buffer.len() < 4 {
            return Vec::new();
        }

        let mut u32_bytes = [0; 4];
        u32_bytes.copy_from_slice(&self.buffer[0..4]);
        let data_size = u32::from_le_bytes(u32_bytes) as usize;

        let remaining_data = &self.buffer[4..];
        if remaining_data.len() < data_size {
            return Vec::new();
        }

        let returnable_data = remaining_data[..data_size].to_vec();
        if remaining_data.len() > data_size {
            self.buffer = remaining_data[data_size + 1..].to_vec();
        } else {
            self.buffer = Vec::new();
        }
        returnable_data
    }

    /// Writing to a TCP socket will take in as much data as the underlying buffer has space for.
    /// This wraps around that buffer and blocks until all the data has been pushed.
    fn write_all(&mut self, data: &[u8]) -> Result<()> {
        let mut unwritten = &data[..];
        let mut total_written = 0;

        while !unwritten.is_empty() {
            let written = self.stream.write(unwritten)?;
            total_written += written;
            unwritten = &data[total_written..];
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libra_config::utils;
    use std::net::{IpAddr, Ipv4Addr, SocketAddr};

    #[test]
    fn test_ping() {
        let server_port = utils::get_available_port();
        let server_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), server_port);
        let mut server = NetworkServer::new(server_addr);
        let mut client = NetworkClient::connect(server_addr).unwrap();

        let data = vec![0, 1, 2, 3];
        client.write(&data).unwrap();
        let result = server.read().unwrap();
        assert_eq!(data, result);

        let data = vec![4, 5, 6, 7];
        server.write(&data).unwrap();
        let result = client.read().unwrap();
        assert_eq!(data, result);
    }
}
<commit_msg>[secure-net] implement reliabllity into NetworkServer<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

//! This provides a simple networking substrate between a client and server. It is assumed that all
//! operations are blocking and return only complete blocks of data. The intended use case has the
//! server blocking on read.  Upon receiving a payload during a read, the server should process the
//! payload, write a response, and then block on read again. The client should block on read after
//! performing a write. Upon errors or remote disconnections, the call (read, write) will return an
//! error to let the caller know of the event. A follow up call will result in the service
//! attempting to either reconnect in the case of a client or accept a new client in the case of a
//! server.
//!
//! Internally both the client and server leverage a NetworkStream that communications in blocks
//! where a block is a length prefixed array of bytes.

use anyhow::{anyhow, ensure, Result};
use std::{
    io::{Read, Write},
    net::{Shutdown, SocketAddr, TcpListener, TcpStream},
    thread, time,
};

pub struct NetworkClient {
    stream: NetworkStream,
}

impl NetworkClient {
    pub fn connect(server: SocketAddr) -> Result<Self> {
        let mut stream = TcpStream::connect(server);

        let mut attempts = 0;
        let sleeptime = time::Duration::from_millis(100);

        while stream.is_err() && attempts < 5 {
            thread::sleep(sleeptime);
            attempts += 1;
            stream = TcpStream::connect(server);
        }
        let stream = stream?;
        stream.set_nodelay(true)?;

        Ok(Self {
            stream: NetworkStream::new(stream),
        })
    }

    /// Blocking read until able to successfully read an entire message
    pub fn read(&mut self) -> Result<Vec<u8>> {
        self.stream.read()
    }

    /// Shutdown the internal network stream
    pub fn shutdown(&self) -> Result<()> {
        self.stream.shutdown()
    }

    /// Blocking read until able to successfully read an entire message
    pub fn write(&mut self, data: &[u8]) -> Result<()> {
        self.stream.write(data)
    }
}

pub struct NetworkServer {
    listener: TcpListener,
    stream: Option<NetworkStream>,
}

impl NetworkServer {
    pub fn new(listen: SocketAddr) -> Self {
        let listener = TcpListener::bind(listen).unwrap();
        Self {
            listener,
            stream: None,
        }
    }

    /// If there isn't already a downstream client, it accepts. Otherwise it
    /// blocks until able to successfully read an entire message
    pub fn read(&mut self) -> Result<Vec<u8>> {
        let stream = self.client()?;
        let result = stream.read();
        if result.is_err() {
            self.stream = None;
        }
        result
    }

    /// Shutdown the internal network stream
    pub fn shutdown(&self) -> Result<()> {
        self.stream
            .as_ref()
            .ok_or_else(|| anyhow!("No active stream"))?
            .shutdown()
    }

    /// If there isn't already a downstream client, it accepts. Otherwise it
    /// blocks until it is able to successfully send an entire message.
    pub fn write(&mut self, data: &[u8]) -> Result<()> {
        let stream = self.client()?;
        let result = stream.write(data);
        if result.is_err() {
            self.stream = None;
        }
        result
    }

    fn client(&mut self) -> Result<&mut NetworkStream> {
        if self.stream.is_none() {
            let (stream, _stream_addr) = self.listener.accept()?;
            stream.set_nodelay(true)?;
            self.stream = Some(NetworkStream::new(stream));
        }

        self.stream
            .as_mut()
            .ok_or_else(|| anyhow!("Unable to retrieve a stream"))
    }
}

struct NetworkStream {
    stream: TcpStream,
    buffer: Vec<u8>,
    temp_buffer: [u8; 1024],
}

impl NetworkStream {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            stream,
            buffer: Vec::new(),
            temp_buffer: [0; 1024],
        }
    }

    /// Blocking read until able to successfully read an entire message
    pub fn read(&mut self) -> Result<Vec<u8>> {
        let result = self.read_buffer();
        if !result.is_empty() {
            return Ok(result);
        }

        loop {
            let read = self.stream.read(&mut self.temp_buffer)?;
            if read == 0 {
                anyhow::bail!("Remote stream cleanly closed");
            }
            self.buffer.extend(self.temp_buffer[0..read].to_vec());
            let result = self.read_buffer();
            if !result.is_empty() {
                return Ok(result);
            }
        }
    }

    /// Terminate the socket
    pub fn shutdown(&self) -> Result<()> {
        Ok(self.stream.shutdown(Shutdown::Both)?)
    }

    /// Blocking write until able to successfully send an entire message
    pub fn write(&mut self, data: &[u8]) -> Result<()> {
        let u32_max = u32::max_value() as usize;
        ensure!(
            data.len() <= u32_max,
            "Found data that is too large to decode: {}",
            data.len()
        );
        let data_len = data.len() as u32;
        self.write_all(&data_len.to_le_bytes())?;
        self.write_all(data)?;
        Ok(())
    }

    /// Data sent on a TCP socket may not necessarily be delivered at the exact time. So a read may
    /// only include a subset of what was sent. This wraps around the TCP read buffer to ensure
    /// that only full messages are received.
    fn read_buffer(&mut self) -> Vec<u8> {
        if self.buffer.len() < 4 {
            return Vec::new();
        }

        let mut u32_bytes = [0; 4];
        u32_bytes.copy_from_slice(&self.buffer[0..4]);
        let data_size = u32::from_le_bytes(u32_bytes) as usize;

        let remaining_data = &self.buffer[4..];
        if remaining_data.len() < data_size {
            return Vec::new();
        }

        let returnable_data = remaining_data[..data_size].to_vec();
        if remaining_data.len() > data_size {
            self.buffer = remaining_data[data_size + 1..].to_vec();
        } else {
            self.buffer = Vec::new();
        }
        returnable_data
    }

    /// Writing to a TCP socket will take in as much data as the underlying buffer has space for.
    /// This wraps around that buffer and blocks until all the data has been pushed.
    fn write_all(&mut self, data: &[u8]) -> Result<()> {
        let mut unwritten = &data[..];
        let mut total_written = 0;

        while !unwritten.is_empty() {
            let written = self.stream.write(unwritten)?;
            total_written += written;
            unwritten = &data[total_written..];
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libra_config::utils;
    use std::net::{IpAddr, Ipv4Addr, SocketAddr};

    #[test]
    fn test_ping() {
        let server_port = utils::get_available_port();
        let server_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), server_port);
        let mut server = NetworkServer::new(server_addr);
        let mut client = NetworkClient::connect(server_addr).unwrap();

        let data = vec![0, 1, 2, 3];
        client.write(&data).unwrap();
        let result = server.read().unwrap();
        assert_eq!(data, result);

        let data = vec![4, 5, 6, 7];
        server.write(&data).unwrap();
        let result = client.read().unwrap();
        assert_eq!(data, result);
    }

    #[test]
    fn test_shutdown() {
        let server_port = utils::get_available_port();
        let server_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), server_port);
        let mut server = NetworkServer::new(server_addr);
        let mut client = NetworkClient::connect(server_addr).unwrap();

        let data = vec![0, 1, 2, 3];
        client.write(&data).unwrap();
        let result = server.read().unwrap();
        assert_eq!(data, result);

        client.shutdown().unwrap();
        let mut client = NetworkClient::connect(server_addr).unwrap();
        assert!(server.read().is_err());

        let data = vec![4, 5, 6, 7];
        client.write(&data).unwrap();
        let result = server.read().unwrap();
        assert_eq!(data, result);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This crate provides a convenient concise way to write unit tests for
//! implementations of [`Serialize`] and [`Deserialize`].
//!
//! [`Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
//! [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
//!
//! The `Serialize` impl for a value can be characterized by the sequence of
//! [`Serializer`] calls that are made in the course of serializing the value,
//! so `serde_test` provides a [`Token`] abstraction which corresponds roughly
//! to `Serializer` method calls. There is an [`assert_ser_tokens`] function to
//! test that a value serializes to a particular sequence of method calls, an
//! [`assert_de_tokens`] function to test that a value can be deserialized from
//! a particular sequence of method calls, and an [`assert_tokens`] function to
//! test both directions. There are also functions to test expected failure
//! conditions.
//!
//! [`Serializer`]: https://docs.serde.rs/serde/ser/trait.Serializer.html
//! [`Token`]: https://docs.serde.rs/serde_test/enum.Token.html
//! [`assert_ser_tokens`]: https://docs.serde.rs/serde_test/fn.assert_ser_tokens.html
//! [`assert_de_tokens`]: https://docs.serde.rs/serde_test/fn.assert_de_tokens.html
//! [`assert_tokens`]: https://docs.serde.rs/serde_test/fn.assert_tokens.html
//!
//! Here is an example from the [`linked-hash-map`] crate.
//!
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
//!
//! ```rust
//! # extern crate serde;
//! #
//! # macro_rules! ignore {
//! #     ($($tt:tt)+) => {}
//! # }
//! #
//! # ignore! {
//! extern crate linked_hash_map;
//! use linked_hash_map::LinkedHashMap;
//! # }
//!
//! extern crate serde_test;
//! use serde_test::{Token, assert_tokens};
//!
//! # use std::fmt;
//! # use std::marker::PhantomData;
//! #
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
//! #
//! # // Dumb immitation of LinkedHashMap.
//! # #[derive(PartialEq, Debug)]
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
//! #
//! # impl<K, V> LinkedHashMap<K, V> {
//! #     fn new() -> Self {
//! #         LinkedHashMap(Vec::new())
//! #     }
//! #
//! #     fn insert(&mut self, k: K, v: V) {
//! #         self.0.push((k, v));
//! #     }
//! # }
//! #
//! # impl<K, V> Serialize for LinkedHashMap<K, V>
//! #     where K: Serialize,
//! #           V: Serialize
//! # {
//! #     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//! #         where S: Serializer
//! #     {
//! #         let mut map = serializer.serialize_map(Some(self.0.len()))?;
//! #         for &(ref k, ref v) in &self.0 {
//! #             map.serialize_entry(k, v)?;
//! #         }
//! #         map.end()
//! #     }
//! # }
//! #
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
//! #
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
//! #     where K: Deserialize<'de>,
//! #           V: Deserialize<'de>
//! # {
//! #     type Value = LinkedHashMap<K, V>;
//! #
//! #     fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result {
//! #         unimplemented!()
//! #     }
//! #
//! #     fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
//! #         where M: MapAccess<'de>
//! #     {
//! #         let mut map = LinkedHashMap::new();
//! #         while let Some((key, value)) = access.next_entry()? {
//! #             map.insert(key, value);
//! #         }
//! #         Ok(map)
//! #     }
//! # }
//! #
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
//! #     where K: Deserialize<'de>,
//! #           V: Deserialize<'de>
//! # {
//! #     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
//! #         where D: Deserializer<'de>
//! #     {
//! #         deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
//! #     }
//! # }
//! #
//! #[test]
//! # fn not_a_test_ser_de_empty() {}
//! fn test_ser_de_empty() {
//!     let map = LinkedHashMap::<char, u32>::new();
//!
//!     assert_tokens(&map, &[
//!         Token::Map { len: Some(0) },
//!         Token::MapEnd,
//!     ]);
//! }
//!
//! #[test]
//! # fn not_a_test_ser_de() {}
//! fn test_ser_de() {
//!     let mut map = LinkedHashMap::new();
//!     map.insert('b', 20);
//!     map.insert('a', 10);
//!     map.insert('c', 30);
//!
//!     assert_tokens(&map, &[
//!         Token::Map { len: Some(3) },
//!         Token::Char('b'),
//!         Token::I32(20),
//!
//!         Token::Char('a'),
//!         Token::I32(10),
//!
//!         Token::Char('c'),
//!         Token::I32(30),
//!         Token::MapEnd,
//!     ]);
//! }
//! #
//! # fn main() {
//! #     test_ser_de_empty();
//! #     test_ser_de();
//! # }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_test/1.0.19")]

#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
    missing_docs_in_private_items,
    stutter,
    use_self,
))]

#[macro_use]
extern crate serde;

mod ser;
mod de;
mod error;

mod configure;
mod token;
mod assert;

pub use token::Token;
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
                 assert_ser_tokens_error, assert_tokens};

pub use configure::{Compact, Configure, Readable};

// Not public API.
#[doc(hidden)]
pub use de::Deserializer;
<commit_msg>Whitelist use of Debug in serde_test<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! This crate provides a convenient concise way to write unit tests for
//! implementations of [`Serialize`] and [`Deserialize`].
//!
//! [`Serialize`]: https://docs.serde.rs/serde/ser/trait.Serialize.html
//! [`Deserialize`]: https://docs.serde.rs/serde/de/trait.Deserialize.html
//!
//! The `Serialize` impl for a value can be characterized by the sequence of
//! [`Serializer`] calls that are made in the course of serializing the value,
//! so `serde_test` provides a [`Token`] abstraction which corresponds roughly
//! to `Serializer` method calls. There is an [`assert_ser_tokens`] function to
//! test that a value serializes to a particular sequence of method calls, an
//! [`assert_de_tokens`] function to test that a value can be deserialized from
//! a particular sequence of method calls, and an [`assert_tokens`] function to
//! test both directions. There are also functions to test expected failure
//! conditions.
//!
//! [`Serializer`]: https://docs.serde.rs/serde/ser/trait.Serializer.html
//! [`Token`]: https://docs.serde.rs/serde_test/enum.Token.html
//! [`assert_ser_tokens`]: https://docs.serde.rs/serde_test/fn.assert_ser_tokens.html
//! [`assert_de_tokens`]: https://docs.serde.rs/serde_test/fn.assert_de_tokens.html
//! [`assert_tokens`]: https://docs.serde.rs/serde_test/fn.assert_tokens.html
//!
//! Here is an example from the [`linked-hash-map`] crate.
//!
//! [`linked-hash-map`]: https://github.com/contain-rs/linked-hash-map
//!
//! ```rust
//! # extern crate serde;
//! #
//! # macro_rules! ignore {
//! #     ($($tt:tt)+) => {}
//! # }
//! #
//! # ignore! {
//! extern crate linked_hash_map;
//! use linked_hash_map::LinkedHashMap;
//! # }
//!
//! extern crate serde_test;
//! use serde_test::{Token, assert_tokens};
//!
//! # use std::fmt;
//! # use std::marker::PhantomData;
//! #
//! # use serde::ser::{Serialize, Serializer, SerializeMap};
//! # use serde::de::{Deserialize, Deserializer, Visitor, MapAccess};
//! #
//! # // Dumb immitation of LinkedHashMap.
//! # #[derive(PartialEq, Debug)]
//! # struct LinkedHashMap<K, V>(Vec<(K, V)>);
//! #
//! # impl<K, V> LinkedHashMap<K, V> {
//! #     fn new() -> Self {
//! #         LinkedHashMap(Vec::new())
//! #     }
//! #
//! #     fn insert(&mut self, k: K, v: V) {
//! #         self.0.push((k, v));
//! #     }
//! # }
//! #
//! # impl<K, V> Serialize for LinkedHashMap<K, V>
//! #     where K: Serialize,
//! #           V: Serialize
//! # {
//! #     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//! #         where S: Serializer
//! #     {
//! #         let mut map = serializer.serialize_map(Some(self.0.len()))?;
//! #         for &(ref k, ref v) in &self.0 {
//! #             map.serialize_entry(k, v)?;
//! #         }
//! #         map.end()
//! #     }
//! # }
//! #
//! # struct LinkedHashMapVisitor<K, V>(PhantomData<(K, V)>);
//! #
//! # impl<'de, K, V> Visitor<'de> for LinkedHashMapVisitor<K, V>
//! #     where K: Deserialize<'de>,
//! #           V: Deserialize<'de>
//! # {
//! #     type Value = LinkedHashMap<K, V>;
//! #
//! #     fn expecting(&self, _: &mut fmt::Formatter) -> fmt::Result {
//! #         unimplemented!()
//! #     }
//! #
//! #     fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
//! #         where M: MapAccess<'de>
//! #     {
//! #         let mut map = LinkedHashMap::new();
//! #         while let Some((key, value)) = access.next_entry()? {
//! #             map.insert(key, value);
//! #         }
//! #         Ok(map)
//! #     }
//! # }
//! #
//! # impl<'de, K, V> Deserialize<'de> for LinkedHashMap<K, V>
//! #     where K: Deserialize<'de>,
//! #           V: Deserialize<'de>
//! # {
//! #     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
//! #         where D: Deserializer<'de>
//! #     {
//! #         deserializer.deserialize_map(LinkedHashMapVisitor(PhantomData))
//! #     }
//! # }
//! #
//! #[test]
//! # fn not_a_test_ser_de_empty() {}
//! fn test_ser_de_empty() {
//!     let map = LinkedHashMap::<char, u32>::new();
//!
//!     assert_tokens(&map, &[
//!         Token::Map { len: Some(0) },
//!         Token::MapEnd,
//!     ]);
//! }
//!
//! #[test]
//! # fn not_a_test_ser_de() {}
//! fn test_ser_de() {
//!     let mut map = LinkedHashMap::new();
//!     map.insert('b', 20);
//!     map.insert('a', 10);
//!     map.insert('c', 30);
//!
//!     assert_tokens(&map, &[
//!         Token::Map { len: Some(3) },
//!         Token::Char('b'),
//!         Token::I32(20),
//!
//!         Token::Char('a'),
//!         Token::I32(10),
//!
//!         Token::Char('c'),
//!         Token::I32(30),
//!         Token::MapEnd,
//!     ]);
//! }
//! #
//! # fn main() {
//! #     test_ser_de_empty();
//! #     test_ser_de();
//! # }
//! ```

#![doc(html_root_url = "https://docs.rs/serde_test/1.0.19")]

#![cfg_attr(feature = "cargo-clippy", deny(clippy, clippy_pedantic))]
// Whitelisted clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp))]
// Whitelisted clippy_pedantic lints
#![cfg_attr(feature = "cargo-clippy", allow(
    missing_docs_in_private_items,
    stutter,
    use_debug,
    use_self,
))]

#[macro_use]
extern crate serde;

mod ser;
mod de;
mod error;

mod configure;
mod token;
mod assert;

pub use token::Token;
pub use assert::{assert_de_tokens, assert_de_tokens_error, assert_ser_tokens,
                 assert_ser_tokens_error, assert_tokens};

pub use configure::{Compact, Configure, Readable};

// Not public API.
#[doc(hidden)]
pub use de::Deserializer;
<|endoftext|>


<commit_before>use parking_lot::{Mutex, MutexGuard};
use std::cmp::{max, min};
use std::mem::replace;

use gc::swiper::card::CardTable;
use gc::swiper::controller::SharedHeapConfig;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::{arena, Address, Region, GEN_SIZE};
use mem;
use object::offset_of_array_data;

pub struct OldGen {
    total: Region,
    protected: Mutex<OldGenProtected>,

    crossing_map: CrossingMap,
    card_table: CardTable,
    config: SharedHeapConfig,
}

impl OldGen {
    pub fn new(
        start: Address,
        end: Address,
        crossing_map: CrossingMap,
        card_table: CardTable,
        config: SharedHeapConfig,
    ) -> OldGen {
        let total = Region::new(start, end);
        let old = OldGen {
            total: total.clone(),
            protected: Mutex::new(OldGenProtected::new(total)),

            crossing_map: crossing_map,
            card_table: card_table,
            config: config,
        };

        old
    }

    pub fn total(&self) -> Region {
        self.total.clone()
    }

    pub fn total_start(&self) -> Address {
        self.total.start
    }

    pub fn committed_size(&self) -> usize {
        let protected = self.protected.lock();

        protected.size
    }

    pub fn active_size(&self) -> usize {
        let protected = self.protected.lock();
        let mut size = 0;

        for old_region in &protected.regions {
            size += old_region.active_size();
        }

        size
    }

    pub fn alloc(&self, size: usize) -> Address {
        let mut protected = self.protected.lock();
        protected.alloc(&self.config, size)
    }

    pub fn update_crossing(&self, old: Address, new: Address, array_ref: bool) {
        if (old.to_usize() >> CARD_SIZE_BITS) == (new.to_usize() >> CARD_SIZE_BITS) {
            // object does not span multiple cards
            if (old.to_usize() & (CARD_SIZE - 1)) == 0 {
                let card = self.card_table.card_idx(old.into());
                self.crossing_map.set_first_object(card, 0);
            }
        } else if array_ref {
            let new_card_idx = self.card_table.card_idx(new.into());
            let new_card_start = self.card_table.to_address(new_card_idx);

            let old_card_idx = self.card_table.card_idx(old);
            let old_card_end = self.card_table.to_address(old_card_idx).offset(CARD_SIZE);

            let refs_per_card = CARD_SIZE / mem::ptr_width_usize();
            let mut loop_card_start = old_card_idx.to_usize() + 1;

            // If you allocate an object array just before the card end,
            // it could happen that the card starts with part of the header
            // or the length-field.
            if old.offset(offset_of_array_data() as usize) > old_card_end {
                let diff = old_card_end.offset_from(old) / mem::ptr_width_usize();
                self.crossing_map
                    .set_array_start(loop_card_start.into(), diff);

                loop_card_start += 1;
            }

            // all cards between ]old_card; new_card[ are full with references
            for c in loop_card_start..new_card_idx.to_usize() {
                self.crossing_map
                    .set_references_at_start(c.into(), refs_per_card);
            }

            // new_card starts with x references, then next object
            if new_card_idx.to_usize() >= loop_card_start {
                let refs_dist = new.offset_from(new_card_start) / mem::ptr_width_usize();

                if refs_dist > 0 {
                    self.crossing_map
                        .set_references_at_start(new_card_idx, refs_dist);
                } else {
                    self.crossing_map.set_first_object(new_card_idx, 0);
                }
            }
        } else {
            let new_card_idx = self.card_table.card_idx(new.into());
            let new_card_start = self.card_table.to_address(new_card_idx);

            let old_card_idx = self.card_table.card_idx(old.into());

            // all cards between ]old_card; new_card[ are set to NoRefs
            for c in old_card_idx.to_usize() + 1..new_card_idx.to_usize() {
                self.crossing_map.set_no_references(c.into());
            }

            // new_card stores x words of object, then next object
            self.crossing_map.set_first_object(
                new_card_idx,
                new.offset_from(new_card_start) / mem::ptr_width_usize(),
            );
        }
    }

    pub fn protected(&self) -> MutexGuard<OldGenProtected> {
        self.protected.lock()
    }
}

pub struct OldGenProtected {
    pub total: Region,
    pub size: usize,
    pub regions: Vec<OldRegion>,
}

impl OldGenProtected {
    fn new(total: Region) -> OldGenProtected {
        OldGenProtected {
            total: total.clone(),
            size: 0,
            regions: vec![OldRegion::new(total)],
        }
    }

    pub fn contains_slow(&self, addr: Address) -> bool {
        for old_region in &self.regions {
            if old_region.start <= addr && addr < old_region.alloc_top {
                return true;
            }
        }

        false
    }

    pub fn commit_single_region(&mut self, top: Address) {
        let limit = top.align_gen();
        assert!(self.total.valid_top(limit));

        let mut last = self.total.start;

        for region in &self.regions {
            let start = last;
            let end = min(region.start, limit);
            let size = end.offset_from(start);

            if size > 0 {
                arena::commit(start, size, false);
            }

            if end == limit {
                return;
            }

            last = region.alloc_limit;
        }

        let start = last;
        let end = limit;

        if end <= start {
            return;
        }

        let size = end.offset_from(start);
        arena::commit(start, size, false);
    }

    pub fn update_single_region(&mut self, top: Address) {
        let limit = top.align_gen();
        assert!(self.total.valid_top(limit));

        let region = OldRegion {
            start: self.total.start,
            end: self.total.end,

            alloc_top: top,
            alloc_limit: limit,
        };

        let regions = replace(&mut self.regions, vec![region]);

        for region in regions {
            if limit >= region.alloc_limit {
                continue;
            }

            let start = max(region.start, limit);
            let size = region.alloc_limit.offset_from(start);

            if size > 0 {
                arena::forget(start, size);
            }
        }
    }

    fn single_region(&self) -> &OldRegion {
        assert!(self.regions.len() == 1);
        self.regions.first().unwrap()
    }

    fn single_region_mut(&mut self) -> &mut OldRegion {
        assert!(self.regions.len() == 1);
        self.regions.first_mut().unwrap()
    }

    pub fn alloc(&mut self, config: &SharedHeapConfig, size: usize) -> Address {
        let ptr = self.pure_alloc(size);

        if ptr.is_non_null() {
            return ptr;
        }

        {
            let mut config = config.lock();

            if !config.grow_old(GEN_SIZE) {
                return Address::null();
            }
        }

        if !self.extend(GEN_SIZE) {
            return Address::null();
        }

        self.pure_alloc(size)
    }

    fn pure_alloc(&mut self, size: usize) -> Address {
        for old_region in &mut self.regions {
            let new_alloc_top = old_region.alloc_top.offset(size);

            if new_alloc_top <= old_region.alloc_limit {
                let addr = old_region.alloc_top;
                old_region.alloc_top = new_alloc_top;
                return addr;
            }
        }

        Address::null()
    }

    fn extend(&mut self, size: usize) -> bool {
        for old_region in &mut self.regions {
            let new_alloc_limit = old_region.alloc_limit.offset(size);

            if new_alloc_limit <= old_region.end {
                arena::commit(old_region.alloc_limit, size, false);
                old_region.alloc_limit = new_alloc_limit;
                return true;
            }
        }

        false
    }
}

#[derive(Clone)]
pub struct OldRegion {
    start: Address,
    end: Address,

    alloc_top: Address,
    alloc_limit: Address,
}

impl OldRegion {
    fn new(region: Region) -> OldRegion {
        OldRegion {
            start: region.start,
            end: region.end,

            alloc_top: region.start,
            alloc_limit: region.start,
        }
    }

    pub fn start(&self) -> Address {
        self.start
    }

    pub fn top(&self) -> Address {
        self.alloc_top
    }

    pub fn size(&self) -> usize {
        self.end.offset_from(self.start)
    }

    pub fn active_size(&self) -> usize {
        self.alloc_top.offset_from(self.start)
    }

    pub fn active_region(&self) -> Region {
        Region::new(self.start, self.alloc_top)
    }

    pub fn total_region(&self) -> Region {
        Region::new(self.start, self.end)
    }

    pub fn committed_region(&self) -> Region {
        Region::new(self.start, self.alloc_limit)
    }
}
<commit_msg>remove single_region(_mut) from OldGenProtected<commit_after>use parking_lot::{Mutex, MutexGuard};
use std::cmp::{max, min};
use std::mem::replace;

use gc::swiper::card::CardTable;
use gc::swiper::controller::SharedHeapConfig;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::{arena, Address, Region, GEN_SIZE};
use mem;
use object::offset_of_array_data;

pub struct OldGen {
    total: Region,
    protected: Mutex<OldGenProtected>,

    crossing_map: CrossingMap,
    card_table: CardTable,
    config: SharedHeapConfig,
}

impl OldGen {
    pub fn new(
        start: Address,
        end: Address,
        crossing_map: CrossingMap,
        card_table: CardTable,
        config: SharedHeapConfig,
    ) -> OldGen {
        let total = Region::new(start, end);
        let old = OldGen {
            total: total.clone(),
            protected: Mutex::new(OldGenProtected::new(total)),

            crossing_map: crossing_map,
            card_table: card_table,
            config: config,
        };

        old
    }

    pub fn total(&self) -> Region {
        self.total.clone()
    }

    pub fn total_start(&self) -> Address {
        self.total.start
    }

    pub fn committed_size(&self) -> usize {
        let protected = self.protected.lock();

        protected.size
    }

    pub fn active_size(&self) -> usize {
        let protected = self.protected.lock();
        let mut size = 0;

        for old_region in &protected.regions {
            size += old_region.active_size();
        }

        size
    }

    pub fn alloc(&self, size: usize) -> Address {
        let mut protected = self.protected.lock();
        protected.alloc(&self.config, size)
    }

    pub fn update_crossing(&self, old: Address, new: Address, array_ref: bool) {
        if (old.to_usize() >> CARD_SIZE_BITS) == (new.to_usize() >> CARD_SIZE_BITS) {
            // object does not span multiple cards
            if (old.to_usize() & (CARD_SIZE - 1)) == 0 {
                let card = self.card_table.card_idx(old.into());
                self.crossing_map.set_first_object(card, 0);
            }
        } else if array_ref {
            let new_card_idx = self.card_table.card_idx(new.into());
            let new_card_start = self.card_table.to_address(new_card_idx);

            let old_card_idx = self.card_table.card_idx(old);
            let old_card_end = self.card_table.to_address(old_card_idx).offset(CARD_SIZE);

            let refs_per_card = CARD_SIZE / mem::ptr_width_usize();
            let mut loop_card_start = old_card_idx.to_usize() + 1;

            // If you allocate an object array just before the card end,
            // it could happen that the card starts with part of the header
            // or the length-field.
            if old.offset(offset_of_array_data() as usize) > old_card_end {
                let diff = old_card_end.offset_from(old) / mem::ptr_width_usize();
                self.crossing_map
                    .set_array_start(loop_card_start.into(), diff);

                loop_card_start += 1;
            }

            // all cards between ]old_card; new_card[ are full with references
            for c in loop_card_start..new_card_idx.to_usize() {
                self.crossing_map
                    .set_references_at_start(c.into(), refs_per_card);
            }

            // new_card starts with x references, then next object
            if new_card_idx.to_usize() >= loop_card_start {
                let refs_dist = new.offset_from(new_card_start) / mem::ptr_width_usize();

                if refs_dist > 0 {
                    self.crossing_map
                        .set_references_at_start(new_card_idx, refs_dist);
                } else {
                    self.crossing_map.set_first_object(new_card_idx, 0);
                }
            }
        } else {
            let new_card_idx = self.card_table.card_idx(new.into());
            let new_card_start = self.card_table.to_address(new_card_idx);

            let old_card_idx = self.card_table.card_idx(old.into());

            // all cards between ]old_card; new_card[ are set to NoRefs
            for c in old_card_idx.to_usize() + 1..new_card_idx.to_usize() {
                self.crossing_map.set_no_references(c.into());
            }

            // new_card stores x words of object, then next object
            self.crossing_map.set_first_object(
                new_card_idx,
                new.offset_from(new_card_start) / mem::ptr_width_usize(),
            );
        }
    }

    pub fn protected(&self) -> MutexGuard<OldGenProtected> {
        self.protected.lock()
    }
}

pub struct OldGenProtected {
    pub total: Region,
    pub size: usize,
    pub regions: Vec<OldRegion>,
}

impl OldGenProtected {
    fn new(total: Region) -> OldGenProtected {
        OldGenProtected {
            total: total.clone(),
            size: 0,
            regions: vec![OldRegion::new(total)],
        }
    }

    pub fn contains_slow(&self, addr: Address) -> bool {
        for old_region in &self.regions {
            if old_region.start <= addr && addr < old_region.alloc_top {
                return true;
            }
        }

        false
    }

    pub fn commit_single_region(&mut self, top: Address) {
        let limit = top.align_gen();
        assert!(self.total.valid_top(limit));

        let mut last = self.total.start;

        for region in &self.regions {
            let start = last;
            let end = min(region.start, limit);
            let size = end.offset_from(start);

            if size > 0 {
                arena::commit(start, size, false);
            }

            if end == limit {
                return;
            }

            last = region.alloc_limit;
        }

        let start = last;
        let end = limit;

        if end <= start {
            return;
        }

        let size = end.offset_from(start);
        arena::commit(start, size, false);
    }

    pub fn update_single_region(&mut self, top: Address) {
        let limit = top.align_gen();
        assert!(self.total.valid_top(limit));

        let region = OldRegion {
            start: self.total.start,
            end: self.total.end,

            alloc_top: top,
            alloc_limit: limit,
        };

        let regions = replace(&mut self.regions, vec![region]);

        for region in regions {
            if limit >= region.alloc_limit {
                continue;
            }

            let start = max(region.start, limit);
            let size = region.alloc_limit.offset_from(start);

            if size > 0 {
                arena::forget(start, size);
            }
        }
    }

    pub fn alloc(&mut self, config: &SharedHeapConfig, size: usize) -> Address {
        let ptr = self.pure_alloc(size);

        if ptr.is_non_null() {
            return ptr;
        }

        {
            let mut config = config.lock();

            if !config.grow_old(GEN_SIZE) {
                return Address::null();
            }
        }

        if !self.extend(GEN_SIZE) {
            return Address::null();
        }

        self.pure_alloc(size)
    }

    fn pure_alloc(&mut self, size: usize) -> Address {
        for old_region in &mut self.regions {
            let new_alloc_top = old_region.alloc_top.offset(size);

            if new_alloc_top <= old_region.alloc_limit {
                let addr = old_region.alloc_top;
                old_region.alloc_top = new_alloc_top;
                return addr;
            }
        }

        Address::null()
    }

    fn extend(&mut self, size: usize) -> bool {
        for old_region in &mut self.regions {
            let new_alloc_limit = old_region.alloc_limit.offset(size);

            if new_alloc_limit <= old_region.end {
                arena::commit(old_region.alloc_limit, size, false);
                old_region.alloc_limit = new_alloc_limit;
                return true;
            }
        }

        false
    }
}

#[derive(Clone)]
pub struct OldRegion {
    start: Address,
    end: Address,

    alloc_top: Address,
    alloc_limit: Address,
}

impl OldRegion {
    fn new(region: Region) -> OldRegion {
        OldRegion {
            start: region.start,
            end: region.end,

            alloc_top: region.start,
            alloc_limit: region.start,
        }
    }

    pub fn start(&self) -> Address {
        self.start
    }

    pub fn top(&self) -> Address {
        self.alloc_top
    }

    pub fn size(&self) -> usize {
        self.end.offset_from(self.start)
    }

    pub fn active_size(&self) -> usize {
        self.alloc_top.offset_from(self.start)
    }

    pub fn active_region(&self) -> Region {
        Region::new(self.start, self.alloc_top)
    }

    pub fn total_region(&self) -> Region {
        Region::new(self.start, self.end)
    }

    pub fn committed_region(&self) -> Region {
        Region::new(self.start, self.alloc_limit)
    }
}
<|endoftext|>