<commit_before>use std::collections::{HashMap, HashSet};
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::CARD_SIZE;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{in_kilo, on_different_cards, start_of_card};
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    young_refs_set: HashSet<Address>,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            young_refs_set: HashSet::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let garbage = init_size - new_size;
            let garbage_ratio = (garbage as f64 / init_size as f64) * 100f64;

            println!("GC: Full GC ({:.2} ms, {:.1}K->{:.1}K size, {:.1}K/{:.0}% garbage)",
                in_ms(dur), in_kilo(init_size), in_kilo(new_size),
                in_kilo(garbage), garbage_ratio);
        });
    }

    fn heap_size(&self) -> usize {
        self.young.used_region().size() + self.old.used_region().size()
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.insert(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, address, _| {
            if full.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if !field_addr.is_null() && !full.perm_space.contains(field_addr) {
                        let &fwd_addr = full.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());

                        if full.young.contains(fwd_addr) {
                            young_refs = true;
                        }
                    }
                });

                if young_refs {
                    full.young_refs_set.insert(address);
                }
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr) {
                let fwd_addr = self.fwd_table.get(&root_ptr).expect("forwarding address not found.");
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let &dest = full.fwd_table.get(&address).expect("forwarding address not found.");
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = full.young_refs_set.contains(&address);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(next_dest);
                    full.update_card(dest, &mut young_refs);
                }

                last_dest = next_dest;
            }
        });

        if !last_dest.is_null() && !start_of_card(last_dest) && self.old.contains(last_dest) {
            self.update_card(last_dest, &mut young_refs);
        }

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;

        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.valid_top(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.valid_top(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        assert!(self.old_top.is_null());
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, addr: Address) {
        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / (mem::ptr_width() as usize);

        let card = self.old.card_from_address(addr);

        self.crossing_map.set_first_object(card, offset_words);
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs { CardEntry::Dirty } else { CardEntry:: Clean };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<commit_msg>swiper: full GC uses only one HashMap<commit_after>use std::collections::HashMap;
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::CARD_SIZE;
use gc::swiper::crossing::CrossingMap;
use gc::swiper::{in_kilo, on_different_cards, start_of_card};
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: ForwardTable,

    fwd: Address,
    fwd_end: Address,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: ForwardTable::new(),

            fwd: old.total.start,
            fwd_end: old.total.end,
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.heap_size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        timer.stop_with(|dur| {
            let new_size = self.heap_size();
            let garbage = init_size - new_size;
            let garbage_ratio = (garbage as f64 / init_size as f64) * 100f64;

            println!("GC: Full GC ({:.2} ms, {:.1}K->{:.1}K size, {:.1}K/{:.0}% garbage)",
                in_ms(dur), in_kilo(init_size), in_kilo(new_size),
                in_kilo(garbage), garbage_ratio);
        });
    }

    fn heap_size(&self) -> usize {
        self.young.used_region().size() + self.old.used_region().size()
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let fwd = full.allocate(object_size);
                full.fwd_table.forward_to(address, fwd);
            }
        });
    }

    fn update_references(&mut self) {
        self.walk_old_and_young(|full, object, address, _| {
            if full.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if !field_addr.is_null() && !full.perm_space.contains(field_addr) {
                        let fwd_addr = full.fwd_table.forward_address(field_addr);
                        field.set(fwd_addr.to_mut_ptr());

                        if full.young.contains(fwd_addr) {
                            young_refs = true;
                        }
                    }
                });

                if young_refs {
                    full.fwd_table.set_young_refs(address);
                }
            }
        });

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if !root_ptr.is_null() && !self.perm_space.contains(root_ptr) {
                let fwd_addr = self.fwd_table.forward_address(root_ptr);
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        self.young.unprotect_to_space();

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        self.walk_old_and_young(|full, object, address, object_size| {
            if full.is_marked(object) {
                let dest = full.fwd_table.forward_address(address);
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = full.fwd_table.has_young_refs(address);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) && full.old.contains(dest) {
                    full.update_crossing(next_dest);
                    full.update_card(dest, &mut young_refs);
                }

                last_dest = next_dest;
            }
        });

        if !last_dest.is_null() && !start_of_card(last_dest) && self.old.contains(last_dest) {
            self.update_card(last_dest, &mut young_refs);
        }

        let young_top;
        let old_top;

        // check if we have left the old-generation into
        // the young generation for copying objects
        if self.old_top.is_null() {
            // if not, young gen is empty
            young_top = self.young.to_space().start;
            old_top = self.fwd;

        } else {
            young_top = self.fwd;
            old_top = self.old_top;
        }

        debug_assert!(self.young.valid_top(young_top));
        self.young.swap_spaces(young_top);
        self.young.protect_to_space();

        debug_assert!(self.old.valid_top(old_top));
        self.old.free.store(old_top.to_usize(), Ordering::SeqCst);
    }

    fn walk_old_and_young<F>(&mut self, mut fct: F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let used_region = self.old.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);

        let used_region = self.young.used_region();
        self.walk_region(used_region.start, used_region.end, &mut fct);
    }

    fn walk_region<F>(&mut self, start: Address, end: Address, fct: &mut F) where F: FnMut(&mut FullCollector, &mut Obj, Address, usize) {
        let mut scan = start;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            fct(self, object, scan, object_size);

            scan = scan.offset(object_size);
        }
    }

    fn allocate(&mut self, object_size: usize) -> Address {
        let addr = self.fwd;
        let next = self.fwd.offset(object_size);

        if next <= self.fwd_end {
            self.fwd = next;
            return addr;
        }

        assert!(self.fwd_end == self.old.total.end);
        assert!(self.old_top.is_null());
        self.old_top = self.fwd;

        let young = self.young.to_space();
        self.fwd = young.start.offset(object_size);
        self.fwd_end = young.end;

        young.start
    }

    fn update_crossing(&mut self, addr: Address) {
        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / (mem::ptr_width() as usize);

        let card = self.old.card_from_address(addr);

        self.crossing_map.set_first_object(card, offset_words);
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs { CardEntry::Dirty } else { CardEntry:: Clean };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}

struct ForwardTable {
    data: HashMap<Address, AddressWithYoungRefs>,
}

impl ForwardTable {
    fn new() -> ForwardTable {
        ForwardTable {
            data: HashMap::new(),
        }
    }

    fn forward_to(&mut self, addr: Address, fwd: Address) {
        self.data.insert(addr, AddressWithYoungRefs::new(fwd));
    }

    fn forward_address(&mut self, addr: Address) -> Address {
        self.data.get(&addr).expect("no forward address found.").address()
    }

    fn has_young_refs(&mut self, addr: Address) -> bool {
        self.data.get(&addr).expect("no forward address found.").has_young_refs()
    }

    fn set_young_refs(&mut self, addr: Address) {
        let value = self.data.get_mut(&addr).expect("no forward address found.");
        *value = value.set_young_refs();
    }
}

#[derive(Copy, Clone)]
struct AddressWithYoungRefs {
    data: usize,
}

impl AddressWithYoungRefs {
    fn new(addr: Address) -> AddressWithYoungRefs {
        AddressWithYoungRefs {
            data: addr.to_usize()
        }
    }

    fn address(self) -> Address {
        (self.data & !1).into()
    }

    fn has_young_refs(self) -> bool {
        (self.data & 1) != 0
    }

    fn set_young_refs(self) -> AddressWithYoungRefs {
        AddressWithYoungRefs {
            data: self.data | 1
        }
    }
}<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use error::Result;
use host::Host;
use serde_json::{to_value, Map, Value};
use target::Target;

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Telemetry {
    pub cpu: Cpu,
    pub fs: Vec<FsMount>,
    pub hostname: String,
    pub memory: u64,
    pub net: Vec<Netif>,
    pub os: Os,
}

#[cfg(feature = "remote-run")]
pub struct Telemetry;

impl Telemetry {
    #[cfg(feature = "local-run")]
    pub fn new(cpu: Cpu, fs: Vec<FsMount>, hostname: &str, memory: u64, net: Vec<Netif>, os: Os) -> Telemetry {
        Telemetry {
            cpu: cpu,
            fs: fs,
            hostname: hostname.to_string(),
            memory: memory,
            net: net,
            os: os,
        }
    }

    pub fn init(host: &mut Host) -> Result<Value> {
        let t = try!(Target::telemetry_init(host));

        // Make sure telemetry is namespaced
        let mut t_map: Map<String, Value> = Map::new();
        t_map.insert("_telemetry".into(), t);
        Ok(to_value(t_map))
    }

    // XXX While Macros 1.1 are unstable, we can't use Serde to
    // convert Telemetry => Value, so we have to roll our own.
    // (https://github.com/rust-lang/rust/issues/35900)
    #[cfg(feature = "local-run")]
    pub fn into_value(self) -> Value {
        let mut cpu: Map<String, Value> = Map::new();
        cpu.insert("vendor".into(), to_value(self.cpu.vendor));
        cpu.insert("brand_string".into(), to_value(self.cpu.brand_string));
        cpu.insert("cores".into(), to_value(self.cpu.cores));

        let mut fs = Vec::new();
        for mount in self.fs {
            let mut map: Map<String, Value> = Map::new();
            map.insert("filesystem".into(), to_value(mount.filesystem));
            map.insert("mountpoint".into(), to_value(mount.mountpoint));
            map.insert("size".into(), to_value(mount.size));
            map.insert("used".into(), to_value(mount.used));
            map.insert("available".into(), to_value(mount.available));
            map.insert("capacity".into(), to_value(mount.capacity));
            fs.push(map);
        }

        let mut net = Vec::new();
        for netif in self.net {
            let mut map: Map<String, Value> = Map::new();
            map.insert("interface".into(), to_value(netif.interface));
            map.insert("mac".into(), to_value(netif.mac));
            if let Some(inet) = netif.inet {
                let mut map1: Map<String, Value> = Map::new();
                map1.insert("address".into(), to_value(inet.address));
                map1.insert("netmask".into(), to_value(inet.netmask));
                map.insert("inet".into(), to_value(map1));
            }
            if let Some(inet6) = netif.inet6 {
                let mut map1: Map<String, Value> = Map::new();
                map1.insert("address".into(), to_value(inet6.address));
                map1.insert("prefixlen".into(), to_value(inet6.prefixlen));
                map1.insert("scopeid".into(), to_value(inet6.scopeid));
                map.insert("inet6".into(), to_value(map1));
            }
            if let Some(status) = netif.status {
                map.insert("status".into(), to_value(if status == NetifStatus::Active { "Active".to_string() } else { "Inactive".to_string() }));
            }
            net.push(map);
        }

        let mut os: Map<String, Value> = Map::new();
        os.insert("arch".into(), to_value(self.os.arch));
        os.insert("family".into(), to_value(self.os.family));
        os.insert("platform".into(), to_value(self.os.platform));
        os.insert("version".into(), to_value(self.os.version));

        let mut telemetry: Map<String, Value> = Map::new();
        telemetry.insert("cpu".into(), to_value(cpu));
        telemetry.insert("fs".into(), to_value(fs));
        telemetry.insert("hostname".into(), to_value(self.hostname));
        telemetry.insert("memory".into(), to_value(self.memory));
        telemetry.insert("net".into(), to_value(net));
        telemetry.insert("os".into(), to_value(os));
        to_value(telemetry)
    }
}

pub trait TelemetryTarget {
    fn telemetry_init(host: &mut Host) -> Result<Value>;
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Cpu {
    pub vendor: String,
    pub brand_string: String,
    pub cores: u32,
}

#[cfg(feature = "local-run")]
impl Cpu {
    pub fn new(vendor: &str, brand_string: &str, cores: u32) -> Cpu {
        Cpu {
            vendor: vendor.to_string(),
            brand_string: brand_string.to_string(),
            cores: cores,
        }
    }
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct FsMount {
    pub filesystem: String,
    pub mountpoint: String,
    pub size: u64,
    pub used: u64,
    pub available: u64,
    pub capacity: f32,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Netif {
    pub interface: String,
    pub mac: Option<String>,
    pub inet: Option<NetifIPv4>,
    pub inet6: Option<NetifIPv6>,
    pub status: Option<NetifStatus>,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable, PartialEq)]
pub enum NetifStatus {
    Active,
    Inactive,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct NetifIPv4 {
    pub address: String,
    pub netmask: String,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct NetifIPv6 {
    pub address: String,
    pub prefixlen: u8,
    pub scopeid: Option<String>,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Os {
    pub arch: String,
    pub family: String,
    pub platform: String,
    pub version: String,
}

#[cfg(feature = "local-run")]
impl Os {
    pub fn new(arch: &str, family: &str, platform: &str, version: &str) -> Os {
        Os {
            arch: arch.to_string(),
            family: family.to_string(),
            platform: platform.to_string(),
            version: version.to_string(),
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "local-run")]
    use Host;
    #[cfg(feature = "local-run")]
    use super::*;

    #[cfg(feature = "local-run")]
    #[test]
    fn test_telemetry_init() {
        let path: Option<String> = None;
        let mut host = Host::local(path).unwrap();
        assert!(Telemetry::init(&mut host).is_ok());
    }
}
<commit_msg>Fixed bug where _telemetry namespace is applied twice for remote hosts<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use error::Result;
use host::Host;
#[cfg(feature = "local-run")]
use serde_json::{to_value, Map};
use serde_json::Value;
use target::Target;

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Telemetry {
    pub cpu: Cpu,
    pub fs: Vec<FsMount>,
    pub hostname: String,
    pub memory: u64,
    pub net: Vec<Netif>,
    pub os: Os,
}

#[cfg(feature = "remote-run")]
pub struct Telemetry;

impl Telemetry {
    #[cfg(feature = "local-run")]
    pub fn new(cpu: Cpu, fs: Vec<FsMount>, hostname: &str, memory: u64, net: Vec<Netif>, os: Os) -> Telemetry {
        Telemetry {
            cpu: cpu,
            fs: fs,
            hostname: hostname.to_string(),
            memory: memory,
            net: net,
            os: os,
        }
    }

    #[cfg(feature = "local-run")]
    pub fn init(host: &mut Host) -> Result<Value> {
        let t = try!(Target::telemetry_init(host));

        // Make sure telemetry is namespaced
        let mut t_map: Map<String, Value> = Map::new();
        t_map.insert("_telemetry".into(), t);
        Ok(to_value(t_map))
    }

    #[cfg(feature = "remote-run")]
    pub fn init(host: &mut Host) -> Result<Value> {
        Ok(try!(Target::telemetry_init(host)))
    }

    // XXX While Macros 1.1 are unstable, we can't use Serde to
    // convert Telemetry => Value, so we have to roll our own.
    // (https://github.com/rust-lang/rust/issues/35900)
    #[cfg(feature = "local-run")]
    pub fn into_value(self) -> Value {
        let mut cpu: Map<String, Value> = Map::new();
        cpu.insert("vendor".into(), to_value(self.cpu.vendor));
        cpu.insert("brand_string".into(), to_value(self.cpu.brand_string));
        cpu.insert("cores".into(), to_value(self.cpu.cores));

        let mut fs = Vec::new();
        for mount in self.fs {
            let mut map: Map<String, Value> = Map::new();
            map.insert("filesystem".into(), to_value(mount.filesystem));
            map.insert("mountpoint".into(), to_value(mount.mountpoint));
            map.insert("size".into(), to_value(mount.size));
            map.insert("used".into(), to_value(mount.used));
            map.insert("available".into(), to_value(mount.available));
            map.insert("capacity".into(), to_value(mount.capacity));
            fs.push(map);
        }

        let mut net = Vec::new();
        for netif in self.net {
            let mut map: Map<String, Value> = Map::new();
            map.insert("interface".into(), to_value(netif.interface));
            map.insert("mac".into(), to_value(netif.mac));
            if let Some(inet) = netif.inet {
                let mut map1: Map<String, Value> = Map::new();
                map1.insert("address".into(), to_value(inet.address));
                map1.insert("netmask".into(), to_value(inet.netmask));
                map.insert("inet".into(), to_value(map1));
            }
            if let Some(inet6) = netif.inet6 {
                let mut map1: Map<String, Value> = Map::new();
                map1.insert("address".into(), to_value(inet6.address));
                map1.insert("prefixlen".into(), to_value(inet6.prefixlen));
                map1.insert("scopeid".into(), to_value(inet6.scopeid));
                map.insert("inet6".into(), to_value(map1));
            }
            if let Some(status) = netif.status {
                map.insert("status".into(), to_value(if status == NetifStatus::Active { "Active".to_string() } else { "Inactive".to_string() }));
            }
            net.push(map);
        }

        let mut os: Map<String, Value> = Map::new();
        os.insert("arch".into(), to_value(self.os.arch));
        os.insert("family".into(), to_value(self.os.family));
        os.insert("platform".into(), to_value(self.os.platform));
        os.insert("version".into(), to_value(self.os.version));

        let mut telemetry: Map<String, Value> = Map::new();
        telemetry.insert("cpu".into(), to_value(cpu));
        telemetry.insert("fs".into(), to_value(fs));
        telemetry.insert("hostname".into(), to_value(self.hostname));
        telemetry.insert("memory".into(), to_value(self.memory));
        telemetry.insert("net".into(), to_value(net));
        telemetry.insert("os".into(), to_value(os));
        to_value(telemetry)
    }
}

pub trait TelemetryTarget {
    fn telemetry_init(host: &mut Host) -> Result<Value>;
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Cpu {
    pub vendor: String,
    pub brand_string: String,
    pub cores: u32,
}

#[cfg(feature = "local-run")]
impl Cpu {
    pub fn new(vendor: &str, brand_string: &str, cores: u32) -> Cpu {
        Cpu {
            vendor: vendor.to_string(),
            brand_string: brand_string.to_string(),
            cores: cores,
        }
    }
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct FsMount {
    pub filesystem: String,
    pub mountpoint: String,
    pub size: u64,
    pub used: u64,
    pub available: u64,
    pub capacity: f32,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Netif {
    pub interface: String,
    pub mac: Option<String>,
    pub inet: Option<NetifIPv4>,
    pub inet6: Option<NetifIPv6>,
    pub status: Option<NetifStatus>,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable, PartialEq)]
pub enum NetifStatus {
    Active,
    Inactive,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct NetifIPv4 {
    pub address: String,
    pub netmask: String,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct NetifIPv6 {
    pub address: String,
    pub prefixlen: u8,
    pub scopeid: Option<String>,
}

#[cfg(feature = "local-run")]
#[derive(Debug, RustcEncodable)]
pub struct Os {
    pub arch: String,
    pub family: String,
    pub platform: String,
    pub version: String,
}

#[cfg(feature = "local-run")]
impl Os {
    pub fn new(arch: &str, family: &str, platform: &str, version: &str) -> Os {
        Os {
            arch: arch.to_string(),
            family: family.to_string(),
            platform: platform.to_string(),
            version: version.to_string(),
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "local-run")]
    use Host;
    #[cfg(feature = "local-run")]
    use super::*;

    #[cfg(feature = "local-run")]
    #[test]
    fn test_telemetry_init() {
        let path: Option<String> = None;
        let mut host = Host::local(path).unwrap();
        assert!(Telemetry::init(&mut host).is_ok());
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::io;
use std::io::Write;
use std::process::Command;
use std::path::Path;
use std::env;
use std::string::String;

pub struct Python {
    user: String,
    subject: String,
}

pub struct Scala {
    user: String,
    subject: String,
}

fn echo(solution: &str, path: &Path) -> io::Result<()> {
    let mut file = try!(fs::File::create(path));
    file.write_all(solution.as_bytes())
}

pub trait Lang {
    fn new(user: String, subject: String) -> Self;
    fn run_test(&self, solution: &str) -> String;
}

impl Lang for Python {
    fn new(user: String, subject: String) -> Python {
        Python { user: user, subject: subject}
    }

    fn run_test(&self, solution: &str) -> String {
        let from = format!("/home/{}/Code-Fight/python/{}", self.user, self.subject);
        let to = format!("/test/{}/Code-Fight/python/{}", self.user, self.subject);
        println!("from => {}, to => {}", &from, &to);

        // write solution to solution.py
        echo(solution, &Path::new(&format!("{}/solution.py", &to)));

        // run test
        let result = Command::new("nosetests")
               .arg(&to)
               .output()
               .expect("cat error to start");

    //    println!("result: {:?}", &result);
        format!("{:?}", &result)
    }
}

impl Lang for Scala {
    fn new(user: String, subject: String) -> Scala {
        Scala { user: user, subject: subject}
    }

    fn run_test(&self, solution: &str) -> String {
        let from = format!("/home/{}/Code-Fight/scala/{}", self.user, self.subject);
        let to = format!("/test/{}/Code-Fight/scala/{}", self.user, self.subject);
        println!("from => {}, to => {}", &from, &to);

        // write solution to Solution.scala
        echo(solution, &Path::new(&format!("{}/src/main/scala/org/sparktw/codefight/Solution.scala", &to)));

        // change location to subject
        let path = Path::new(&to);
        env::set_current_dir(&path).is_ok();

        // run test
        let result = Command::new("sbt")
               .arg("test")
               .output()
               .expect("cat error to start");

        //println!("result: {:?}", &result);
        format!("{:?}", &result)
    }
}
<commit_msg>Remove no-used statements.<commit_after>use std::fs;
use std::io;
use std::io::Write;
use std::process::Command;
use std::path::Path;
use std::env;
use std::string::String;

pub struct Python {
    user: String,
    subject: String,
}

pub struct Scala {
    user: String,
    subject: String,
}

fn echo(solution: &str, path: &Path) -> io::Result<()> {
    let mut file = try!(fs::File::create(path));
    file.write_all(solution.as_bytes())
}

pub trait Lang {
    fn new(user: String, subject: String) -> Self;
    fn run_test(&self, solution: &str) -> String;
}

impl Lang for Python {
    fn new(user: String, subject: String) -> Python {
        Python { user: user, subject: subject}
    }

    fn run_test(&self, solution: &str) -> String {
        let to = format!("/test/{}/Code-Fight/python/{}", self.user, self.subject);
        println!("language => python, to => {}", &to);

        // write solution to solution.py
        echo(solution, &Path::new(&format!("{}/solution.py", &to)));

        // run test
        let result =
            Command::new("nosetests")
               .arg(&to)
               .output()
               .ok()
               .expect("cat error to start");

//        println!("result: {:?}", &result);
        format!("{:?}", &result)
    }
}

impl Lang for Scala {
    fn new(user: String, subject: String) -> Scala {
        Scala { user: user, subject: subject}
    }

    fn run_test(&self, solution: &str) -> String {
        let to = format!("/test/{}/Code-Fight/scala/{}", self.user, self.subject);
        println!("language => scala, to => {}", &to);

        // write solution to Solution.scala
        echo(solution, &Path::new(&format!("{}/src/main/scala/org/sparktw/codefight/Solution.scala", &to)));
        let path = Path::new(&to);

        // change location to subject
        // run test
        let result =
            Command::new("/usr/bin/sbt")
               .current_dir(&path)
               .arg("test")
               .output()
               .ok()
               .expect("cat error to start");

//        println!("result: {:?}", &result);
        format!("{:?}", &result)
    }
}
<|endoftext|>


<commit_before>use assembler::x64::{Addr, R64};
use assembler::x64::R64::*;
use assembler::x64::traits::*;
use assembler::emit::{Emit, Label};

use template_interp::shared::{Dispatchable, build_interp, breakpoint};

use std::mem;
use std::env;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum Op {
    // stack.push(oparg_i8)
    LoadI8 = 0,

    // stack.push(stack[oparg_i8])
    LoadL,

    // r = stack.pop(); l = stack.pop(); if l < r then pc += oparg_i8
    BranchLt,

    // Callee clears the stack.
    // func_ix = oparg_u8; stack.push(pc); pc = func_table[oparg_u8]; locals = args
    Call,

    // res = stack.pop(); pc = stack.pop(); stack.pops(oparg_u8); stack.push(res)
    Ret,

    // rax = stack.pop(); halt
    Halt,

    // r = stack.pop(); l = stack.pop(); stack.push(l + r)
    Add,
}

#[derive(Debug, Clone, Copy)]
enum Instr {
    OpOnly(Op),
    OpWithArg(Op, i8),
}

fn instr_to_bs(is: &[Instr]) -> Vec<u8> {
    let mut bs = vec![];
    for i in is {
        match i {
            &Instr::OpOnly(op) => {
                bs.push(op as u8);
            }
            &Instr::OpWithArg(op, arg) => {
                bs.push(op as u8);
                bs.push(arg as u8);
            }
        }
    }
    bs
}

const LAST_OP: Op = Op::Add;

struct VMRegs {
    pc: R64,
    tmpl: R64,
    tmpr: R64,
    dispatch_table: R64,
    func_table: R64,
    trace_ctx: R64,
}

#[derive(Debug)]
struct Trace {
    bc_list: Vec<isize>,
    bc_set: HashSet<isize>,
}

impl Trace {
    fn new() -> Self {
        Trace {
            bc_list: Default::default(),
            bc_set: Default::default(),
        }
    }

    // Returns false if this trace is finished.
    fn record(&mut self, bc_ptr: isize) -> bool {
        self.bc_list.push(bc_ptr);
        if self.bc_set.contains(&bc_ptr) {
            return false;
        }
        self.bc_set.insert(bc_ptr);
        true
    }
}

#[derive(Debug)]
struct TraceContext {
    current: Trace,
    traces: Vec<Trace>,
}

impl TraceContext {
    fn new() -> Box<Self> {
        Box::new(TraceContext {
            current: Trace::new(),
            traces: vec![],
        })
    }

    fn as_ptr(&self) -> *const Self {
        self as *const _
    }

    fn record(&mut self, bc_ptr: isize) {
        if !self.current.record(bc_ptr) {
            let mut new_trace = Trace::new();
            mem::swap(&mut self.current, &mut new_trace);
            self.traces.push(new_trace);

            // Shall we record the trace bridge?
            self.record(bc_ptr);
        }
    }

    unsafe extern "C" fn record_unsafe(raw: *mut TraceContext, bc_ptr: isize) {
        (&mut *raw).record(bc_ptr);
    }
}

impl VMRegs {
    fn new() -> Self {
        VMRegs {
            pc: rdi,
            dispatch_table: rsi,
            func_table: rdx,
            tmpl: rcx,
            tmpr: r8,
            trace_ctx: r9,
        }
    }

    fn regs(&self) -> Vec<R64> {
        vec![self.pc, self.dispatch_table, self.func_table, self.tmpr, self.tmpl, self.trace_ctx]
    }
}

struct Opts {
    duplicate_branch_op_tails: bool,
    trace_on: bool,
}

impl Opts {
    fn new() -> Self {
        Opts {
            duplicate_branch_op_tails: true,
            trace_on: true,
        }
    }
}

impl From<u8> for Op {
    fn from(repr: u8) -> Self {
        Op::from_u8(repr)
    }
}

impl From<Op> for u8 {
    fn from(repr: Op) -> Self {
        repr as u8
    }
}

impl Dispatchable<(VMRegs, Opts)> for Op {
    fn build_dispatch_case(self, emit: &mut Emit, args: &(VMRegs, Opts)) {
        Op::build_dispatch_case(self, emit, &args.0, &args.1);
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, args: &(VMRegs, Opts), offset: i32) {
        Op::build_dispatch_with_pc_offset(emit, &args.0, &args.1, offset);
    }
}

impl Op {
    fn from_u8(repr: u8) -> Self {
        unsafe { mem::transmute(repr) }
    }

    fn build_dispatch_case(self, emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
        use self::Op::*;

        match self {
            LoadI8 => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .push(vr.tmpl);
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            LoadL => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .push(&(rsp + vr.tmpl * 8));
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            BranchLt => {
                emit.pop(vr.tmpr)
                    .pop(vr.tmpl)
                    .cmp(vr.tmpl, vr.tmpr);

                if opts.duplicate_branch_op_tails {
                    let mut lt = Label::new();
                    emit.jl(&mut lt);
                    build_dispatch_skip_oparg(emit, vr, opts);
                    emit.bind(&mut lt)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl);
                    build_dispatch_skip_oparg(emit, vr, opts);
                } else {
                    let mut ge = Label::new();
                    emit.jge(&mut ge)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl)
                        .bind(&mut ge);
                    build_dispatch_skip_oparg(emit, vr, opts);
                }
            }
            Call => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .add(vr.pc, 2)
                    .push(vr.pc)
                    .mov(vr.pc, &(vr.func_table + vr.tmpl * 8));
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Ret => {
                emit.pop(vr.tmpl)
                    .movsb(vr.tmpr, &(vr.pc + 1))
                    .pop(vr.pc)
                    .lea(rsp, &(rsp + vr.tmpr * 8))
                    .push(vr.tmpl);
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Halt => {
                emit.pop(rax)
                    .ret();
            }
            Add => {
                emit.pop(vr.tmpr)
                    .add(&Addr::B(rsp), vr.tmpr);
                Op::build_dispatch_with_pc_offset(emit, vr, opts, 1);
            }
        }
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, vr: &VMRegs, opts: &Opts, offset: i32) {
        if offset == 0 {
            emit.movsb(vr.tmpl, &Addr::B(vr.pc));
        } else {
            emit.movsb(vr.tmpl, &(vr.pc + offset))
                .add(vr.pc, offset);
        }

        // Like PyPy's jit_merge_point
        if opts.trace_on {
            // XXX: stack alignment?
            for r in vr.regs() {
                emit.push(r);
            }

            // Align the stack
            emit.push(rsp)
                .push(&Addr::B(rsp))
                .and(rsp, -16)

                .mov(rdi, vr.trace_ctx)
                .mov(rsi, vr.pc)
                .mov(rax, unsafe { mem::transmute::<_, i64>(TraceContext::record_unsafe) })
                .call(rax)

                .mov(rsp, &(rsp + 8));

            for r in vr.regs().iter().rev() {
                emit.pop(*r);
            }
        }

        emit.jmp(&(vr.dispatch_table + vr.tmpl * 8));
    }
}

fn build_dispatch_skip_oparg(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    Op::build_dispatch_with_pc_offset(emit, vr, opts, 2)
}

fn build_dispatch_correct_pc(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    Op::build_dispatch_with_pc_offset(emit, vr, opts, 0)
}

pub fn main(n: u8) {
    use self::Instr::*;
    use self::Op::*;

    let mut opts = Opts::new();
    if env::var("NO_DUP_BR_TAILS").is_ok() {
        opts.duplicate_branch_op_tails = false;
    };

    let (labels, jm) = build_interp(LAST_OP, &(VMRegs::new(), opts));

    let main_code = instr_to_bs(&[
        OpWithArg(LoadI8, n as i8),
        OpWithArg(Call, 1),
        OpOnly(Halt),
    ]);

    let id_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let fibo_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, 2),
        OpWithArg(BranchLt, 17),

        // Recur case.
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, -1),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpWithArg(LoadL, 2),
        OpWithArg(LoadI8, -2),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpOnly(Add),
        OpWithArg(Ret, 1),

        // Base case.
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let func_table = [
        id_code.as_ptr(),
        fibo_code.as_ptr(),
    ];

    let trace_ctx = TraceContext::new();

    let res = unsafe {
        let pc = main_code.as_ptr() as isize;
        let lbl_ptr = labels.as_ptr() as isize;
        let func_table_ptr = func_table.as_ptr() as isize;
        let trace_ctx_ptr = trace_ctx.as_ptr() as isize;
        if env::var("BREAK").is_ok() {
            breakpoint();
        }
        jm.call_ptr6_ptr(pc, lbl_ptr, func_table_ptr, 0, 0, trace_ctx_ptr)
    };
    println!("res = {}", res);
    println!("trace = {:?}", trace_ctx);
}
<commit_msg>Using non-native stack.<commit_after>use assembler::x64::{Addr, R64};
use assembler::x64::R64::*;
use assembler::x64::traits::*;
use assembler::emit::{Emit, Label};

use template_interp::shared::{Dispatchable, build_interp, breakpoint};

use std::mem;
use std::env;
use std::collections::HashSet;

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
enum Op {
    // stack.push(oparg_i8)
    LoadI8 = 0,

    // stack.push(stack[oparg_i8])
    LoadL,

    // r = stack.pop(); l = stack.pop(); if l < r then pc += oparg_i8
    BranchLt,

    // Callee clears the stack.
    // func_ix = oparg_u8; stack.push(pc); pc = func_table[oparg_u8]; locals = args
    Call,

    // res = stack.pop(); pc = stack.pop(); stack.pops(oparg_u8); stack.push(res)
    Ret,

    // rax = stack.pop(); halt
    Halt,

    // r = stack.pop(); l = stack.pop(); stack.push(l + r)
    Add,
}

#[derive(Debug, Clone, Copy)]
enum Instr {
    OpOnly(Op),
    OpWithArg(Op, i8),
}

fn instr_to_bs(is: &[Instr]) -> Vec<u8> {
    let mut bs = vec![];
    for i in is {
        match i {
            &Instr::OpOnly(op) => {
                bs.push(op as u8);
            }
            &Instr::OpWithArg(op, arg) => {
                bs.push(op as u8);
                bs.push(arg as u8);
            }
        }
    }
    bs
}

const LAST_OP: Op = Op::Add;

#[repr(C)]
struct InterpContext {
    pc: isize,
    dispatch_table: isize,
    func_table: isize,
    trace_ctx: isize,
    sp: isize,
}

const PC_OFFSET: i32 = 0;
const DT_OFFSET: i32 = 1 * 8;
const FT_OFFSET: i32 = 2 * 8;
const TC_OFFSET: i32 = 3 * 8;
const SP_OFFSET: i32 = 4 * 8;

#[derive(Debug)]
struct Trace {
    bc_list: Vec<isize>,
    bc_set: HashSet<isize>,
}

impl Trace {
    fn new() -> Self {
        Trace {
            bc_list: Default::default(),
            bc_set: Default::default(),
        }
    }

    // Returns false if this trace is finished.
    fn record(&mut self, bc_ptr: isize) -> bool {
        self.bc_list.push(bc_ptr);
        if self.bc_set.contains(&bc_ptr) {
            return false;
        }
        self.bc_set.insert(bc_ptr);
        true
    }
}

#[derive(Debug)]
struct TraceContext {
    current: Trace,
    traces: Vec<Trace>,
}

impl TraceContext {
    fn new() -> Box<Self> {
        Box::new(TraceContext {
            current: Trace::new(),
            traces: vec![],
        })
    }

    fn as_ptr(&self) -> *const Self {
        self as *const _
    }

    fn record(&mut self, bc_ptr: isize) {
        if !self.current.record(bc_ptr) {
            let mut new_trace = Trace::new();
            mem::swap(&mut self.current, &mut new_trace);
            self.traces.push(new_trace);

            // Shall we record the trace bridge?
            self.record(bc_ptr);
        }
    }

    unsafe extern "C" fn record_unsafe(raw: *mut TraceContext, bc_ptr: isize) {
        (&mut *raw).record(bc_ptr);
    }
}

struct VMRegs {
    pc: R64,
    tmpl: R64,
    tmpr: R64,
    dispatch_table: R64,
    func_table: R64,
    trace_ctx: R64,
    sp: R64,
    scratch: R64,
}

impl VMRegs {
    fn new() -> Self {
        VMRegs {
            pc: rdi,
            dispatch_table: rsi,
            func_table: rdx,
            tmpl: rcx,
            tmpr: r8,
            trace_ctx: r9,
            sp: r10,
            scratch: r11,
        }
    }

    fn regs(&self) -> Vec<R64> {
        vec![self.pc, self.dispatch_table, self.func_table, self.tmpr, self.tmpl, self.trace_ctx]
    }
}

struct Opts {
    duplicate_branch_op_tails: bool,
    trace_on: bool,
}

impl Opts {
    fn new() -> Self {
        Opts {
            duplicate_branch_op_tails: true,
            trace_on: false,
        }
    }
}

impl From<u8> for Op {
    fn from(repr: u8) -> Self {
        Op::from_u8(repr)
    }
}

impl From<Op> for u8 {
    fn from(repr: Op) -> Self {
        repr as u8
    }
}

impl Dispatchable<(VMRegs, Opts)> for Op {
    fn build_dispatch_case(self, emit: &mut Emit, args: &(VMRegs, Opts)) {
        Op::build_dispatch_case(self, emit, &args.0, &args.1);
    }

    fn build_dispatch_with_pc_offset(emit: &mut Emit, args: &(VMRegs, Opts), offset: i32) {
        build_dispatch_with_pc_offset(emit, &args.0, &args.1, offset);
    }
}

impl Op {
    fn from_u8(repr: u8) -> Self {
        unsafe { mem::transmute(repr) }
    }

    fn build_dispatch_case(self, emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
        use self::Op::*;

        fn push_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(&(vr.sp + (-8)), r)
                .sub(vr.sp, 8);
        }

        fn push_a(emit: &mut Emit, vr: &VMRegs, a: &Addr) {
            emit.mov(vr.scratch, a)
                .mov(&(vr.sp + (-8)), vr.scratch)
                .sub(vr.sp, 8);
        }

        fn pop_r(emit: &mut Emit, vr: &VMRegs, r: R64) {
            emit.mov(r, &Addr::B(vr.sp))
                .add(vr.sp, 8);
        }

        match self {
            LoadI8 => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            LoadL => {
                emit.movsb(vr.tmpl, &(vr.pc + 1));
                push_a(emit, vr, &(vr.sp + vr.tmpl * 8));
                build_dispatch_skip_oparg(emit, vr, opts);
            }
            BranchLt => {
                pop_r(emit, vr, vr.tmpr);
                pop_r(emit, vr, vr.tmpl);
                emit.cmp(vr.tmpl, vr.tmpr);

                if opts.duplicate_branch_op_tails {
                    let mut lt = Label::new();
                    emit.jl(&mut lt);
                    build_dispatch_skip_oparg(emit, vr, opts);
                    emit.bind(&mut lt)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl);
                    build_dispatch_skip_oparg(emit, vr, opts);
                } else {
                    let mut ge = Label::new();
                    emit.jge(&mut ge)
                        .movsb(vr.tmpl, &(vr.pc + 1))
                        .add(vr.pc, vr.tmpl)
                        .bind(&mut ge);
                    build_dispatch_skip_oparg(emit, vr, opts);
                }
            }
            Call => {
                emit.movsb(vr.tmpl, &(vr.pc + 1))
                    .add(vr.pc, 2);

                push_r(emit, vr, vr.pc);
                emit.mov(vr.pc, &(vr.func_table + vr.tmpl * 8));
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Ret => {
                pop_r(emit, vr, vr.tmpl);
                emit.movsb(vr.tmpr, &(vr.pc + 1));
                pop_r(emit, vr, vr.pc);
                emit.lea(vr.sp, &(vr.sp + vr.tmpr * 8));
                push_r(emit, vr, vr.tmpl);
                build_dispatch_correct_pc(emit, vr, opts);
            }
            Halt => {
                pop_r(emit, vr, rax);
                emit.ret();
            }
            Add => {
                pop_r(emit, vr, vr.tmpr);
                emit.add(&Addr::B(vr.sp), vr.tmpr);
                build_dispatch_with_pc_offset(emit, vr, opts, 1);
            }
        }
    }

}

fn build_dispatch_with_pc_offset(emit: &mut Emit, vr: &VMRegs, opts: &Opts, offset: i32) {
    if offset == 0 {
        emit.movsb(vr.tmpl, &Addr::B(vr.pc));
    } else {
        emit.movsb(vr.tmpl, &(vr.pc + offset))
            .add(vr.pc, offset);
    }

    // Like PyPy's jit_merge_point
    if opts.trace_on {
        let rs = vr.regs();
        for r in &rs {
            emit.push(*r);
        }

        let mut moar_pops: Box<FnMut(&mut Emit)> = if rs.len() % 2 == 0 {
            // Stack alignment
            emit.push(rax);
            Box::new(|emit| { emit.pop(rax); })
        } else {
            Box::new(|_| ())
        };

        emit.mov(rdi, vr.trace_ctx)
            .mov(rsi, vr.pc)
            .mov(rax, unsafe { mem::transmute::<_, i64>(TraceContext::record_unsafe) })
            .call(rax);

        moar_pops(emit);

        for r in rs.iter().rev() {
            emit.pop(*r);
        }
    }

    emit.jmp(&(vr.dispatch_table + vr.tmpl * 8));
}

fn build_dispatch_skip_oparg(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 2)
}

fn build_dispatch_correct_pc(emit: &mut Emit, vr: &VMRegs, opts: &Opts) {
    build_dispatch_with_pc_offset(emit, vr, opts, 0)
}

pub fn main(n: u8) {
    use self::Instr::*;
    use self::Op::*;

    let mut opts = Opts::new();
    if env::var("NO_DUP_BR_TAILS").is_ok() {
        opts.duplicate_branch_op_tails = false;
    };

    if env::var("TRACE_ON").is_ok() {
        opts.trace_on = true;
    };

    let (labels, jm) = build_interp(LAST_OP, &(VMRegs::new(), opts));

    let main_code = instr_to_bs(&[
        OpWithArg(LoadI8, n as i8),
        OpWithArg(Call, 1),
        OpOnly(Halt),
    ]);

    let id_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let fibo_code = instr_to_bs(&[
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, 2),
        OpWithArg(BranchLt, 17),

        // Recur case.
        OpWithArg(LoadL, 1),
        OpWithArg(LoadI8, -1),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpWithArg(LoadL, 2),
        OpWithArg(LoadI8, -2),
        OpOnly(Add),
        OpWithArg(Call, 1),

        OpOnly(Add),
        OpWithArg(Ret, 1),

        // Base case.
        OpWithArg(LoadL, 1),
        OpWithArg(Ret, 1),
    ]);

    let func_table = [
        id_code.as_ptr(),
        fibo_code.as_ptr(),
    ];

    let trace_ctx = TraceContext::new();

    let stack = [0_isize; 1024];

    let res = unsafe {
        let pc = main_code.as_ptr() as isize;
        let lbl_ptr = labels.as_ptr() as isize;
        let func_table_ptr = func_table.as_ptr() as isize;
        let trace_ctx_ptr = trace_ctx.as_ptr() as isize;
        let stack_ptr = stack.as_ptr().offset(stack.len() as isize) as isize;
        let ictx = InterpContext {
            pc: pc,
            func_table: func_table_ptr,
            trace_ctx: trace_ctx_ptr,
            dispatch_table: lbl_ptr,
            sp: stack_ptr,
        };
        if env::var("BREAK").is_ok() {
            breakpoint();
        }
        jm.call_ptr_ptr(&ictx as *const _ as isize)
    };
    println!("res = {}", res);
    println!("trace = {:?}", trace_ctx);
}
<|endoftext|>


<commit_before>//
// btree.rs
// Nif Ward
// 10/24/13
//
// starting implementation of a btree for rust
// inspired by github user davidhalperin's gist

//What's in a BTree?
pub struct BTree<K, V>{
    root: Node<K, V>,
    len: uint,
    lower_bound: uint,
    upper_bound: uint
}

impl<K: Clone + TotalOrd, V: Clone> BTree<K, V>{

    //Returns new BTree with root node (leaf) and user-supplied lower bound
    fn new(k: K, v: V, lb: uint) -> BTree<K, V>{
        BTree{
	    root: Node::new_leaf(~[LeafElt::new(k, v)]),
	    len: 1,
	    lower_bound: lb,
	    upper_bound: 2 * lb
        }
    }

    //Helper function for clone
    fn new_with_node_len(n: Node<K, V>, length: uint, lb: uint) -> BTree<K, V>{
        BTree{
	    root: n,
	    len: length,
	    lower_bound: lb,
	    upper_bound: 2 * lb
	}
    }

    fn clone(&self) -> BTree<K, V>{
        return BTree::new_with_node_len(self.root.clone(), self.len, self.lower_bound);
    }

    fn get(self, k: K) -> Option<V>{
        return self.root.get(k);
    }

    fn add(self, k: K, v: V) -> bool{
        let is_get = &self.clone().get(k.clone());
	if is_get.is_some(){ return false; }
	else{
	    std::util::replace(&mut self.root.clone(),self.root.add(k.clone(), v));
	    return true;
	}

    }

}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for BTree<K, V>{
    //Returns a string representation of the BTree
    fn to_str(&self) -> ~str{
        let ret=self.root.to_str();
	return ret;
    }
}

//Node types
enum Node<K, V>{
    LeafNode(Leaf<K, V>),
    BranchNode(Branch<K, V>)
}

//Node functions/methods
impl<K: Clone + TotalOrd, V: Clone> Node<K, V>{
    //differentiates between leaf and branch nodes
    fn is_leaf(&self) -> bool{
        match self{
	    &LeafNode(*) => true,
	    &BranchNode(*) => false
        }
    }

    //Creates a new leaf or branch node
    fn new_leaf(vec: ~[LeafElt<K, V>]) -> Node<K,V>{
         LeafNode(Leaf::new(vec))
    }
    fn new_branch(vec: ~[BranchElt<K, V>], right: ~Node<K, V>) -> Node<K, V>{
        BranchNode(Branch::new(vec, right))
    }

    fn get(&self, k: K) -> Option<V>{
        match *self{
	    LeafNode(ref leaf) => return leaf.get(k),
	    BranchNode(ref branch) => return branch.get(k)
        }
    }

    //A placeholder for add
    //Currently returns a leaf node with a single value (the added one)
    fn add(self, k: K, v: V) -> Node<K, V>{
        return Node::new_leaf(~[LeafElt::new(k, v)]);
    }
}

impl<K: Clone + TotalOrd, V: Clone> Clone for Node<K, V>{
    fn clone(&self) -> Node<K, V>{
        match *self{
	    LeafNode(ref leaf) => return Node::new_leaf(leaf.elts.clone()),
	    BranchNode(ref branch) => return Node::new_branch(branch.elts.clone(), branch.rightmost_child.clone())
	}
    }
}

impl<K: Clone + TotalOrd, V: Clone> TotalOrd for Node<K, V>{
    #[allow(unused_variable)]
    fn cmp(&self, other: &Node<K, V>) -> Ordering{
        //Requires a match statement--defer these procs to branch and leaf.
        /* if self.elts[0].less_than(other.elts[0]) { return Less}
	if self.elts[0].greater_than(other.elts[0]) {return Greater}
	else {return Equal}
	*/
	return Equal;
    }
}

impl<K: Clone + TotalOrd, V: Clone> TotalEq for Node<K, V>{
    //Making sure Nodes have TotalEq
    #[allow(unused_variable)]
    fn equals(&self, other: &Node<K, V>) -> bool{
    /* put in a match and defer this stuff to branch and leaf

        let mut shorter = 0;
        if self.elts.len() <= other.elts.len(){
	    shorter = self.elts.len();
	}
	else{
	    shorter = other.elts.len();
	}
	let mut i = 0;
	while i < shorter{
	    if !self.elts[i].has_key(other.elts[i].key){
	        return false;
	    }
	    i +=1;
        }
	return true;
    */
    return true;
    }
}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for Node<K, V>{
    fn to_str(&self) -> ~str{
       match *self{
           LeafNode(ref leaf) => leaf.to_str(),
	   BranchNode(*) => ~""
       }
    }
}

//Array with no children
struct Leaf<K, V>{
    elts: ~[LeafElt<K, V>]
}

//Array of values with children, plus a rightmost child (greater than all)
struct Branch<K, V>{
    elts: ~[BranchElt<K,V>],
    rightmost_child: ~Node<K, V>
}

impl<K: Clone + TotalOrd, V: Clone> Leaf<K, V>{
    //Constructor takes in a vector of leaves
    fn new(vec: ~[LeafElt<K, V>]) -> Leaf<K, V>{
        Leaf{
            elts: vec
        }
    }

    fn get(&self, k: K) -> Option<V>{
        for s in self.elts.iter(){
	    let order=s.key.cmp(&k);
	    match order{
	        Equal => return Some(s.value.clone()),
		_ => {}
	    }
	}
	return None;
    }

    //Add method in progress
    fn add(&self, k: K, v: V) -> Node<K, V>{
        return Node::new_leaf(~[LeafElt::new(k, v)]);
    }

}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for Leaf<K, V>{
    fn to_str(&self) -> ~str{
       let mut ret=~"";
       for s in self.elts.iter(){
           ret = ret+" // "+ s.to_str();
       }
       return ret;
    }

}

impl<K: Clone + TotalOrd, V: Clone> Branch<K, V>{
    //constructor takes a branch vector and a rightmost child
    fn new(vec: ~[BranchElt<K, V>], right: ~Node<K, V>) -> Branch<K, V>{
        Branch{
	    elts: vec,
	    rightmost_child: right
        }
    }

    fn get(&self, k: K) -> Option<V>{
        for s in self.elts.iter(){
	    let order = s.key.cmp(&k);
	    match order{
	        Less => return s.left.get(k),
		Equal => return Some(s.value.clone()),
		_ => {}
	    }
	}
	return self.rightmost_child.get(k);
    }

    //Add method in progress
    fn add(&self, k: K, v: V) -> Node<K, V>{
        return Node::new_leaf(~[LeafElt::new(k, v)]);
    }
}

//No left child
struct LeafElt<K, V>{
    key: K,
    value: V
}

//Has a left child
struct BranchElt<K, V>{
    left: Node<K, V>,
    key: K,
    value: V
}

impl<K: Clone + TotalOrd, V> LeafElt<K, V>{
    fn new(k: K, v: V) -> LeafElt<K, V>{
        LeafElt{
            key: k,
	    value: v
	}
    }

    fn less_than(&self, other: LeafElt<K, V>) -> bool{
        let order = self.key.cmp(&other.key);
	match order{
	    Less => true,
	    _ => false
	}
    }

    fn greater_than(&self, other: LeafElt<K, V>) -> bool{
        let order = self.key.cmp(&other.key);
	match order{
	    Greater => true,
	    _ => false
	}
    }

    fn has_key(&self, other: K) -> bool{
        let order = self.key.cmp(&other);
	match order{
	    Equal => true,
	    _ => false
	}
    }

}

impl<K: Clone + TotalOrd, V: Clone> Clone for LeafElt<K, V>{
    fn clone(&self) -> LeafElt<K, V>{
        return LeafElt::new(self.key.clone(), self.value.clone());
    }
}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for LeafElt<K, V>{
    fn to_str(&self) -> ~str{
        return "Key: "+self.key.to_str()+", value: "+self.value.to_str()+"; ";
    }

}

impl<K: Clone + TotalOrd, V: Clone> BranchElt<K, V>{
    fn new(k: K, v: V, n: Node<K, V>) -> BranchElt<K, V>{
        BranchElt{
            left: n,
            key: k,
            value: v
        }
    }

    //Add method in progress.  Should it return a branch or a leaf elt?  It will depend on implementation.
    fn add(&self, k: K, v: V) -> LeafElt<K, V>{
        return LeafElt::new(k, v);
    }
}

impl<K: Clone + TotalOrd, V: Clone> Clone for BranchElt<K, V>{
    fn clone(&self) -> BranchElt<K, V>{
        return BranchElt::new(self.key.clone(), self.value.clone(), self.left.clone());
    }
}

#[test]
fn add_test(){
    let b = BTree::new(1, ~"abc", 2);
    let is_add = b.add(2, ~"xyz");
    assert!(is_add);

}

#[test]
fn get_test(){
    let b = BTree::new(1, ~"abc", 2);
    let val = b.get(1);
    assert_eq!(val, Some(~"abc"));
}

//Testing LeafElt<K, V> functions (less_than, greater_than, and has_key)
#[test]
fn leaf_lt(){
    let l1 = LeafElt::new(1, ~"abc");
    let l2 = LeafElt::new(2, ~"xyz");
    assert!(l1.less_than(l2));
}

#[test]
fn leaf_gt(){
    let l1 = LeafElt::new(1, ~"abc");
    let l2 = LeafElt::new(2, ~"xyz");
    assert!(l2.greater_than(l1));
}

#[test]
fn leaf_hk(){
    let l1 = LeafElt::new(1, ~"abc");
    assert!(l1.has_key(1));
}

fn main(){

}
<commit_msg>Re-arranging some things in btree.rs to accommodate testing.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//
// btree.rs
// Nif Ward
// 10/24/13
//
// starting implementation of a btree for rust
// inspired by github user davidhalperin's gist

//What's in a BTree?
pub struct BTree<K, V>{
    root: Node<K, V>,
    len: uint,
    lower_bound: uint,
    upper_bound: uint
}

impl<K: Clone + TotalOrd, V: Clone> BTree<K, V>{

    //Returns new BTree with root node (leaf) and user-supplied lower bound
    fn new(k: K, v: V, lb: uint) -> BTree<K, V>{
        BTree{
            root: Node::new_leaf(~[LeafElt::new(k, v)]),
            len: 1,
            lower_bound: lb,
            upper_bound: 2 * lb
        }
    }

    //Helper function for clone
    fn new_with_node_len(n: Node<K, V>, length: uint, lb: uint) -> BTree<K, V>{
        BTree{
            root: n,
            len: length,
            lower_bound: lb,
            upper_bound: 2 * lb
        }
    }

    fn clone(&self) -> BTree<K, V>{
        return BTree::new_with_node_len(self.root.clone(), self.len, self.lower_bound);
    }

    fn get(self, k: K) -> Option<V>{
        return self.root.get(k);
    }

    fn add(self, k: K, v: V) -> bool{
        let is_get = &self.clone().get(k.clone());
        if is_get.is_some(){ return false; }
        else{
            std::util::replace(&mut self.root.clone(),self.root.add(k.clone(), v));
            return true;
        }

    }

}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for BTree<K, V>{
    //Returns a string representation of the BTree
    fn to_str(&self) -> ~str{
        let ret=self.root.to_str();
        return ret;
    }
}

//Node types
enum Node<K, V>{
    LeafNode(Leaf<K, V>),
    BranchNode(Branch<K, V>)
}

//Node functions/methods
impl<K: Clone + TotalOrd, V: Clone> Node<K, V>{
    //differentiates between leaf and branch nodes
    fn is_leaf(&self) -> bool{
        match self{
            &LeafNode(*) => true,
            &BranchNode(*) => false
        }
    }

    //Creates a new leaf or branch node
    fn new_leaf(vec: ~[LeafElt<K, V>]) -> Node<K,V>{
         LeafNode(Leaf::new(vec))
    }
    fn new_branch(vec: ~[BranchElt<K, V>], right: ~Node<K, V>) -> Node<K, V>{
        BranchNode(Branch::new(vec, right))
    }

    fn get(&self, k: K) -> Option<V>{
        match *self{
            LeafNode(ref leaf) => return leaf.get(k),
            BranchNode(ref branch) => return branch.get(k)
        }
    }

    //A placeholder for add
    //Currently returns a leaf node with a single value (the added one)
    fn add(self, k: K, v: V) -> Node<K, V>{
        return Node::new_leaf(~[LeafElt::new(k, v)]);
    }
}

impl<K: Clone + TotalOrd, V: Clone> Clone for Node<K, V>{
    fn clone(&self) -> Node<K, V>{
        match *self{
            LeafNode(ref leaf) => return Node::new_leaf(leaf.elts.clone()),
            BranchNode(ref branch) => return Node::new_branch(branch.elts.clone(),
                                      branch.rightmost_child.clone())
        }
    }
}

impl<K: Clone + TotalOrd, V: Clone> TotalOrd for Node<K, V>{
    #[allow(unused_variable)]
    fn cmp(&self, other: &Node<K, V>) -> Ordering{
        //Requires a match statement--defer these procs to branch and leaf.
        /* if self.elts[0].less_than(other.elts[0]) { return Less}
        if self.elts[0].greater_than(other.elts[0]) {return Greater}
        else {return Equal}
        */
        return Equal;
    }
}

impl<K: Clone + TotalOrd, V: Clone> TotalEq for Node<K, V>{
    //Making sure Nodes have TotalEq
    #[allow(unused_variable)]
    fn equals(&self, other: &Node<K, V>) -> bool{
    /* put in a match and defer this stuff to branch and leaf

        let mut shorter = 0;
        if self.elts.len() <= other.elts.len(){
            shorter = self.elts.len();
        }
        else{
            shorter = other.elts.len();
        }
        let mut i = 0;
        while i < shorter{
            if !self.elts[i].has_key(other.elts[i].key){
                return false;
            }
            i +=1;
        }
        return true;
    */
    return true;
    }
}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for Node<K, V>{
    fn to_str(&self) -> ~str{
       match *self{
           LeafNode(ref leaf) => leaf.to_str(),
           BranchNode(*) => ~""
       }
    }
}

//Array with no children
struct Leaf<K, V>{
    elts: ~[LeafElt<K, V>]
}

//Array of values with children, plus a rightmost child (greater than all)
struct Branch<K, V>{
    elts: ~[BranchElt<K,V>],
    rightmost_child: ~Node<K, V>
}

impl<K: Clone + TotalOrd, V: Clone> Leaf<K, V>{
    //Constructor takes in a vector of leaves
    fn new(vec: ~[LeafElt<K, V>]) -> Leaf<K, V>{
        Leaf{
            elts: vec
        }
    }

    fn get(&self, k: K) -> Option<V>{
        for s in self.elts.iter(){
            let order=s.key.cmp(&k);
            match order{
                Equal => return Some(s.value.clone()),
                _ => {}
            }
        }
        return None;
    }

    //Add method in progress
    fn add(&self, k: K, v: V) -> Node<K, V>{
        return Node::new_leaf(~[LeafElt::new(k, v)]);
    }

}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for Leaf<K, V>{
    fn to_str(&self) -> ~str{
       let mut ret=~"";
       for s in self.elts.iter(){
           ret = ret+" // "+ s.to_str();
       }
       return ret;
    }

}

impl<K: Clone + TotalOrd, V: Clone> Branch<K, V>{
    //constructor takes a branch vector and a rightmost child
    fn new(vec: ~[BranchElt<K, V>], right: ~Node<K, V>) -> Branch<K, V>{
        Branch{
            elts: vec,
            rightmost_child: right
        }
    }

    fn get(&self, k: K) -> Option<V>{
        for s in self.elts.iter(){
            let order = s.key.cmp(&k);
            match order{
                Less => return s.left.get(k),
                Equal => return Some(s.value.clone()),
                _ => {}
            }
        }
        return self.rightmost_child.get(k);
     }

    //Add method in progress
    fn add(&self, k: K, v: V) -> Node<K, V>{
        return Node::new_leaf(~[LeafElt::new(k, v)]);
    }
}

//No left child
struct LeafElt<K, V>{
    key: K,
    value: V
}

//Has a left child
struct BranchElt<K, V>{
    left: Node<K, V>,
    key: K,
    value: V
}

impl<K: Clone + TotalOrd, V> LeafElt<K, V>{
    fn new(k: K, v: V) -> LeafElt<K, V>{
        LeafElt{
            key: k,
            value: v
        }
    }

    fn less_than(&self, other: LeafElt<K, V>) -> bool{
        let order = self.key.cmp(&other.key);
        match order{
            Less => true,
            _ => false
        }
    }

    fn greater_than(&self, other: LeafElt<K, V>) -> bool{
        let order = self.key.cmp(&other.key);
        match order{
            Greater => true,
            _ => false
        }
    }

    fn has_key(&self, other: K) -> bool{
        let order = self.key.cmp(&other);
        match order{
            Equal => true,
            _ => false
        }
    }

}

impl<K: Clone + TotalOrd, V: Clone> Clone for LeafElt<K, V>{
    fn clone(&self) -> LeafElt<K, V>{
        return LeafElt::new(self.key.clone(), self.value.clone());
    }
}

impl<K: ToStr + TotalOrd, V: ToStr> ToStr for LeafElt<K, V>{
    fn to_str(&self) -> ~str{
        return "Key: "+self.key.to_str()+", value: "+self.value.to_str()+"; ";
    }

}

impl<K: Clone + TotalOrd, V: Clone> BranchElt<K, V>{
    fn new(k: K, v: V, n: Node<K, V>) -> BranchElt<K, V>{
        BranchElt{
            left: n,
            key: k,
            value: v
        }
    }

    //Add method in progress.  Should it return a branch or a leaf elt?
    fn add(&self, k: K, v: V) -> LeafElt<K, V>{
        return LeafElt::new(k, v);
    }
}

impl<K: Clone + TotalOrd, V: Clone> Clone for BranchElt<K, V>{
    fn clone(&self) -> BranchElt<K, V>{
        return BranchElt::new(self.key.clone(), self.value.clone(), self.left.clone());
    }
}

#[cfg(test)]
mod test_btree{

    use super::*;

    #[test]
    fn add_test(){
        let b = BTree::new(1, ~"abc", 2);
        let is_add = b.add(2, ~"xyz");
        assert!(is_add);
    }

    #[test]
    fn get_test(){
        let b = BTree::new(1, ~"abc", 2);
        let val = b.get(1);
        assert_eq!(val, Some(~"abc"));
    }

    //Testing LeafElt<K, V> functions (less_than, greater_than, and has_key)
    #[test]
    fn leaf_lt(){
        let l1 = LeafElt::new(1, ~"abc");
        let l2 = LeafElt::new(2, ~"xyz");
        assert!(l1.less_than(l2));
    }

    #[test]
    fn leaf_gt(){
        let l1 = LeafElt::new(1, ~"abc");
        let l2 = LeafElt::new(2, ~"xyz");
        assert!(l2.greater_than(l1));
    }

    #[test]
    fn leaf_hk(){
        let l1 = LeafElt::new(1, ~"abc");
        assert!(l1.has_key(1));
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use buffer::TypedBuffer;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::DescriptorWrite;
use image::ImageView;
use sampler::Sampler;

/// Call this macro with the layout of a pipeline to generate some helper structs that wrap around
/// vulkano's unsafe APIs.
// TODO: more docs
#[macro_export]
macro_rules! pipeline_layout {
    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

        impl CustomPipeline {
            #[allow(unsafe_code)]
            pub fn new(device: &Arc<Device>) -> Result<Arc<CustomPipeline>, OomError> {
                let layouts = vec![
                    $(
                        try!($name::build_set_layout(device))
                    ),*
                ];

                let inner = unsafe {
                    try!(UnsafePipelineLayout::new(device, layouts.iter()))
                };

                Ok(Arc::new(CustomPipeline {
                    inner: inner
                }))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner_pipeline_layout(&self) -> &UnsafePipelineLayout {
                &self.inner
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayoutDesc for CustomPipeline {
            type SetsIter = VecIntoIter<Self::DescIter>;
            type DescIter = VecIntoIter<DescriptorDesc>;

            fn descriptors_desc(&self) -> Self::SetsIter {
                // FIXME:
                vec![].into_iter()
            }
        }

        pipeline_layout!{__inner__ (0) $($name: {$($field: $ty),*}),*}
    };

    (__inner__ ($num:expr) $name:ident: { $($field:ident: $ty:ty),* } $($rest:tt)*) => {
        pub mod $name {
            use std::sync::Arc;
            use super::CustomPipeline;
            use $crate::OomError;
            use $crate::device::Device;
            use $crate::descriptor::descriptor::DescriptorDesc;
            use $crate::descriptor::descriptor::DescriptorWrite;
            use $crate::descriptor::descriptor::ShaderStages;
            use $crate::descriptor::descriptor_set::DescriptorPool;
            use $crate::descriptor::descriptor_set::DescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
            use $crate::descriptor::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::ValidParameter;

            // This constant is part of the API, but Rust sees it as dead code.
            #[allow(dead_code)]
            pub const SET_NUM: u32 = $num;

            #[allow(non_camel_case_types)]
            pub struct Descriptors<$($field),*> {
                $(
                    pub $field: $field
                ),*
            }

            #[allow(non_camel_case_types)]
            #[allow(unused_assignments)]
            impl<$($field: ValidParameter<$ty>),*> Descriptors<$($field),*> {
                pub fn writes(&self) -> Vec<DescriptorWrite> {
                    let mut writes = Vec::new();
                    let mut binding = 0;
                    $(
                        writes.push(self.$field.write(binding));
                        binding += 1;
                    )*
                    writes
                }
            }

            pub struct Set {
                inner: UnsafeDescriptorSet
            }

            impl Set {
                #[inline]
                #[allow(non_camel_case_types)]
                pub fn new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field)*>)
                           -> Result<Arc<Set>, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner_pipeline_layout().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Arc::new(Set { inner: set }))
                    }
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner_descriptor_set(&self) -> &UnsafeDescriptorSet {
                    &self.inner
                }
            }

            #[allow(unused_assignments)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Result<Arc<UnsafeDescriptorSetLayout>, OomError>
            {
                let mut descriptors = Vec::new();
                let mut binding = 0;

                $(
                    descriptors.push(DescriptorDesc {
                        binding: binding,
                        ty: <$ty as DescriptorMarker>::descriptor_type(),
                        array_count: 1,                     // TODO:
                        stages: ShaderStages::all(),        // TODO:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::new(device, descriptors.into_iter())
            }
        }

        pipeline_layout!{__inner__ ($num+1) $($rest)*}
    };

    (__inner__ ($num:expr)) => {};
}

pub unsafe trait ValidParameter<Target> {
    fn write(&self, binding: u32) -> DescriptorWrite;
}

pub unsafe trait DescriptorMarker {
    fn descriptor_type() -> DescriptorType;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::UniformBuffer
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<UniformBuffer<T>> for &'a Arc<B>
    where B: TypedBuffer<Content = T>
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::uniform_buffer(binding, *self)
    }
}

pub struct CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::CombinedImageSampler
    }
}

unsafe impl<'a, I> ValidParameter<CombinedImageSampler> for (&'a Arc<Sampler>, &'a Arc<I>)
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::combined_image_sampler(binding, self.0, self.1)
    }
}
<commit_msg>Add small test for the pipeline_layout! macro<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use buffer::TypedBuffer;
use descriptor::descriptor::DescriptorType;
use descriptor::descriptor::DescriptorWrite;
use image::ImageView;
use sampler::Sampler;

/// Call this macro with the layout of a pipeline to generate some helper structs that wrap around
/// vulkano's unsafe APIs.
// TODO: more docs
#[macro_export]
macro_rules! pipeline_layout {
    ($($name:ident: { $($field:ident: $ty:ty),* }),*) => {
        use std::sync::Arc;
        use std::vec::IntoIter as VecIntoIter;
        use $crate::OomError;
        use $crate::device::Device;
        use $crate::descriptor::descriptor::DescriptorDesc;
        use $crate::descriptor::pipeline_layout::PipelineLayout;
        use $crate::descriptor::pipeline_layout::PipelineLayoutDesc;
        use $crate::descriptor::pipeline_layout::UnsafePipelineLayout;

        pub struct CustomPipeline {
            inner: UnsafePipelineLayout
        }

        impl CustomPipeline {
            #[allow(unsafe_code)]
            pub fn new(device: &Arc<Device>) -> Result<Arc<CustomPipeline>, OomError> {
                let layouts = vec![
                    $(
                        try!($name::build_set_layout(device))
                    ),*
                ];

                let inner = unsafe {
                    try!(UnsafePipelineLayout::new(device, layouts.iter()))
                };

                Ok(Arc::new(CustomPipeline {
                    inner: inner
                }))
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayout for CustomPipeline {
            #[inline]
            fn inner_pipeline_layout(&self) -> &UnsafePipelineLayout {
                &self.inner
            }
        }

        #[allow(unsafe_code)]
        unsafe impl PipelineLayoutDesc for CustomPipeline {
            type SetsIter = VecIntoIter<Self::DescIter>;
            type DescIter = VecIntoIter<DescriptorDesc>;

            fn descriptors_desc(&self) -> Self::SetsIter {
                // FIXME:
                vec![].into_iter()
            }
        }

        pipeline_layout!{__inner__ (0) $($name: {$($field: $ty),*}),*}
    };

    (__inner__ ($num:expr) $name:ident: { $($field:ident: $ty:ty),* } $($rest:tt)*) => {
        pub mod $name {
            #![allow(unused_imports)]

            use std::sync::Arc;
            use super::CustomPipeline;
            use $crate::OomError;
            use $crate::device::Device;
            use $crate::descriptor::descriptor::DescriptorDesc;
            use $crate::descriptor::descriptor::DescriptorWrite;
            use $crate::descriptor::descriptor::ShaderStages;
            use $crate::descriptor::descriptor_set::DescriptorPool;
            use $crate::descriptor::descriptor_set::DescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSet;
            use $crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
            use $crate::descriptor::pipeline_layout::PipelineLayout;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::CombinedImageSampler;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::DescriptorMarker;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::UniformBuffer;
            use $crate::descriptor::pipeline_layout::custom_pipeline_macro::ValidParameter;

            // This constant is part of the API, but Rust sees it as dead code.
            #[allow(dead_code)]
            pub const SET_NUM: u32 = $num;

            #[allow(non_camel_case_types)]
            pub struct Descriptors<$($field),*> {
                $(
                    pub $field: $field
                ),*
            }

            #[allow(non_camel_case_types)]
            #[allow(unused_assignments)]
            impl<$($field: ValidParameter<$ty>),*> Descriptors<$($field),*> {
                pub fn writes(&self) -> Vec<DescriptorWrite> {
                    let mut writes = Vec::new();
                    let mut binding = 0;
                    $(
                        writes.push(self.$field.write(binding));
                        binding += 1;
                    )*
                    writes
                }
            }

            pub struct Set {
                inner: UnsafeDescriptorSet
            }

            impl Set {
                #[inline]
                #[allow(non_camel_case_types)]
                pub fn new<$($field: ValidParameter<$ty>),*>
                          (pool: &Arc<DescriptorPool>, layout: &Arc<CustomPipeline>,
                           descriptors: &Descriptors<$($field)*>)
                           -> Result<Arc<Set>, OomError>
                {
                    #![allow(unsafe_code)]
                    unsafe {
                        let layout = layout.inner_pipeline_layout().descriptor_set_layout($num).unwrap();
                        let mut set = try!(UnsafeDescriptorSet::uninitialized(pool, layout));
                        set.write(descriptors.writes());
                        Ok(Arc::new(Set { inner: set }))
                    }
                }
            }

            #[allow(unsafe_code)]
            unsafe impl DescriptorSet for Set {
                #[inline]
                fn inner_descriptor_set(&self) -> &UnsafeDescriptorSet {
                    &self.inner
                }
            }

            #[allow(unused_assignments)]
            pub fn build_set_layout(device: &Arc<Device>)
                                    -> Result<Arc<UnsafeDescriptorSetLayout>, OomError>
            {
                let mut descriptors = Vec::new();
                let mut binding = 0;

                $(
                    descriptors.push(DescriptorDesc {
                        binding: binding,
                        ty: <$ty as DescriptorMarker>::descriptor_type(),
                        array_count: 1,                     // TODO:
                        stages: ShaderStages::all(),        // TODO:
                    });

                    binding += 1;
                )*

                UnsafeDescriptorSetLayout::new(device, descriptors.into_iter())
            }
        }

        pipeline_layout!{__inner__ ($num+1) $($rest)*}
    };

    (__inner__ ($num:expr)) => {};
}

pub unsafe trait ValidParameter<Target> {
    fn write(&self, binding: u32) -> DescriptorWrite;
}

pub unsafe trait DescriptorMarker {
    fn descriptor_type() -> DescriptorType;
}

pub struct UniformBuffer<T: ?Sized>(PhantomData<T>);
unsafe impl<T: ?Sized> DescriptorMarker for UniformBuffer<T> {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::UniformBuffer
    }
}

unsafe impl<'a, B, T: ?Sized + 'static> ValidParameter<UniformBuffer<T>> for &'a Arc<B>
    where B: TypedBuffer<Content = T>
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::uniform_buffer(binding, *self)
    }
}

pub struct CombinedImageSampler;
unsafe impl DescriptorMarker for CombinedImageSampler {
    #[inline]
    fn descriptor_type() -> DescriptorType {
        DescriptorType::CombinedImageSampler
    }
}

unsafe impl<'a, I> ValidParameter<CombinedImageSampler> for (&'a Arc<Sampler>, &'a Arc<I>)
    where I: ImageView + 'static
{
    #[inline]
    fn write(&self, binding: u32) -> DescriptorWrite {
        DescriptorWrite::combined_image_sampler(binding, self.0, self.1)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn no_warning() {
        #![deny(warnings)]
        mod layout {
            pipeline_layout! {
                set0: {
                    field1: UniformBuffer<[u8]>
                }
            }
        }
    }
}
<|endoftext|>