<commit_before>use std::fmt::Write;

use syntax_pos::symbol::Symbol;
use rustc::ty::layout::{self, Size, Primitive};
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
    Scalar, AllocType, EvalResult, ScalarMaybeUndef,
};

use super::{
    MPlaceTy, PlaceExtra, Machine, EvalContext
};

macro_rules! validation_failure{
    ($what:expr, $where:expr, $details:expr) => {{
        let where_ = path_format($where);
        let where_ = if where_.is_empty() {
            String::new()
        } else {
            format!(" at {}", where_)
        };
        err!(ValidationFailure(format!(
            "encountered {}{}, but expected {}",
            $what, where_, $details,
        )))
    }};
    ($what:expr, $where:expr) => {{
        let where_ = path_format($where);
        let where_ = if where_.is_empty() {
            String::new()
        } else {
            format!(" at {}", where_)
        };
        err!(ValidationFailure(format!(
            "encountered {}{}",
            $what, where_,
        )))
    }};
}

/// We want to show a nice path to the invalid field for diagnotsics,
/// but avoid string operations in the happy case where no error happens.
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
/// need to later print something for the user.
#[derive(Copy, Clone, Debug)]
pub enum PathElem {
    Field(Symbol),
    ClosureVar(Symbol),
    ArrayElem(usize),
    TupleElem(usize),
    Deref,
    Tag,
}

// Adding a Deref and making a copy of the path to be put into the queue
// always go together.  This one does it with only new allocation.
fn path_clone_and_deref(path: &Vec<PathElem>) -> Vec<PathElem> {
    let mut new_path = Vec::with_capacity(path.len()+1);
    new_path.clone_from(path);
    new_path.push(PathElem::Deref);
    new_path
}

/// Format a path
fn path_format(path: &Vec<PathElem>) -> String {
    use self::PathElem::*;

    let mut out = String::new();
    for elem in path.iter() {
        match elem {
            Field(name) => write!(out, ".{}", name).unwrap(),
            ClosureVar(name) => write!(out, ".<closure-var({})>", name).unwrap(),
            TupleElem(idx) => write!(out, ".{}", idx).unwrap(),
            ArrayElem(idx) => write!(out, "[{}]", idx).unwrap(),
            Deref =>
                // This does not match Rust syntax, but it is more readable for long paths -- and
                // some of the other items here also are not Rust syntax.  Actually we can't
                // even use the usual syntax because we are just showing the projections,
                // not the root.
                write!(out, ".<deref>").unwrap(),
            Tag => write!(out, ".<enum-tag>").unwrap(),
        }
    }
    out
}

impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
    fn validate_scalar(
        &self,
        value: ScalarMaybeUndef,
        size: Size,
        scalar: &layout::Scalar,
        path: &Vec<PathElem>,
        ty: Ty,
    ) -> EvalResult<'tcx> {
        trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
        let (lo, hi) = scalar.valid_range.clone().into_inner();

        let value = match value {
            ScalarMaybeUndef::Scalar(scalar) => scalar,
            ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
        };

        let bits = match value {
            Scalar::Bits { bits, size: value_size } => {
                assert_eq!(value_size as u64, size.bytes());
                bits
            },
            Scalar::Ptr(_) => {
                let ptr_size = self.memory.pointer_size();
                let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
                return if lo > hi {
                    if lo - hi == 1 {
                        // no gap, all values are ok
                        Ok(())
                    } else if hi < ptr_max || lo > 1 {
                        let max = u128::max_value() >> (128 - size.bits());
                        validation_failure!(
                            "pointer",
                            path,
                            format!("something in the range {:?} or {:?}", 0..=lo, hi..=max)
                        )
                    } else {
                        Ok(())
                    }
                } else if hi < ptr_max || lo > 1 {
                    validation_failure!(
                        "pointer",
                        path,
                        format!("something in the range {:?}", scalar.valid_range)
                    )
                } else {
                    Ok(())
                };
            },
        };

        // char gets a special treatment, because its number space is not contiguous so `TyLayout`
        // has no special checks for chars
        match ty.sty {
            ty::TyChar => {
                debug_assert_eq!(size.bytes(), 4);
                if ::std::char::from_u32(bits as u32).is_none() {
                    return validation_failure!(
                        "character",
                        path,
                        "a valid unicode codepoint"
                    );
                }
            }
            _ => {},
        }

        use std::ops::RangeInclusive;
        let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
        if lo > hi {
            if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
                Ok(())
            } else {
                validation_failure!(
                    bits,
                    path,
                    format!("something in the range {:?} or {:?}", ..=hi, lo..)
                )
            }
        } else {
            if in_range(scalar.valid_range.clone()) {
                Ok(())
            } else {
                validation_failure!(
                    bits,
                    path,
                    format!("something in the range {:?}", scalar.valid_range)
                )
            }
        }
    }

    /// This function checks the memory where `dest` points to.  The place must be sized
    /// (i.e., dest.extra == PlaceExtra::None).
    /// It will error if the bits at the destination do not match the ones described by the layout.
    /// The `path` may be pushed to, but the part that is present when the function
    /// starts must not be changed!
    pub fn validate_mplace(
        &self,
        dest: MPlaceTy<'tcx>,
        path: &mut Vec<PathElem>,
        seen: &mut FxHashSet<(MPlaceTy<'tcx>)>,
        todo: &mut Vec<(MPlaceTy<'tcx>, Vec<PathElem>)>,
    ) -> EvalResult<'tcx> {
        self.memory.dump_alloc(dest.to_ptr()?.alloc_id);
        trace!("validate_mplace: {:?}, {:#?}", *dest, dest.layout);

        // Find the right variant.  We have to handle this as a prelude, not via
        // proper recursion with the new inner layout, to be able to later nicely
        // print the field names of the enum field that is being accessed.
        let (variant, dest) = match dest.layout.variants {
            layout::Variants::NicheFilling { niche: ref tag, .. } |
            layout::Variants::Tagged { ref tag, .. } => {
                let size = tag.value.size(self);
                // we first read the tag value as scalar, to be able to validate it
                let tag_mplace = self.mplace_field(dest, 0)?;
                let tag_value = self.read_scalar(tag_mplace.into())?;
                path.push(PathElem::Tag);
                self.validate_scalar(
                    tag_value, size, tag, &path, tag_mplace.layout.ty
                )?;
                path.pop(); // remove the element again
                // then we read it again to get the index, to continue
                let variant = self.read_discriminant_as_variant_index(dest.into())?;
                let inner_dest = self.mplace_downcast(dest, variant)?;
                // Put the variant projection onto the path, as a field
                path.push(PathElem::Field(dest.layout.ty.ty_adt_def().unwrap().variants[variant].name));
                trace!("variant layout: {:#?}", dest.layout);
                (variant, inner_dest)
            },
            layout::Variants::Single { index } => {
                (index, dest)
            }
        };

        // Remember the length, in case we need to truncate
        let path_len = path.len();

        // Validate all fields
        match dest.layout.fields {
            // primitives are unions with zero fields
            // FIXME: Use some other indicator instead, like `layout.abi`.
            layout::FieldPlacement::Union(0) => {
                match dest.layout.abi {
                    // nothing to do, whatever the pointer points to, it is never going to be read
                    layout::Abi::Uninhabited =>
                        return validation_failure!("a value of an uninhabited type", path),
                    // check that the scalar is a valid pointer or that its bit range matches the
                    // expectation.
                    layout::Abi::Scalar(ref scalar_layout) => {
                        let size = scalar_layout.value.size(self);
                        let value = self.read_value(dest.into())?;
                        let scalar = value.to_scalar_or_undef();
                        self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
                        if scalar_layout.value == Primitive::Pointer {
                            // ignore integer pointers, we can't reason about the final hardware
                            if let Scalar::Ptr(ptr) = scalar.not_undef()? {
                                let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
                                if let Some(AllocType::Static(did)) = alloc_kind {
                                    // statics from other crates are already checked.
                                    // extern statics should not be validated as they have no body.
                                    if !did.is_local() || self.tcx.is_foreign_item(did) {
                                        return Ok(());
                                    }
                                }
                                if value.layout.ty.builtin_deref(false).is_some() {
                                    trace!("Recursing below ptr {:#?}", value);
                                    let ptr_place = self.ref_to_mplace(value)?;
                                    // we have not encountered this pointer+layout combination before
                                    if seen.insert(ptr_place) {
                                        todo.push((ptr_place, path_clone_and_deref(path)));
                                    }
                                }
                            }
                        }
                    },
                    _ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", dest.layout.abi),
                }
            }
            layout::FieldPlacement::Union(_) => {
                // We can't check unions, their bits are allowed to be anything.
                // The fields don't need to correspond to any bit pattern of the union's fields.
                // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
            },
            layout::FieldPlacement::Array { .. } => {
                for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
                    let field = field?;
                    path.push(PathElem::ArrayElem(i));
                    self.validate_mplace(field, path, seen, todo)?;
                    path.truncate(path_len);
                }
            },
            layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
                // Fat pointers need special treatment.
                match dest.layout.ty.builtin_deref(true).map(|tam| &tam.ty.sty) {
                    | Some(ty::TyStr)
                    | Some(ty::TySlice(_)) => {
                        // check the length (for nicer error messages); must be valid even
                        // for a raw pointer.
                        let len_mplace = self.mplace_field(dest, 1)?;
                        let len = self.read_scalar(len_mplace.into())?;
                        let len = match len.to_bits(len_mplace.layout.size) {
                            Err(_) => return validation_failure!("length is not a valid integer", path),
                            Ok(len) => len as u64,
                        };
                        // for safe ptrs, get the fat ptr, and recursively check it
                        if !dest.layout.ty.is_unsafe_ptr() {
                            let ptr = self.ref_to_mplace(self.read_value(dest.into())?)?;
                            assert_eq!(ptr.extra, PlaceExtra::Length(len));
                            let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
                            if seen.insert(unpacked_ptr) {
                                todo.push((unpacked_ptr, path_clone_and_deref(path)));
                            }
                        }
                    },
                    Some(ty::TyDynamic(..)) => {
                        // check the vtable (for nicer error messages); must be valid even for a
                        // raw ptr.
                        let vtable = self.read_scalar(self.mplace_field(dest, 1)?.into())?;
                        let vtable = match vtable.to_ptr() {
                            Err(_) => return validation_failure!("vtable address is not a pointer", path),
                            Ok(vtable) => vtable,
                        };
                        // for safe ptrs, get the fat ptr, and recursively check it
                        if !dest.layout.ty.is_unsafe_ptr() {
                            let ptr = self.ref_to_mplace(self.read_value(dest.into())?)?;
                            assert_eq!(ptr.extra, PlaceExtra::Vtable(vtable));
                            let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
                            if seen.insert(unpacked_ptr) {
                                todo.push((unpacked_ptr, path_clone_and_deref(path)));
                            }
                            // FIXME: More checks for the vtable... making sure it is exactly
                            // the one one would expect for this type.
                        }
                    },
                    Some(ty) =>
                        bug!("Unexpected fat pointer target type {:?}", ty),
                    None => {
                        // Not a pointer, perform regular aggregate handling below
                        for i in 0..offsets.len() {
                            let field = self.mplace_field(dest, i as u64)?;
                            path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
                            self.validate_mplace(field, path, seen, todo)?;
                            path.truncate(path_len);
                        }
                        // FIXME: For a TyStr, check that this is valid UTF-8.
                    },
                }
            }
        }
        Ok(())
    }

    fn aggregate_field_path_elem(&self, ty: Ty<'tcx>, variant: usize, field: usize) -> PathElem {
        match ty.sty {
            // generators and closures.
            ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
                let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
                PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
            }

            // tuples
            ty::TyTuple(_) => PathElem::TupleElem(field),

            // enums
            ty::TyAdt(def, ..) if def.is_enum() => {
                let variant = &def.variants[variant];
                PathElem::Field(variant.fields[field].ident.name)
            }

            // other ADTs
            ty::TyAdt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),

            // nothing else has an aggregate layout
            _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", ty),
        }
    }
}
<commit_msg>fix a comment in validity<commit_after>use std::fmt::Write;

use syntax_pos::symbol::Symbol;
use rustc::ty::layout::{self, Size, Primitive};
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
    Scalar, AllocType, EvalResult, ScalarMaybeUndef,
};

use super::{
    MPlaceTy, PlaceExtra, Machine, EvalContext
};

macro_rules! validation_failure{
    ($what:expr, $where:expr, $details:expr) => {{
        let where_ = path_format($where);
        let where_ = if where_.is_empty() {
            String::new()
        } else {
            format!(" at {}", where_)
        };
        err!(ValidationFailure(format!(
            "encountered {}{}, but expected {}",
            $what, where_, $details,
        )))
    }};
    ($what:expr, $where:expr) => {{
        let where_ = path_format($where);
        let where_ = if where_.is_empty() {
            String::new()
        } else {
            format!(" at {}", where_)
        };
        err!(ValidationFailure(format!(
            "encountered {}{}",
            $what, where_,
        )))
    }};
}

/// We want to show a nice path to the invalid field for diagnotsics,
/// but avoid string operations in the happy case where no error happens.
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
/// need to later print something for the user.
#[derive(Copy, Clone, Debug)]
pub enum PathElem {
    Field(Symbol),
    ClosureVar(Symbol),
    ArrayElem(usize),
    TupleElem(usize),
    Deref,
    Tag,
}

// Adding a Deref and making a copy of the path to be put into the queue
// always go together.  This one does it with only new allocation.
fn path_clone_and_deref(path: &Vec<PathElem>) -> Vec<PathElem> {
    let mut new_path = Vec::with_capacity(path.len()+1);
    new_path.clone_from(path);
    new_path.push(PathElem::Deref);
    new_path
}

/// Format a path
fn path_format(path: &Vec<PathElem>) -> String {
    use self::PathElem::*;

    let mut out = String::new();
    for elem in path.iter() {
        match elem {
            Field(name) => write!(out, ".{}", name).unwrap(),
            ClosureVar(name) => write!(out, ".<closure-var({})>", name).unwrap(),
            TupleElem(idx) => write!(out, ".{}", idx).unwrap(),
            ArrayElem(idx) => write!(out, "[{}]", idx).unwrap(),
            Deref =>
                // This does not match Rust syntax, but it is more readable for long paths -- and
                // some of the other items here also are not Rust syntax.  Actually we can't
                // even use the usual syntax because we are just showing the projections,
                // not the root.
                write!(out, ".<deref>").unwrap(),
            Tag => write!(out, ".<enum-tag>").unwrap(),
        }
    }
    out
}

impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
    fn validate_scalar(
        &self,
        value: ScalarMaybeUndef,
        size: Size,
        scalar: &layout::Scalar,
        path: &Vec<PathElem>,
        ty: Ty,
    ) -> EvalResult<'tcx> {
        trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
        let (lo, hi) = scalar.valid_range.clone().into_inner();

        let value = match value {
            ScalarMaybeUndef::Scalar(scalar) => scalar,
            ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
        };

        let bits = match value {
            Scalar::Bits { bits, size: value_size } => {
                assert_eq!(value_size as u64, size.bytes());
                bits
            },
            Scalar::Ptr(_) => {
                let ptr_size = self.memory.pointer_size();
                let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
                return if lo > hi {
                    if lo - hi == 1 {
                        // no gap, all values are ok
                        Ok(())
                    } else if hi < ptr_max || lo > 1 {
                        let max = u128::max_value() >> (128 - size.bits());
                        validation_failure!(
                            "pointer",
                            path,
                            format!("something in the range {:?} or {:?}", 0..=lo, hi..=max)
                        )
                    } else {
                        Ok(())
                    }
                } else if hi < ptr_max || lo > 1 {
                    validation_failure!(
                        "pointer",
                        path,
                        format!("something in the range {:?}", scalar.valid_range)
                    )
                } else {
                    Ok(())
                };
            },
        };

        // char gets a special treatment, because its number space is not contiguous so `TyLayout`
        // has no special checks for chars
        match ty.sty {
            ty::TyChar => {
                debug_assert_eq!(size.bytes(), 4);
                if ::std::char::from_u32(bits as u32).is_none() {
                    return validation_failure!(
                        "character",
                        path,
                        "a valid unicode codepoint"
                    );
                }
            }
            _ => {},
        }

        use std::ops::RangeInclusive;
        let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
        if lo > hi {
            if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
                Ok(())
            } else {
                validation_failure!(
                    bits,
                    path,
                    format!("something in the range {:?} or {:?}", ..=hi, lo..)
                )
            }
        } else {
            if in_range(scalar.valid_range.clone()) {
                Ok(())
            } else {
                validation_failure!(
                    bits,
                    path,
                    format!("something in the range {:?}", scalar.valid_range)
                )
            }
        }
    }

    /// This function checks the memory where `dest` points to.  The place must be sized
    /// (i.e., dest.extra == PlaceExtra::None).
    /// It will error if the bits at the destination do not match the ones described by the layout.
    /// The `path` may be pushed to, but the part that is present when the function
    /// starts must not be changed!
    pub fn validate_mplace(
        &self,
        dest: MPlaceTy<'tcx>,
        path: &mut Vec<PathElem>,
        seen: &mut FxHashSet<(MPlaceTy<'tcx>)>,
        todo: &mut Vec<(MPlaceTy<'tcx>, Vec<PathElem>)>,
    ) -> EvalResult<'tcx> {
        self.memory.dump_alloc(dest.to_ptr()?.alloc_id);
        trace!("validate_mplace: {:?}, {:#?}", *dest, dest.layout);

        // Find the right variant.  We have to handle this as a prelude, not via
        // proper recursion with the new inner layout, to be able to later nicely
        // print the field names of the enum field that is being accessed.
        let (variant, dest) = match dest.layout.variants {
            layout::Variants::NicheFilling { niche: ref tag, .. } |
            layout::Variants::Tagged { ref tag, .. } => {
                let size = tag.value.size(self);
                // we first read the tag value as scalar, to be able to validate it
                let tag_mplace = self.mplace_field(dest, 0)?;
                let tag_value = self.read_scalar(tag_mplace.into())?;
                path.push(PathElem::Tag);
                self.validate_scalar(
                    tag_value, size, tag, &path, tag_mplace.layout.ty
                )?;
                path.pop(); // remove the element again
                // then we read it again to get the index, to continue
                let variant = self.read_discriminant_as_variant_index(dest.into())?;
                let inner_dest = self.mplace_downcast(dest, variant)?;
                // Put the variant projection onto the path, as a field
                path.push(PathElem::Field(dest.layout.ty.ty_adt_def().unwrap().variants[variant].name));
                trace!("variant layout: {:#?}", dest.layout);
                (variant, inner_dest)
            },
            layout::Variants::Single { index } => {
                (index, dest)
            }
        };

        // Remember the length, in case we need to truncate
        let path_len = path.len();

        // Validate all fields
        match dest.layout.fields {
            // primitives are unions with zero fields
            // We still check `layout.fields`, not `layout.abi`, because `layout.abi`
            // is `Scalar` for newtypes around scalars, but we want to descend through the
            // fields to get a proper `path`.
            layout::FieldPlacement::Union(0) => {
                match dest.layout.abi {
                    // nothing to do, whatever the pointer points to, it is never going to be read
                    layout::Abi::Uninhabited =>
                        return validation_failure!("a value of an uninhabited type", path),
                    // check that the scalar is a valid pointer or that its bit range matches the
                    // expectation.
                    layout::Abi::Scalar(ref scalar_layout) => {
                        let size = scalar_layout.value.size(self);
                        let value = self.read_value(dest.into())?;
                        let scalar = value.to_scalar_or_undef();
                        self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
                        if scalar_layout.value == Primitive::Pointer {
                            // ignore integer pointers, we can't reason about the final hardware
                            if let Scalar::Ptr(ptr) = scalar.not_undef()? {
                                let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
                                if let Some(AllocType::Static(did)) = alloc_kind {
                                    // statics from other crates are already checked.
                                    // extern statics should not be validated as they have no body.
                                    if !did.is_local() || self.tcx.is_foreign_item(did) {
                                        return Ok(());
                                    }
                                }
                                if value.layout.ty.builtin_deref(false).is_some() {
                                    trace!("Recursing below ptr {:#?}", value);
                                    let ptr_place = self.ref_to_mplace(value)?;
                                    // we have not encountered this pointer+layout combination before
                                    if seen.insert(ptr_place) {
                                        todo.push((ptr_place, path_clone_and_deref(path)));
                                    }
                                }
                            }
                        }
                    },
                    _ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", dest.layout.abi),
                }
            }
            layout::FieldPlacement::Union(_) => {
                // We can't check unions, their bits are allowed to be anything.
                // The fields don't need to correspond to any bit pattern of the union's fields.
                // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
            },
            layout::FieldPlacement::Array { .. } => {
                for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
                    let field = field?;
                    path.push(PathElem::ArrayElem(i));
                    self.validate_mplace(field, path, seen, todo)?;
                    path.truncate(path_len);
                }
            },
            layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
                // Fat pointers need special treatment.
                match dest.layout.ty.builtin_deref(true).map(|tam| &tam.ty.sty) {
                    | Some(ty::TyStr)
                    | Some(ty::TySlice(_)) => {
                        // check the length (for nicer error messages); must be valid even
                        // for a raw pointer.
                        let len_mplace = self.mplace_field(dest, 1)?;
                        let len = self.read_scalar(len_mplace.into())?;
                        let len = match len.to_bits(len_mplace.layout.size) {
                            Err(_) => return validation_failure!("length is not a valid integer", path),
                            Ok(len) => len as u64,
                        };
                        // for safe ptrs, get the fat ptr, and recursively check it
                        if !dest.layout.ty.is_unsafe_ptr() {
                            let ptr = self.ref_to_mplace(self.read_value(dest.into())?)?;
                            assert_eq!(ptr.extra, PlaceExtra::Length(len));
                            let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
                            if seen.insert(unpacked_ptr) {
                                todo.push((unpacked_ptr, path_clone_and_deref(path)));
                            }
                        }
                    },
                    Some(ty::TyDynamic(..)) => {
                        // check the vtable (for nicer error messages); must be valid even for a
                        // raw ptr.
                        let vtable = self.read_scalar(self.mplace_field(dest, 1)?.into())?;
                        let vtable = match vtable.to_ptr() {
                            Err(_) => return validation_failure!("vtable address is not a pointer", path),
                            Ok(vtable) => vtable,
                        };
                        // for safe ptrs, get the fat ptr, and recursively check it
                        if !dest.layout.ty.is_unsafe_ptr() {
                            let ptr = self.ref_to_mplace(self.read_value(dest.into())?)?;
                            assert_eq!(ptr.extra, PlaceExtra::Vtable(vtable));
                            let unpacked_ptr = self.unpack_unsized_mplace(ptr)?;
                            if seen.insert(unpacked_ptr) {
                                todo.push((unpacked_ptr, path_clone_and_deref(path)));
                            }
                            // FIXME: More checks for the vtable... making sure it is exactly
                            // the one one would expect for this type.
                        }
                    },
                    Some(ty) =>
                        bug!("Unexpected fat pointer target type {:?}", ty),
                    None => {
                        // Not a pointer, perform regular aggregate handling below
                        for i in 0..offsets.len() {
                            let field = self.mplace_field(dest, i as u64)?;
                            path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
                            self.validate_mplace(field, path, seen, todo)?;
                            path.truncate(path_len);
                        }
                        // FIXME: For a TyStr, check that this is valid UTF-8.
                    },
                }
            }
        }
        Ok(())
    }

    fn aggregate_field_path_elem(&self, ty: Ty<'tcx>, variant: usize, field: usize) -> PathElem {
        match ty.sty {
            // generators and closures.
            ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
                let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
                let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
                PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
            }

            // tuples
            ty::TyTuple(_) => PathElem::TupleElem(field),

            // enums
            ty::TyAdt(def, ..) if def.is_enum() => {
                let variant = &def.variants[variant];
                PathElem::Field(variant.fields[field].ident.name)
            }

            // other ADTs
            ty::TyAdt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),

            // nothing else has an aggregate layout
            _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", ty),
        }
    }
}
<|endoftext|>


<commit_before>//! A number of passes which remove various redundancies in the CFG.
//!
//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals`
//! gets rid of all the unnecessary local variable declarations.
//!
//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often.
//! Most of the passes should not care or be impacted in meaningful ways due to extra locals
//! either, so running the pass once, right before codegen, should suffice.
//!
//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus
//! one should run it after every pass which may modify CFG in significant ways. This pass must
//! also be run before any analysis passes because it removes dead blocks, and some of these can be
//! ill-typed.
//!
//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have
//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's
//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A
//! standard example of the situation is:
//!
//! ```rust
//!   fn example() {
//!       let _a: char = { return; };
//!   }
//! ```
//!
//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.

use crate::transform::{MirPass, MirSource};
use rustc::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc::mir::*;
use rustc::ty::{self, TyCtxt};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use std::borrow::Cow;

pub struct SimplifyCfg {
    label: String,
}

impl SimplifyCfg {
    pub fn new(label: &str) -> Self {
        SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
    }
}

pub fn simplify_cfg(body: &mut BodyAndCache<'_>) {
    CfgSimplifier::new(body).simplify();
    remove_dead_blocks(body);

    // FIXME: Should probably be moved into some kind of pass manager
    body.basic_blocks_mut().raw.shrink_to_fit();
}

impl<'tcx> MirPass<'tcx> for SimplifyCfg {
    fn name(&self) -> Cow<'_, str> {
        Cow::Borrowed(&self.label)
    }

    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
        simplify_cfg(body);
    }
}

pub struct CfgSimplifier<'a, 'tcx> {
    basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
    pred_count: IndexVec<BasicBlock, u32>,
}

impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
    pub fn new(body: &'a mut BodyAndCache<'tcx>) -> Self {
        let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());

        // we can't use mir.predecessors() here because that counts
        // dead blocks, which we don't want to.
        pred_count[START_BLOCK] = 1;

        for (_, data) in traversal::preorder(body) {
            if let Some(ref term) = data.terminator {
                for &tgt in term.successors() {
                    pred_count[tgt] += 1;
                }
            }
        }

        let basic_blocks = body.basic_blocks_mut();

        CfgSimplifier { basic_blocks, pred_count }
    }

    pub fn simplify(mut self) {
        self.strip_nops();

        let mut start = START_BLOCK;
        let mut new_stmts = vec![];

        loop {
            let mut changed = false;

            self.collapse_goto_chain(&mut start, &mut changed);

            for bb in self.basic_blocks.indices() {
                if self.pred_count[bb] == 0 {
                    continue;
                }

                debug!("simplifying {:?}", bb);

                let mut terminator =
                    self.basic_blocks[bb].terminator.take().expect("invalid terminator state");

                for successor in terminator.successors_mut() {
                    self.collapse_goto_chain(successor, &mut changed);
                }

                let mut inner_changed = true;
                while inner_changed {
                    inner_changed = false;
                    inner_changed |= self.simplify_branch(&mut terminator);
                    inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator);
                    changed |= inner_changed;
                }

                let data = &mut self.basic_blocks[bb];
                data.statements.extend(new_stmts.drain(..));
                data.terminator = Some(terminator);

                changed |= inner_changed;
            }

            if !changed {
                break;
            }
        }

        if start != START_BLOCK {
            debug_assert!(self.pred_count[START_BLOCK] == 0);
            self.basic_blocks.swap(START_BLOCK, start);
            self.pred_count.swap(START_BLOCK, start);

            // pred_count == 1 if the start block has no predecessor _blocks_.
            if self.pred_count[START_BLOCK] > 1 {
                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
                    if self.pred_count[bb] == 0 {
                        continue;
                    }

                    for target in data.terminator_mut().successors_mut() {
                        if *target == start {
                            *target = START_BLOCK;
                        }
                    }
                }
            }
        }
    }

    // Collapse a goto chain starting from `start`
    fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) {
        let mut terminator = match self.basic_blocks[*start] {
            BasicBlockData {
                ref statements,
                terminator:
                    ref mut terminator @ Some(Terminator { kind: TerminatorKind::Goto { .. }, .. }),
                ..
            } if statements.is_empty() => terminator.take(),
            // if `terminator` is None, this means we are in a loop. In that
            // case, let all the loop collapse to its entry.
            _ => return,
        };

        let target = match terminator {
            Some(Terminator { kind: TerminatorKind::Goto { ref mut target }, .. }) => {
                self.collapse_goto_chain(target, changed);
                *target
            }
            _ => unreachable!(),
        };
        self.basic_blocks[*start].terminator = terminator;

        debug!("collapsing goto chain from {:?} to {:?}", *start, target);

        *changed |= *start != target;

        if self.pred_count[*start] == 1 {
            // This is the last reference to *start, so the pred-count to
            // to target is moved into the current block.
            self.pred_count[*start] = 0;
        } else {
            self.pred_count[target] += 1;
            self.pred_count[*start] -= 1;
        }

        *start = target;
    }

    // merge a block with 1 `goto` predecessor to its parent
    fn merge_successor(
        &mut self,
        new_stmts: &mut Vec<Statement<'tcx>>,
        terminator: &mut Terminator<'tcx>,
    ) -> bool {
        let target = match terminator.kind {
            TerminatorKind::Goto { target } if self.pred_count[target] == 1 => target,
            _ => return false,
        };

        debug!("merging block {:?} into {:?}", target, terminator);
        *terminator = match self.basic_blocks[target].terminator.take() {
            Some(terminator) => terminator,
            None => {
                // unreachable loop - this should not be possible, as we
                // don't strand blocks, but handle it correctly.
                return false;
            }
        };
        new_stmts.extend(self.basic_blocks[target].statements.drain(..));
        self.pred_count[target] = 0;

        true
    }

    // turn a branch with all successors identical to a goto
    fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
        match terminator.kind {
            TerminatorKind::SwitchInt { .. } => {}
            _ => return false,
        };

        let first_succ = {
            if let Some(&first_succ) = terminator.successors().nth(0) {
                if terminator.successors().all(|s| *s == first_succ) {
                    let count = terminator.successors().count();
                    self.pred_count[first_succ] -= (count - 1) as u32;
                    first_succ
                } else {
                    return false;
                }
            } else {
                return false;
            }
        };

        debug!("simplifying branch {:?}", terminator);
        terminator.kind = TerminatorKind::Goto { target: first_succ };
        true
    }

    fn strip_nops(&mut self) {
        for blk in self.basic_blocks.iter_mut() {
            blk.statements
                .retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { true })
        }
    }
}

pub fn remove_dead_blocks(body: &mut BodyAndCache<'_>) {
    let mut seen = BitSet::new_empty(body.basic_blocks().len());
    for (bb, _) in traversal::preorder(body) {
        seen.insert(bb.index());
    }

    let basic_blocks = body.basic_blocks_mut();

    let num_blocks = basic_blocks.len();
    let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
    let mut used_blocks = 0;
    for alive_index in seen.iter() {
        replacements[alive_index] = BasicBlock::new(used_blocks);
        if alive_index != used_blocks {
            // Swap the next alive block data with the current available slot. Since
            // alive_index is non-decreasing this is a valid operation.
            basic_blocks.raw.swap(alive_index, used_blocks);
        }
        used_blocks += 1;
    }
    basic_blocks.raw.truncate(used_blocks);

    for block in basic_blocks {
        for target in block.terminator_mut().successors_mut() {
            *target = replacements[target.index()];
        }
    }
}

pub struct SimplifyLocals;

impl<'tcx> MirPass<'tcx> for SimplifyLocals {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        trace!("running SimplifyLocals on {:?}", source);
        let locals = {
            let read_only_cache = read_only!(body);
            let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()), body };
            marker.visit_body(read_only_cache);
            // Return pointer and arguments are always live
            marker.locals.insert(RETURN_PLACE);
            for arg in body.args_iter() {
                marker.locals.insert(arg);
            }

            marker.locals
        };

        let map = make_local_map(&mut body.local_decls, locals);
        // Update references to all vars and tmps now
        LocalUpdater { map, tcx }.visit_body(body);
        body.local_decls.shrink_to_fit();
    }
}

/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<V>(
    vec: &mut IndexVec<Local, V>,
    mask: BitSet<Local>,
) -> IndexVec<Local, Option<Local>> {
    let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
    let mut used = Local::new(0);
    for alive_index in mask.iter() {
        map[alive_index] = Some(used);
        if alive_index != used {
            vec.swap(alive_index, used);
        }
        used.increment_by(1);
    }
    vec.truncate(used.index());
    map
}

struct DeclMarker<'a, 'tcx> {
    pub locals: BitSet<Local>,
    pub body: &'a Body<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
    fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) {
        // Ignore storage markers altogether, they get removed along with their otherwise unused
        // decls.
        // FIXME: Extend this to all non-uses.
        if ctx.is_storage_marker() {
            return;
        }

        // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
        // of these locals. However, if the local is still needed, then it will be referenced in
        // another place and we'll mark it as being used there.
        if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store)
            || ctx == PlaceContext::MutatingUse(MutatingUseContext::Projection)
        {
            let block = &self.body.basic_blocks()[location.block];
            if location.statement_index != block.statements.len() {
                let stmt = &block.statements[location.statement_index];

                if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) =
                    &stmt.kind
                {
                    match c.literal.val {
                        // Keep assignments from unevaluated constants around, since the evaluation
                        // may report errors, even if the use of the constant is dead code.
                        ty::ConstKind::Unevaluated(..) => {}
                        _ => {
                            if !p.is_indirect() {
                                trace!("skipping store of const value {:?} to {:?}", c, p);
                                return;
                            }
                        }
                    }
                }
            }
        }

        self.locals.insert(*local);
    }
}

struct LocalUpdater<'tcx> {
    map: IndexVec<Local, Option<Local>>,
    tcx: TyCtxt<'tcx>,
}

impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
        // Remove unnecessary StorageLive and StorageDead annotations.
        data.statements.retain(|stmt| match &stmt.kind {
            StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(),
            StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(),
            _ => true,
        });
        self.super_basic_block_data(block, data);
    }

    fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
        *l = self.map[*l].unwrap();
    }

    fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option<PlaceElem<'tcx>> {
        match elem {
            PlaceElem::Index(local) => Some(PlaceElem::Index(self.map[*local].unwrap())),
            _ => None,
        }
    }
}
<commit_msg>Use Vec::append<commit_after>//! A number of passes which remove various redundancies in the CFG.
//!
//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals`
//! gets rid of all the unnecessary local variable declarations.
//!
//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often.
//! Most of the passes should not care or be impacted in meaningful ways due to extra locals
//! either, so running the pass once, right before codegen, should suffice.
//!
//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus
//! one should run it after every pass which may modify CFG in significant ways. This pass must
//! also be run before any analysis passes because it removes dead blocks, and some of these can be
//! ill-typed.
//!
//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have
//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's
//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A
//! standard example of the situation is:
//!
//! ```rust
//!   fn example() {
//!       let _a: char = { return; };
//!   }
//! ```
//!
//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.

use crate::transform::{MirPass, MirSource};
use rustc::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc::mir::*;
use rustc::ty::{self, TyCtxt};
use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use std::borrow::Cow;

pub struct SimplifyCfg {
    label: String,
}

impl SimplifyCfg {
    pub fn new(label: &str) -> Self {
        SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
    }
}

pub fn simplify_cfg(body: &mut BodyAndCache<'_>) {
    CfgSimplifier::new(body).simplify();
    remove_dead_blocks(body);

    // FIXME: Should probably be moved into some kind of pass manager
    body.basic_blocks_mut().raw.shrink_to_fit();
}

impl<'tcx> MirPass<'tcx> for SimplifyCfg {
    fn name(&self) -> Cow<'_, str> {
        Cow::Borrowed(&self.label)
    }

    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
        simplify_cfg(body);
    }
}

pub struct CfgSimplifier<'a, 'tcx> {
    basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
    pred_count: IndexVec<BasicBlock, u32>,
}

impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
    pub fn new(body: &'a mut BodyAndCache<'tcx>) -> Self {
        let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());

        // we can't use mir.predecessors() here because that counts
        // dead blocks, which we don't want to.
        pred_count[START_BLOCK] = 1;

        for (_, data) in traversal::preorder(body) {
            if let Some(ref term) = data.terminator {
                for &tgt in term.successors() {
                    pred_count[tgt] += 1;
                }
            }
        }

        let basic_blocks = body.basic_blocks_mut();

        CfgSimplifier { basic_blocks, pred_count }
    }

    pub fn simplify(mut self) {
        self.strip_nops();

        let mut start = START_BLOCK;
        let mut new_stmts = vec![];

        loop {
            let mut changed = false;

            self.collapse_goto_chain(&mut start, &mut changed);

            for bb in self.basic_blocks.indices() {
                if self.pred_count[bb] == 0 {
                    continue;
                }

                debug!("simplifying {:?}", bb);

                let mut terminator =
                    self.basic_blocks[bb].terminator.take().expect("invalid terminator state");

                for successor in terminator.successors_mut() {
                    self.collapse_goto_chain(successor, &mut changed);
                }

                let mut inner_changed = true;
                while inner_changed {
                    inner_changed = false;
                    inner_changed |= self.simplify_branch(&mut terminator);
                    inner_changed |= self.merge_successor(&mut new_stmts, &mut terminator);
                    changed |= inner_changed;
                }

                let data = &mut self.basic_blocks[bb];
                data.statements.append(&mut new_stmts);
                data.terminator = Some(terminator);

                changed |= inner_changed;
            }

            if !changed {
                break;
            }
        }

        if start != START_BLOCK {
            debug_assert!(self.pred_count[START_BLOCK] == 0);
            self.basic_blocks.swap(START_BLOCK, start);
            self.pred_count.swap(START_BLOCK, start);

            // pred_count == 1 if the start block has no predecessor _blocks_.
            if self.pred_count[START_BLOCK] > 1 {
                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
                    if self.pred_count[bb] == 0 {
                        continue;
                    }

                    for target in data.terminator_mut().successors_mut() {
                        if *target == start {
                            *target = START_BLOCK;
                        }
                    }
                }
            }
        }
    }

    // Collapse a goto chain starting from `start`
    fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) {
        let mut terminator = match self.basic_blocks[*start] {
            BasicBlockData {
                ref statements,
                terminator:
                    ref mut terminator @ Some(Terminator { kind: TerminatorKind::Goto { .. }, .. }),
                ..
            } if statements.is_empty() => terminator.take(),
            // if `terminator` is None, this means we are in a loop. In that
            // case, let all the loop collapse to its entry.
            _ => return,
        };

        let target = match terminator {
            Some(Terminator { kind: TerminatorKind::Goto { ref mut target }, .. }) => {
                self.collapse_goto_chain(target, changed);
                *target
            }
            _ => unreachable!(),
        };
        self.basic_blocks[*start].terminator = terminator;

        debug!("collapsing goto chain from {:?} to {:?}", *start, target);

        *changed |= *start != target;

        if self.pred_count[*start] == 1 {
            // This is the last reference to *start, so the pred-count to
            // to target is moved into the current block.
            self.pred_count[*start] = 0;
        } else {
            self.pred_count[target] += 1;
            self.pred_count[*start] -= 1;
        }

        *start = target;
    }

    // merge a block with 1 `goto` predecessor to its parent
    fn merge_successor(
        &mut self,
        new_stmts: &mut Vec<Statement<'tcx>>,
        terminator: &mut Terminator<'tcx>,
    ) -> bool {
        let target = match terminator.kind {
            TerminatorKind::Goto { target } if self.pred_count[target] == 1 => target,
            _ => return false,
        };

        debug!("merging block {:?} into {:?}", target, terminator);
        *terminator = match self.basic_blocks[target].terminator.take() {
            Some(terminator) => terminator,
            None => {
                // unreachable loop - this should not be possible, as we
                // don't strand blocks, but handle it correctly.
                return false;
            }
        };
        new_stmts.extend(self.basic_blocks[target].statements.drain(..));
        self.pred_count[target] = 0;

        true
    }

    // turn a branch with all successors identical to a goto
    fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
        match terminator.kind {
            TerminatorKind::SwitchInt { .. } => {}
            _ => return false,
        };

        let first_succ = {
            if let Some(&first_succ) = terminator.successors().nth(0) {
                if terminator.successors().all(|s| *s == first_succ) {
                    let count = terminator.successors().count();
                    self.pred_count[first_succ] -= (count - 1) as u32;
                    first_succ
                } else {
                    return false;
                }
            } else {
                return false;
            }
        };

        debug!("simplifying branch {:?}", terminator);
        terminator.kind = TerminatorKind::Goto { target: first_succ };
        true
    }

    fn strip_nops(&mut self) {
        for blk in self.basic_blocks.iter_mut() {
            blk.statements
                .retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { true })
        }
    }
}

pub fn remove_dead_blocks(body: &mut BodyAndCache<'_>) {
    let mut seen = BitSet::new_empty(body.basic_blocks().len());
    for (bb, _) in traversal::preorder(body) {
        seen.insert(bb.index());
    }

    let basic_blocks = body.basic_blocks_mut();

    let num_blocks = basic_blocks.len();
    let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
    let mut used_blocks = 0;
    for alive_index in seen.iter() {
        replacements[alive_index] = BasicBlock::new(used_blocks);
        if alive_index != used_blocks {
            // Swap the next alive block data with the current available slot. Since
            // alive_index is non-decreasing this is a valid operation.
            basic_blocks.raw.swap(alive_index, used_blocks);
        }
        used_blocks += 1;
    }
    basic_blocks.raw.truncate(used_blocks);

    for block in basic_blocks {
        for target in block.terminator_mut().successors_mut() {
            *target = replacements[target.index()];
        }
    }
}

pub struct SimplifyLocals;

impl<'tcx> MirPass<'tcx> for SimplifyLocals {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        trace!("running SimplifyLocals on {:?}", source);
        let locals = {
            let read_only_cache = read_only!(body);
            let mut marker = DeclMarker { locals: BitSet::new_empty(body.local_decls.len()), body };
            marker.visit_body(read_only_cache);
            // Return pointer and arguments are always live
            marker.locals.insert(RETURN_PLACE);
            for arg in body.args_iter() {
                marker.locals.insert(arg);
            }

            marker.locals
        };

        let map = make_local_map(&mut body.local_decls, locals);
        // Update references to all vars and tmps now
        LocalUpdater { map, tcx }.visit_body(body);
        body.local_decls.shrink_to_fit();
    }
}

/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<V>(
    vec: &mut IndexVec<Local, V>,
    mask: BitSet<Local>,
) -> IndexVec<Local, Option<Local>> {
    let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
    let mut used = Local::new(0);
    for alive_index in mask.iter() {
        map[alive_index] = Some(used);
        if alive_index != used {
            vec.swap(alive_index, used);
        }
        used.increment_by(1);
    }
    vec.truncate(used.index());
    map
}

struct DeclMarker<'a, 'tcx> {
    pub locals: BitSet<Local>,
    pub body: &'a Body<'tcx>,
}

impl<'a, 'tcx> Visitor<'tcx> for DeclMarker<'a, 'tcx> {
    fn visit_local(&mut self, local: &Local, ctx: PlaceContext, location: Location) {
        // Ignore storage markers altogether, they get removed along with their otherwise unused
        // decls.
        // FIXME: Extend this to all non-uses.
        if ctx.is_storage_marker() {
            return;
        }

        // Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
        // of these locals. However, if the local is still needed, then it will be referenced in
        // another place and we'll mark it as being used there.
        if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store)
            || ctx == PlaceContext::MutatingUse(MutatingUseContext::Projection)
        {
            let block = &self.body.basic_blocks()[location.block];
            if location.statement_index != block.statements.len() {
                let stmt = &block.statements[location.statement_index];

                if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) =
                    &stmt.kind
                {
                    match c.literal.val {
                        // Keep assignments from unevaluated constants around, since the evaluation
                        // may report errors, even if the use of the constant is dead code.
                        ty::ConstKind::Unevaluated(..) => {}
                        _ => {
                            if !p.is_indirect() {
                                trace!("skipping store of const value {:?} to {:?}", c, p);
                                return;
                            }
                        }
                    }
                }
            }
        }

        self.locals.insert(*local);
    }
}

struct LocalUpdater<'tcx> {
    map: IndexVec<Local, Option<Local>>,
    tcx: TyCtxt<'tcx>,
}

impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
        // Remove unnecessary StorageLive and StorageDead annotations.
        data.statements.retain(|stmt| match &stmt.kind {
            StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => self.map[*l].is_some(),
            StatementKind::Assign(box (place, _)) => self.map[place.local].is_some(),
            _ => true,
        });
        self.super_basic_block_data(block, data);
    }

    fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
        *l = self.map[*l].unwrap();
    }

    fn process_projection_elem(&mut self, elem: &PlaceElem<'tcx>) -> Option<PlaceElem<'tcx>> {
        match elem {
            PlaceElem::Index(local) => Some(PlaceElem::Index(self.map[*local].unwrap())),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use libzakocmp::config::Config;
use libzakocmp::snapshot::Snapshot;
use libzakocmp::structs::CliOptions;
use libzakocmp::structs::ZakocmpError;

use clap::{App, Arg, ArgMatches};

const DEFAULT_POLICY_ARG_NAME: &'static str = "default-policy";
const CONFIG_FILE_ARG_NAME: &'static str = "config";
const OLD_SNAPSHOT_PATH_ARG_NAME: &'static str = "old-snapshot-path";
const NEW_SNAPSHOT_PATH_ARG_NAME: &'static str = "new-snapshot-path";

// Holds one instance of each struct necessary to operate.
struct OperationalData {
    config: Config,
    old_snapshot: Snapshot,
    new_snapshot: Snapshot,
}

// Reads parsed command-line arguments and returns the appropriate
// operational data. Can abort the program on error.
fn complete_initialization(matches: &ArgMatches) -> Result<OperationalData, ZakocmpError> {
    // The two snapshot paths are required, so these are safe to unwrap.
    let old_snapshot_path = matches.value_of(OLD_SNAPSHOT_PATH_ARG_NAME).unwrap();
    let new_snapshot_path = matches.value_of(NEW_SNAPSHOT_PATH_ARG_NAME).unwrap();
    let old_contents = libzakocmp::helpers::ingest_file(old_snapshot_path)?;
    let new_contents = libzakocmp::helpers::ingest_file(new_snapshot_path)?;

    let options = CliOptions {
        config_path: matches.value_of(CONFIG_FILE_ARG_NAME),
        default_policy: matches.value_of(DEFAULT_POLICY_ARG_NAME),
    };

    Ok(OperationalData {
        config: Config::new(&options)?,
        old_snapshot: Snapshot::new(&old_contents)?,
        new_snapshot: Snapshot::new(&new_contents)?,
    })
}

// Begins parsing command-line arguments. Can abort the program on
// error.
fn initialize() -> Result<OperationalData, ZakocmpError> {
    let matches = App::new("zakocmp")
        .version("0.2.0")
        .author("j39m")
        .about("compares zakocmp snapshots")
        .arg(
            Arg::with_name(CONFIG_FILE_ARG_NAME)
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("specifies a zakocmp config")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(DEFAULT_POLICY_ARG_NAME)
                .short("d")
                .long("default-policy")
                .value_name("POLICY_TOKENS")
                .help("specifies an explicit default policy")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(OLD_SNAPSHOT_PATH_ARG_NAME)
                .help("path to older snapshot")
                .index(1)
                .required(true),
        )
        .arg(
            Arg::with_name(NEW_SNAPSHOT_PATH_ARG_NAME)
                .help("path to newer snapshot")
                .index(2)
                .required(true),
        )
        .get_matches();
    return complete_initialization(&matches);
}

fn main() {
    let operational_data = match initialize() {
        Ok(data) => data,
        Err(error) => {
            eprintln!("{}", error.to_string());
            std::process::exit(1);
        }
    };

    let OperationalData {
        config,
        new_snapshot,
        old_snapshot,
    } = operational_data;
    assert!(config.rules() > 0);
    let violations = libzakocmp::enter(&config, &old_snapshot, &new_snapshot);
    println!("{}", violations);
}
<commit_msg>zakocmp: correct usage string<commit_after>use libzakocmp::config::Config;
use libzakocmp::snapshot::Snapshot;
use libzakocmp::structs::CliOptions;
use libzakocmp::structs::ZakocmpError;

use clap::{App, Arg, ArgMatches};

const DEFAULT_POLICY_ARG_NAME: &'static str = "default-policy";
const CONFIG_FILE_ARG_NAME: &'static str = "config";
const OLD_SNAPSHOT_PATH_ARG_NAME: &'static str = "old-snapshot-path";
const NEW_SNAPSHOT_PATH_ARG_NAME: &'static str = "new-snapshot-path";

// Holds one instance of each struct necessary to operate.
struct OperationalData {
    config: Config,
    old_snapshot: Snapshot,
    new_snapshot: Snapshot,
}

// Reads parsed command-line arguments and returns the appropriate
// operational data. Can abort the program on error.
fn complete_initialization(matches: &ArgMatches) -> Result<OperationalData, ZakocmpError> {
    // The two snapshot paths are required, so these are safe to unwrap.
    let old_snapshot_path = matches.value_of(OLD_SNAPSHOT_PATH_ARG_NAME).unwrap();
    let new_snapshot_path = matches.value_of(NEW_SNAPSHOT_PATH_ARG_NAME).unwrap();
    let old_contents = libzakocmp::helpers::ingest_file(old_snapshot_path)?;
    let new_contents = libzakocmp::helpers::ingest_file(new_snapshot_path)?;

    let options = CliOptions {
        config_path: matches.value_of(CONFIG_FILE_ARG_NAME),
        default_policy: matches.value_of(DEFAULT_POLICY_ARG_NAME),
    };

    Ok(OperationalData {
        config: Config::new(&options)?,
        old_snapshot: Snapshot::new(&old_contents)?,
        new_snapshot: Snapshot::new(&new_contents)?,
    })
}

// Begins parsing command-line arguments. Can abort the program on
// error.
fn initialize() -> Result<OperationalData, ZakocmpError> {
    let matches = App::new("zakocmp")
        .version("0.2.0")
        .author("j39m")
        .about("compares zakopane snapshots")
        .arg(
            Arg::with_name(CONFIG_FILE_ARG_NAME)
                .short("c")
                .long("config")
                .value_name("FILE")
                .help("specifies a zakocmp config")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(DEFAULT_POLICY_ARG_NAME)
                .short("d")
                .long("default-policy")
                .value_name("POLICY_TOKENS")
                .help("specifies an explicit default policy")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(OLD_SNAPSHOT_PATH_ARG_NAME)
                .help("path to older snapshot")
                .index(1)
                .required(true),
        )
        .arg(
            Arg::with_name(NEW_SNAPSHOT_PATH_ARG_NAME)
                .help("path to newer snapshot")
                .index(2)
                .required(true),
        )
        .get_matches();
    return complete_initialization(&matches);
}

fn main() {
    let operational_data = match initialize() {
        Ok(data) => data,
        Err(error) => {
            eprintln!("{}", error.to_string());
            std::process::exit(1);
        }
    };

    let OperationalData {
        config,
        new_snapshot,
        old_snapshot,
    } = operational_data;
    assert!(config.rules() > 0);
    let violations = libzakocmp::enter(&config, &old_snapshot, &new_snapshot);
    println!("{}", violations);
}
<|endoftext|>


<commit_before>use bson::{Bson, Document};
use mongodb::{Client, ThreadedClient};
use mongodb::command_type::CommandType;
use mongodb::db::ThreadedDatabase;
use mongodb::cursor::Cursor;
use mongodb::wire_protocol::flags::OpQueryFlags;

#[test]
fn cursor_features() {
    let client = Client::with_uri("mongodb://localhost:27017").unwrap();
    let db = client.db("test");
    let coll = db.collection("cursor_test");

    coll.drop().ok().expect("Failed to drop database.");

    let docs = (0..10).map(|i| {
        doc! { "foo" => (i as i64) }
    }).collect();

    assert!(coll.insert_many(docs, false, None).is_ok());

    let doc = Document::new();
    let flags = OpQueryFlags::no_flags();

    let result = Cursor::query(client.clone(), "test.cursor_test".to_owned(), 3, flags, 0, 0,
                               doc, None, false);

    let mut cursor = match result {
        Ok(c) => c,
        Err(s) => panic!("{}", s)
    };

    let batch = cursor.next_batch().ok().expect("Failed to get next batch from cursor.");

    assert_eq!(batch.len(), 3 as usize);

    for i in 0..batch.len() {
        match batch[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(i as i64, j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }

    let bson = match cursor.next() {
        Some(Ok(b)) => b,
        Some(Err(_)) => panic!("Received error on 'cursor.next()'"),
        None => panic!("Nothing returned from Cursor#next")
    };

    match bson.get("foo") {
        Some(&Bson::I64(3)) => (),
        _ => panic!("Wrong value returned from Cursor#next")
    };

    assert!(cursor.has_next().ok().expect("Failed to execute 'has_next()'."));
    let vec = cursor.next_n(20).ok().expect("Failed to get next 20 results.");;

    assert_eq!(vec.len(), 6 as usize);
    assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()'."));

    for i in 0..vec.len() {
        match vec[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(4 + i as i64 , j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }
}
<commit_msg>fixed issue with reversion of cursor test<commit_after>use bson::{Bson, Document};
use mongodb::{Client, ThreadedClient};
use mongodb::command_type::CommandType;
use mongodb::db::ThreadedDatabase;
use mongodb::cursor::Cursor;
use mongodb::wire_protocol::flags::OpQueryFlags;

#[test]
fn cursor_features() {
    let client = Client::with_uri("mongodb://localhost:27017").unwrap();
    let db = client.db("test");
    let coll = db.collection("cursor_test");

    coll.drop().ok().expect("Failed to drop database.");

    let docs = (0..10).map(|i| {
        doc! { "foo" => (i as i64) }
    }).collect();

    assert!(coll.insert_many(docs, false, None).is_ok());

    let doc = Document::new();
    let flags = OpQueryFlags::no_flags();

    let result = Cursor::query(client.clone(), "test.cursor_test".to_owned(),
                               3, flags, 0, 0, doc, None, CommandType::Find,
                               false);

    let mut cursor = match result {
        Ok(c) => c,
        Err(s) => panic!("{}", s)
    };

    let batch = cursor.next_batch().ok().expect("Failed to get next batch from cursor.");

    assert_eq!(batch.len(), 3 as usize);

    for i in 0..batch.len() {
        match batch[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(i as i64, j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }

    let bson = match cursor.next() {
        Some(Ok(b)) => b,
        Some(Err(_)) => panic!("Received error on 'cursor.next()'"),
        None => panic!("Nothing returned from Cursor#next")
    };

    match bson.get("foo") {
        Some(&Bson::I64(3)) => (),
        _ => panic!("Wrong value returned from Cursor#next")
    };

    assert!(cursor.has_next().ok().expect("Failed to execute 'has_next()'."));
    let vec = cursor.next_n(20).ok().expect("Failed to get next 20 results.");;

    assert_eq!(vec.len(), 6 as usize);
    assert!(!cursor.has_next().ok().expect("Failed to execute 'has_next()'."));

    for i in 0..vec.len() {
        match vec[i].get("foo") {
            Some(&Bson::I64(j)) => assert_eq!(4 + i as i64 , j),
            _ => panic!("Wrong value returned from Cursor#next_batch")
        };
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use std::sync::mpsc;
use std::sync::{Arc, Mutex, Condvar};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell};
use std::io::{Error, ErrorKind};
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::Deref;
use std::mem;

use uuid::Uuid;

struct ServerRecord {
    sender: MpscSender,
    conn_sender: mpsc::Sender<bool>,
    conn_receiver: Mutex<mpsc::Receiver<bool>>,
}

impl ServerRecord {
    fn new(sender: MpscSender) -> ServerRecord {
        let (tx, rx) = mpsc::channel::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: Mutex::new(rx),
        }
    }

    fn accept(&self) {
        self.conn_receiver.lock().unwrap().recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct MpscChannelMessage(Vec<u8>, Vec<MpscChannel>, Vec<MpscSharedMemory>);

pub fn channel() -> Result<(MpscSender, MpscReceiver),MpscError> {
    let (base_sender, base_receiver) = mpsc::channel::<MpscChannelMessage>();
    Ok((MpscSender::new(base_sender), MpscReceiver::new(base_receiver)))
}

pub struct MpscReceiver {
    receiver: RefCell<Option<mpsc::Receiver<MpscChannelMessage>>>,
}

impl MpscReceiver {
    fn new(receiver: mpsc::Receiver<MpscChannelMessage>) -> MpscReceiver {
        MpscReceiver {
            receiver: RefCell::new(Some(receiver)),
        }
    }

    pub fn consume(&self) -> MpscReceiver {
        let receiver = self.receiver.borrow_mut().take();
        MpscReceiver::new(receiver.unwrap())
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }

    pub fn try_recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().try_recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }
}

unsafe impl Send for MpscReceiver { }
unsafe impl Sync for MpscReceiver { }

#[derive(Clone)]
pub struct MpscSender {
    sender: RefCell<mpsc::Sender<MpscChannelMessage>>,
}

unsafe impl Send for MpscSender { }
unsafe impl Sync for MpscSender { }

impl MpscSender {
    fn new(sender: mpsc::Sender<MpscChannelMessage>) -> MpscSender {
        MpscSender {
            sender: RefCell::new(sender),
        }
    }

    pub fn connect(name: String) -> Result<MpscSender,MpscError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().remove(&name).unwrap();
        record.connect();
        Ok(record.sender)
    }

    pub fn send(&self,
                data: &[u8],
                ports: Vec<MpscChannel>,
                shared_memory_regions: Vec<MpscSharedMemory>)
                -> Result<(),MpscError>
    {
        match self.sender.borrow().send(MpscChannelMessage(data.to_vec(), ports, shared_memory_regions)) {
            Err(_) => Err(MpscError::ChannelClosedError),
            Ok(_) => Ok(()),
        }
    }
}

pub struct MpscReceiverSet {
    last_index: usize,
    receiver_ids: Vec<usize>,
    receivers: Vec<MpscReceiver>,
}

impl MpscReceiverSet {
    pub fn new() -> Result<MpscReceiverSet,MpscError> {
        Ok(MpscReceiverSet {
            last_index: 0,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: MpscReceiver) -> Result<i64,MpscError> {
        self.last_index += 1;
        self.receiver_ids.push(self.last_index);
        self.receivers.push(receiver.consume());
        Ok(self.last_index as i64)
    }

    pub fn select(&mut self) -> Result<Vec<MpscSelectionResult>,MpscError> {
        let mut receivers: Vec<Option<mpsc::Receiver<MpscChannelMessage>>> = Vec::with_capacity(self.receivers.len());
        let mut r_id: i64 = -1;
        let mut r_index: usize = 0;

        {
            let select = mpsc::Select::new();
            // we *must* allocate exact capacity for this, because the Handles *can't move*
            let mut handles: Vec<mpsc::Handle<MpscChannelMessage>> = Vec::with_capacity(self.receivers.len());

            for r in &self.receivers {
                let inner_r = mem::replace(&mut *r.receiver.borrow_mut(), None);
                receivers.push(inner_r);
            }

            for r in &receivers {
                unsafe {
                    handles.push(select.handle(r.as_ref().unwrap()));
                    handles.last_mut().unwrap().add();
                }
            }

            let id = select.wait();

            for (index,h) in handles.iter().enumerate() {
                if h.id() == id {
                    r_index = index;
                    r_id = self.receiver_ids[index] as i64;
                    break;
                }
            }
        }

        // put the receivers back
        for (index,r) in self.receivers.iter().enumerate() {
            mem::replace(&mut *r.receiver.borrow_mut(), mem::replace(&mut receivers[index], None));
        }

        if r_id == -1 {
            return Err(MpscError::UnknownError);
        }

        let receivers = &mut self.receivers;
        match receivers[r_index].recv() {
            Ok((data, channels, shmems)) =>
                Ok(vec![MpscSelectionResult::DataReceived(r_id, data, channels, shmems)]),
            Err(MpscError::ChannelClosedError) => {
                receivers.remove(r_index);
                self.receiver_ids.remove(r_index);
                Ok(vec![MpscSelectionResult::ChannelClosed(r_id)])
            },
            Err(err) => Err(err),
        }
    }
}

pub enum MpscSelectionResult {
    DataReceived(i64, Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),
    ChannelClosed(i64),
}

pub struct MpscOneShotServer {
    receiver: RefCell<Option<MpscReceiver>>,
    name: String,
}

impl MpscOneShotServer {
    pub fn new() -> Result<(MpscOneShotServer, String),MpscError> {
        let (sender, receiver) = match channel() {
            Ok((s,r)) => (s,r),
            Err(err) => return Err(err),
        };

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((MpscOneShotServer {
            receiver: RefCell::new(Some(receiver)),
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(&self) -> Result<(MpscReceiver,
                                    Vec<u8>,
                                    Vec<OpaqueMpscChannel>,
                                    Vec<MpscSharedMemory>),MpscError>
    {
        ONE_SHOT_SERVERS.lock().unwrap().get(&self.name).unwrap().accept();
        let receiver = self.receiver.borrow_mut().take().unwrap();
        let (data, channels, shmems) = receiver.recv().unwrap();
        Ok((receiver, data, channels, shmems))
    }
}

pub enum MpscChannel {
    Sender(MpscSender),
    Receiver(MpscReceiver),
}

pub struct OpaqueMpscChannel {
    channel: RefCell<Option<MpscChannel>>,
}

impl OpaqueMpscChannel {
    fn new(channel: MpscChannel) -> OpaqueMpscChannel {
        OpaqueMpscChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> MpscReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            MpscChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&self) -> MpscSender {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(s) => s,
            MpscChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct MpscSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for MpscSharedMemory {}
unsafe impl Sync for MpscSharedMemory {}

impl Clone for MpscSharedMemory {
    fn clone(&self) -> MpscSharedMemory {
        MpscSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for MpscSharedMemory {
    fn eq(&self, other: &MpscSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for MpscSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for MpscSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `MpscSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl MpscSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> MpscSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> MpscSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug)]
pub enum MpscError {
    ChannelClosedError,
    UnknownError,
}

impl From<MpscError> for Error {
    fn from(mpsc_error: MpscError) -> Error {
        match mpsc_error {
            MpscError::ChannelClosedError => {
                Error::new(ErrorKind::BrokenPipe, "MPSC channel closed")
            }
            MpscError::UnknownError => Error::new(ErrorKind::Other, "Other MPSC channel error"),
        }
    }
}

<commit_msg>Auto merge of #22 - antrik:fix-debug, r=larsbergstrom<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use std::sync::mpsc;
use std::sync::{Arc, Mutex, Condvar};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell};
use std::io::{Error, ErrorKind};
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::Deref;
use std::mem;

use uuid::Uuid;

struct ServerRecord {
    sender: MpscSender,
    conn_sender: mpsc::Sender<bool>,
    conn_receiver: Mutex<mpsc::Receiver<bool>>,
}

impl ServerRecord {
    fn new(sender: MpscSender) -> ServerRecord {
        let (tx, rx) = mpsc::channel::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: Mutex::new(rx),
        }
    }

    fn accept(&self) {
        self.conn_receiver.lock().unwrap().recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct MpscChannelMessage(Vec<u8>, Vec<MpscChannel>, Vec<MpscSharedMemory>);

pub fn channel() -> Result<(MpscSender, MpscReceiver),MpscError> {
    let (base_sender, base_receiver) = mpsc::channel::<MpscChannelMessage>();
    Ok((MpscSender::new(base_sender), MpscReceiver::new(base_receiver)))
}

pub struct MpscReceiver {
    receiver: RefCell<Option<mpsc::Receiver<MpscChannelMessage>>>,
}

// Can't derive, as mpsc::Receiver doesn't implement Debug.
impl fmt::Debug for MpscReceiver {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "MpscReceiver {{ .. }}")
    }
}

impl MpscReceiver {
    fn new(receiver: mpsc::Receiver<MpscChannelMessage>) -> MpscReceiver {
        MpscReceiver {
            receiver: RefCell::new(Some(receiver)),
        }
    }

    pub fn consume(&self) -> MpscReceiver {
        let receiver = self.receiver.borrow_mut().take();
        MpscReceiver::new(receiver.unwrap())
    }

    pub fn recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }

    pub fn try_recv(&self) -> Result<(Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),MpscError> {
        let r = self.receiver.borrow();
        match r.as_ref().unwrap().try_recv() {
            Ok(MpscChannelMessage(d,c,s)) => Ok((d,
                                                 c.into_iter().map(OpaqueMpscChannel::new).collect(),
                                                 s)),
            Err(_) => Err(MpscError::ChannelClosedError),
        }
    }
}

unsafe impl Send for MpscReceiver { }
unsafe impl Sync for MpscReceiver { }

#[derive(Clone)]
pub struct MpscSender {
    sender: RefCell<mpsc::Sender<MpscChannelMessage>>,
}

// Can't derive, as mpsc::Sender doesn't implement Debug.
impl fmt::Debug for MpscSender {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure there is anything useful we could print here.
        write!(f, "MpscSender {{ .. }}")
    }
}

unsafe impl Send for MpscSender { }
unsafe impl Sync for MpscSender { }

impl MpscSender {
    fn new(sender: mpsc::Sender<MpscChannelMessage>) -> MpscSender {
        MpscSender {
            sender: RefCell::new(sender),
        }
    }

    pub fn connect(name: String) -> Result<MpscSender,MpscError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().remove(&name).unwrap();
        record.connect();
        Ok(record.sender)
    }

    pub fn send(&self,
                data: &[u8],
                ports: Vec<MpscChannel>,
                shared_memory_regions: Vec<MpscSharedMemory>)
                -> Result<(),MpscError>
    {
        match self.sender.borrow().send(MpscChannelMessage(data.to_vec(), ports, shared_memory_regions)) {
            Err(_) => Err(MpscError::ChannelClosedError),
            Ok(_) => Ok(()),
        }
    }
}

pub struct MpscReceiverSet {
    last_index: usize,
    receiver_ids: Vec<usize>,
    receivers: Vec<MpscReceiver>,
}

impl MpscReceiverSet {
    pub fn new() -> Result<MpscReceiverSet,MpscError> {
        Ok(MpscReceiverSet {
            last_index: 0,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: MpscReceiver) -> Result<i64,MpscError> {
        self.last_index += 1;
        self.receiver_ids.push(self.last_index);
        self.receivers.push(receiver.consume());
        Ok(self.last_index as i64)
    }

    pub fn select(&mut self) -> Result<Vec<MpscSelectionResult>,MpscError> {
        let mut receivers: Vec<Option<mpsc::Receiver<MpscChannelMessage>>> = Vec::with_capacity(self.receivers.len());
        let mut r_id: i64 = -1;
        let mut r_index: usize = 0;

        {
            let select = mpsc::Select::new();
            // we *must* allocate exact capacity for this, because the Handles *can't move*
            let mut handles: Vec<mpsc::Handle<MpscChannelMessage>> = Vec::with_capacity(self.receivers.len());

            for r in &self.receivers {
                let inner_r = mem::replace(&mut *r.receiver.borrow_mut(), None);
                receivers.push(inner_r);
            }

            for r in &receivers {
                unsafe {
                    handles.push(select.handle(r.as_ref().unwrap()));
                    handles.last_mut().unwrap().add();
                }
            }

            let id = select.wait();

            for (index,h) in handles.iter().enumerate() {
                if h.id() == id {
                    r_index = index;
                    r_id = self.receiver_ids[index] as i64;
                    break;
                }
            }
        }

        // put the receivers back
        for (index,r) in self.receivers.iter().enumerate() {
            mem::replace(&mut *r.receiver.borrow_mut(), mem::replace(&mut receivers[index], None));
        }

        if r_id == -1 {
            return Err(MpscError::UnknownError);
        }

        let receivers = &mut self.receivers;
        match receivers[r_index].recv() {
            Ok((data, channels, shmems)) =>
                Ok(vec![MpscSelectionResult::DataReceived(r_id, data, channels, shmems)]),
            Err(MpscError::ChannelClosedError) => {
                receivers.remove(r_index);
                self.receiver_ids.remove(r_index);
                Ok(vec![MpscSelectionResult::ChannelClosed(r_id)])
            },
            Err(err) => Err(err),
        }
    }
}

pub enum MpscSelectionResult {
    DataReceived(i64, Vec<u8>, Vec<OpaqueMpscChannel>, Vec<MpscSharedMemory>),
    ChannelClosed(i64),
}

pub struct MpscOneShotServer {
    receiver: RefCell<Option<MpscReceiver>>,
    name: String,
}

impl MpscOneShotServer {
    pub fn new() -> Result<(MpscOneShotServer, String),MpscError> {
        let (sender, receiver) = match channel() {
            Ok((s,r)) => (s,r),
            Err(err) => return Err(err),
        };

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((MpscOneShotServer {
            receiver: RefCell::new(Some(receiver)),
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(&self) -> Result<(MpscReceiver,
                                    Vec<u8>,
                                    Vec<OpaqueMpscChannel>,
                                    Vec<MpscSharedMemory>),MpscError>
    {
        ONE_SHOT_SERVERS.lock().unwrap().get(&self.name).unwrap().accept();
        let receiver = self.receiver.borrow_mut().take().unwrap();
        let (data, channels, shmems) = receiver.recv().unwrap();
        Ok((receiver, data, channels, shmems))
    }
}

pub enum MpscChannel {
    Sender(MpscSender),
    Receiver(MpscReceiver),
}

pub struct OpaqueMpscChannel {
    channel: RefCell<Option<MpscChannel>>,
}

impl OpaqueMpscChannel {
    fn new(channel: MpscChannel) -> OpaqueMpscChannel {
        OpaqueMpscChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> MpscReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            MpscChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&self) -> MpscSender {
        match self.channel.borrow_mut().take().unwrap() {
            MpscChannel::Sender(s) => s,
            MpscChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct MpscSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for MpscSharedMemory {}
unsafe impl Sync for MpscSharedMemory {}

impl Clone for MpscSharedMemory {
    fn clone(&self) -> MpscSharedMemory {
        MpscSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for MpscSharedMemory {
    fn eq(&self, other: &MpscSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for MpscSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for MpscSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `MpscSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl MpscSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> MpscSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> MpscSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        MpscSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug)]
pub enum MpscError {
    ChannelClosedError,
    UnknownError,
}

impl From<MpscError> for Error {
    fn from(mpsc_error: MpscError) -> Error {
        match mpsc_error {
            MpscError::ChannelClosedError => {
                Error::new(ErrorKind::BrokenPipe, "MPSC channel closed")
            }
            MpscError::UnknownError => Error::new(ErrorKind::Other, "Other MPSC channel error"),
        }
    }
}

<|endoftext|>