<commit_before>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 *
 * Coming:
 * equal?, eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args.len() {
                0 => $identity,
                1 => vec::foldl($identity, args, |x, y| {x.$function(y)}),
                _ => vec::foldl(args.head(), args.tail(), |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<commit_msg>Add equal? builtin<commit_after>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 *
 * Coming:
 * equal?, eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args.len() {
                0 => $identity,
                1 => vec::foldl($identity, args, |x, y| {x.$function(y)}),
                _ => vec::foldl(args.head(), args.tail(), |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'equal?' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<|endoftext|>


<commit_before>use clap::Arg;
use clap::App;
use clap::{ArgMatches};
use loader;
use rusqlite::Connection;

pub fn cli_clap(conn: &Connection) -> ArgMatches{

    let application = App::new("whenenv")
                        .about("Parses an input file to do awesome things")
                        .version("0.0.1")
                        .author("Owen Synge <osynge@googlemail.com>")
                        .arg(Arg::with_name("verbose")
                                    .help("Increase log output.")
                                    .short("v")
                                    .multiple(true)
                                    .long("verbose"))
                        .arg(Arg::with_name("quiet")
                                    .help("Decrease log output.")
                                    .short("q")
                                    .multiple(true)
                                    .long("quiet"))
                        .arg(Arg::with_name("env")
                                    .short("e")
                                    .long("env")
                                    .value_name("ENVIROMENT_VARIABLE")
                                    .help("Which enviroment variables to process")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-jobs")
                                    .long("dir-jobs")
                                    .value_name("DIR_JOB")
                                    .help("directory storing json jobs.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-sh")
                                    .long("dir-sh")
                                    .value_name("DIR_SHELL")
                                    .help("directory storing jobs shell scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("config")
                                    .short("c")
                                    .long("config")
                                    .value_name("FILE")
                                    .help("Sets a custom config file")
                                    .takes_value(true));
    let matches = application.get_matches();

    // We can find out whether or not debugging was turned on
    if matches.is_present("debug") {
        println!("Debugging is turned on");
    }

    // If we wanted to some custom initialization based off some configuration file provided
    // by the user, we could get the file (A string of the file)
    if let Some(ref file) = matches.value_of("config") {
        println!("Using config file: {}", file);
    }
    if let Some(ref env) = matches.value_of("env") {
        println!("Using config file: {}", env);
    }
    // Continued program logic goes here...
    //loader::deligate(conn, matches);
    return matches;
}
<commit_msg>Make unused type simpler<commit_after>use clap::Arg;
use clap::App;
use clap::{ArgMatches};
use loader;
use rusqlite::Connection;

pub fn cli_clap(number: &u32) -> ArgMatches{

    let application = App::new("whenenv")
                        .about("Parses an input file to do awesome things")
                        .version("0.0.1")
                        .author("Owen Synge <osynge@googlemail.com>")
                        .arg(Arg::with_name("verbose")
                                    .help("Increase log output.")
                                    .short("v")
                                    .multiple(true)
                                    .long("verbose"))
                        .arg(Arg::with_name("quiet")
                                    .help("Decrease log output.")
                                    .short("q")
                                    .multiple(true)
                                    .long("quiet"))
                        .arg(Arg::with_name("env")
                                    .short("e")
                                    .long("env")
                                    .value_name("ENVIROMENT_VARIABLE")
                                    .help("Which enviroment variables to process")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-jobs")
                                    .long("dir-jobs")
                                    .value_name("DIR_JOB")
                                    .help("directory storing json jobs.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-sh")
                                    .long("dir-sh")
                                    .value_name("DIR_SHELL")
                                    .help("directory storing jobs shell scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("dir-py")
                                    .long("dir-py")
                                    .value_name("DIR_PYTHON")
                                    .help("directory storing jobs python scripts.")
                                    .multiple(true)
                                    .takes_value(true))
                        .arg(Arg::with_name("config")
                                    .short("c")
                                    .long("config")
                                    .value_name("FILE")
                                    .help("Sets a custom config file")
                                    .takes_value(true));
    let matches = application.get_matches();

    // We can find out whether or not debugging was turned on
    if matches.is_present("debug") {
        println!("Debugging is turned on");
    }

    // If we wanted to some custom initialization based off some configuration file provided
    // by the user, we could get the file (A string of the file)
    if let Some(ref file) = matches.value_of("config") {
        println!("Using config file: {}", file);
    }
    if let Some(ref env) = matches.value_of("env") {
        println!("Using config file: {}", env);
    }
    // Continued program logic goes here...
    //loader::deligate(conn, matches);
    return matches;
}
<|endoftext|>


<commit_before>use crate::convert::TryFrom;
use crate::ptr;
use crate::sync::atomic::{
    AtomicI8, AtomicUsize,
    Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::{c, dur2timeout};
use crate::time::Duration;

pub struct Parker {
    state: AtomicI8,
}

const PARKED: i8 = -1;
const EMPTY: i8 = 0;
const NOTIFIED: i8 = 1;

// Notes about memory ordering:
//
// Memory ordering is only relevant for the relative ordering of operations
// between different variables. Even Ordering::Relaxed guarantees a
// monotonic/consistent order when looking at just a single atomic variable.
//
// So, since this parker is just a single atomic variable, we only need to look
// at the ordering guarantees we need to provide to the 'outside world'.
//
// The only memory ordering guarantee that parking and unparking provide, is
// that things which happened before unpark() are visible on the thread
// returning from park() afterwards. Otherwise, it was effectively unparked
// before unpark() was called while still consuming the 'token'.
//
// In other words, unpark() needs to synchronize with the part of park() that
// consumes the token and returns.
//
// This is done with a release-acquire synchronization, by using
// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
// Ordering::Acquire when checking for this state in park().
impl Parker {
    pub fn new() -> Self {
        Self { state: AtomicI8::new(EMPTY) }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park(&self) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        loop {
            // Wait for something to happen.
            if c::WaitOnAddress::is_available() {
                c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
            } else {
                c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
            }
            // Change NOTIFIED=>EMPTY and return in that case.
            if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
                return;
            } else {
                // Spurious wake up. We loop to try again.
            }
        }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park_timeout(&self, timeout: Duration) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            // Wait for something to happen, assuming it's still set to PARKED.
            c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
            // Change NOTIFIED=>EMPTY and return in that case.
            if self.state.swap(EMPTY, Acquire) == NOTIFIED {
                return;
            } else {
                // Timeout or spurious wake up.
                // We return either way, because we can't easily tell if it was the
                // timeout or not.
            }
        } else {
            // Need to wait for unpark() using NtWaitForKeyedEvent.
            let handle = keyed_event_handle();

            // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative values
            // to indicate the monotonic clock.
            let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
                Ok(t) => -t,
                Err(_) => i64::MIN,
            };

            // Wait for unpark() to produce this event.
            if c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS {
                // Awoken by another thread.
                self.state.swap(EMPTY, Acquire);
            } else {
                // Not awoken by another thread (spurious or timeout).
                if self.state.swap(EMPTY, Acquire) == NOTIFIED {
                    // If the state is NOTIFIED, we *just* missed an unpark(),
                    // which is now waiting for us to wait for it.
                    // Wait for it to consume the event and unblock it.
                    c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
                }
            }
        }
    }

    pub fn unpark(&self) {
        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
        // wake the thread in the first case.
        //
        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
        // purpose, to make sure every unpark() has a release-acquire ordering
        // with park().
        if self.state.swap(NOTIFIED, Release) == PARKED {
            if c::WakeByAddressSingle::is_available() {
                unsafe {
                    c::WakeByAddressSingle(self.ptr());
                }
            } else {
                // If we run NtReleaseKeyedEvent before the waiting thread runs
                // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
                // If the waiting thread wakes up before we run NtReleaseKeyedEvent
                // (e.g. due to a timeout), this blocks until we do wake up a thread.
                // To prevent this thread from blocking indefinitely in that case,
                // park_impl() will, after seeing the state set to NOTIFIED after
                // waking up, call NtWaitForKeyedEvent again to unblock us.
                unsafe {
                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
                }
            }
        }
    }

    fn ptr(&self) -> c::LPVOID {
        &self.state as *const _ as c::LPVOID
    }
}

fn keyed_event_handle() -> c::HANDLE {
    const INVALID: usize = !0;
    static HANDLE: AtomicUsize = AtomicUsize::new(INVALID);
    match HANDLE.load(Relaxed) {
        INVALID => {
            let mut handle = c::INVALID_HANDLE_VALUE;
            unsafe {
                match c::NtCreateKeyedEvent(
                    &mut handle,
                    c::GENERIC_READ | c::GENERIC_WRITE,
                    ptr::null_mut(),
                    0,
                ) {
                    c::STATUS_SUCCESS => {}
                    r => panic!("Unable to create keyed event handle: error {}", r),
                }
            }
            match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
                Ok(_) => handle,
                Err(h) => {
                    // Lost the race to another thread initializing HANDLE before we did.
                    // Closing our handle and using theirs instead.
                    unsafe {
                        c::CloseHandle(handle);
                    }
                    h as c::HANDLE
                }
            }
        }
        handle => handle as c::HANDLE,
    }
}
<commit_msg>Improve windows thread parker.<commit_after>use crate::convert::TryFrom;
use crate::ptr;
use crate::sync::atomic::{
    AtomicI8, AtomicUsize,
    Ordering::{Acquire, Relaxed, Release},
};
use crate::sys::{c, dur2timeout};
use crate::time::Duration;

pub struct Parker {
    state: AtomicI8,
}

const PARKED: i8 = -1;
const EMPTY: i8 = 0;
const NOTIFIED: i8 = 1;

// Notes about memory ordering:
//
// Memory ordering is only relevant for the relative ordering of operations
// between different variables. Even Ordering::Relaxed guarantees a
// monotonic/consistent order when looking at just a single atomic variable.
//
// So, since this parker is just a single atomic variable, we only need to look
// at the ordering guarantees we need to provide to the 'outside world'.
//
// The only memory ordering guarantee that parking and unparking provide, is
// that things which happened before unpark() are visible on the thread
// returning from park() afterwards. Otherwise, it was effectively unparked
// before unpark() was called while still consuming the 'token'.
//
// In other words, unpark() needs to synchronize with the part of park() that
// consumes the token and returns.
//
// This is done with a release-acquire synchronization, by using
// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using
// Ordering::Acquire when checking for this state in park().
impl Parker {
    pub fn new() -> Self {
        Self { state: AtomicI8::new(EMPTY) }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park(&self) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            loop {
                // Wait for something to happen, assuming it's still set to PARKED.
                c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, c::INFINITE);
                // Change NOTIFIED=>EMPTY but leave PARKED alone.
                if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED {
                    // Actually woken up by unpark().
                    return;
                } else {
                    // Spurious wake up. We loop to try again.
                }
            }
        } else {
            // Wait for unpark() to produce this event.
            c::NtWaitForKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            // Note that we don't just write EMPTY, but use swap() to also
            // include a acquire-ordered read to synchronize with unpark()'s
            // release-ordered write.
            self.state.swap(EMPTY, Acquire);
        }
    }

    // Assumes this is only called by the thread that owns the Parker,
    // which means that `self.state != PARKED`.
    pub unsafe fn park_timeout(&self, timeout: Duration) {
        // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the
        // first case.
        if self.state.fetch_sub(1, Acquire) == NOTIFIED {
            return;
        }

        if c::WaitOnAddress::is_available() {
            // Wait for something to happen, assuming it's still set to PARKED.
            c::WaitOnAddress(self.ptr(), &PARKED as *const _ as c::LPVOID, 1, dur2timeout(timeout));
            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            // Note that we don't just write EMPTY, but use swap() to also
            // include a acquire-ordered read to synchronize with unpark()'s
            // release-ordered write.
            if self.state.swap(EMPTY, Acquire) == NOTIFIED {
                // Actually woken up by unpark().
            } else {
                // Timeout or spurious wake up.
                // We return either way, because we can't easily tell if it was the
                // timeout or not.
            }
        } else {
            // Need to wait for unpark() using NtWaitForKeyedEvent.
            let handle = keyed_event_handle();

            // NtWaitForKeyedEvent uses a unit of 100ns, and uses negative values
            // to indicate the monotonic clock.
            let mut timeout = match i64::try_from((timeout.as_nanos() + 99) / 100) {
                Ok(t) => -t,
                Err(_) => i64::MIN,
            };

            // Wait for unpark() to produce this event.
            let unparked = c::NtWaitForKeyedEvent(handle, self.ptr(), 0, &mut timeout) == c::STATUS_SUCCESS;

            // Set the state back to EMPTY (from either PARKED or NOTIFIED).
            let prev_state = self.state.swap(EMPTY, Acquire);

            if !unparked && prev_state == NOTIFIED {
                // We were awoken by a timeout, not by unpark(), but the state
                // was set to NOTIFIED, which means we *just* missed an
                // unpark(), which is now blocked on us to wait for it.
                // Wait for it to consume the event and unblock that thread.
                c::NtWaitForKeyedEvent(handle, self.ptr(), 0, ptr::null_mut());
            }
        }
    }

    pub fn unpark(&self) {
        // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and
        // wake the thread in the first case.
        //
        // Note that even NOTIFIED=>NOTIFIED results in a write. This is on
        // purpose, to make sure every unpark() has a release-acquire ordering
        // with park().
        if self.state.swap(NOTIFIED, Release) == PARKED {
            if c::WakeByAddressSingle::is_available() {
                unsafe {
                    c::WakeByAddressSingle(self.ptr());
                }
            } else {
                // If we run NtReleaseKeyedEvent before the waiting thread runs
                // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
                // If the waiting thread wakes up before we run NtReleaseKeyedEvent
                // (e.g. due to a timeout), this blocks until we do wake up a thread.
                // To prevent this thread from blocking indefinitely in that case,
                // park_impl() will, after seeing the state set to NOTIFIED after
                // waking up, call NtWaitForKeyedEvent again to unblock us.
                unsafe {
                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
                }
            }
        }
    }

    fn ptr(&self) -> c::LPVOID {
        &self.state as *const _ as c::LPVOID
    }
}

fn keyed_event_handle() -> c::HANDLE {
    const INVALID: usize = !0;
    static HANDLE: AtomicUsize = AtomicUsize::new(INVALID);
    match HANDLE.load(Relaxed) {
        INVALID => {
            let mut handle = c::INVALID_HANDLE_VALUE;
            unsafe {
                match c::NtCreateKeyedEvent(
                    &mut handle,
                    c::GENERIC_READ | c::GENERIC_WRITE,
                    ptr::null_mut(),
                    0,
                ) {
                    c::STATUS_SUCCESS => {}
                    r => panic!("Unable to create keyed event handle: error {}", r),
                }
            }
            match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) {
                Ok(_) => handle,
                Err(h) => {
                    // Lost the race to another thread initializing HANDLE before we did.
                    // Closing our handle and using theirs instead.
                    unsafe {
                        c::CloseHandle(handle);
                    }
                    h as c::HANDLE
                }
            }
        }
        handle => handle as c::HANDLE,
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, quote, rustc_private, box_patterns)]
extern crate rustc_plugin;
#[macro_use] pub extern crate syntax;
#[macro_use] extern crate syntax_pos;
extern crate rustc_errors as errors;

extern crate peg;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::tokenstream::TokenTree;
use syntax::parse;
use syntax::parse::token;
use syntax::symbol::Symbol;
use syntax::fold::Folder;
use syntax::util::small_vector::SmallVector;
use rustc_plugin::Registry;
use std::io::Read;
use std::fs::File;
use std::path::Path;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            Symbol::intern("peg"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_str), None, false));

    reg.register_syntax_extension(
            Symbol::intern("peg_file"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_file), None, false));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, &tts) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, &tts) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(&cx.codemap().span_to_filename(sp)).parent().unwrap().join(&fname);

    let mut source = String::new();
    if let Err(e) = File::open(&path).map(|mut f| f.read_to_string(&mut source)) {
        cx.span_err(sp, &e.to_string());
        return DummyResult::any(sp);
    }

    cx.codemap().new_filemap(format!("{}", path.display()), None, "".to_string());

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let code = match peg::compile(&source) {
        Ok(code) => code,
        Err(e) => {
          cx.span_err(sp, &format!("{}", e));
          return DummyResult::any(sp)
        }
    };

    let mut p = parse::new_parser_from_source_str(&cx.parse_sess, "<peg expansion>".into(), code);
    let tts = panictry!(p.parse_all_token_trees());

    let module = quote_item! { cx,
        mod $ident {
            $tts
        }
    }.unwrap();

    MacEager::items(SmallVector::one(module))
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(panictry!(parser.parse_expr()));
    match arg.node {
        ast::ExprKind::Lit(ref spanned) => {
            match spanned.node {
                ast::LitKind::Str(ref n, _) => {
                    if !parser.eat(&token::Eof) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, &err);
    None
}
<commit_msg>rust: Fix peg-syntax-ext for filemap API change<commit_after>#![feature(plugin_registrar, quote, rustc_private, box_patterns)]
extern crate rustc_plugin;
#[macro_use] pub extern crate syntax;
extern crate rustc_errors as errors;

extern crate peg;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{ExtCtxt, MacResult, MacEager, DummyResult};
use syntax::tokenstream::TokenTree;
use syntax::parse;
use syntax::parse::token;
use syntax::symbol::Symbol;
use syntax::fold::Folder;
use syntax::util::small_vector::SmallVector;
use rustc_plugin::Registry;
use std::io::Read;
use std::fs::File;
use std::path::Path;

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
            Symbol::intern("peg"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_str), None, false));

    reg.register_syntax_extension(
            Symbol::intern("peg_file"),
            syntax::ext::base::IdentTT(Box::new(expand_peg_file), None, false));
}

fn expand_peg_str<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<TokenTree>) -> Box<MacResult + 's> {
    let source = match parse_arg(cx, &tts) {
        Some(source) => source,
        None => return DummyResult::any(sp),
    };

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg_file<'s>(cx: &'s mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, tts: Vec<TokenTree>) -> Box<MacResult + 's> {
    let fname = match parse_arg(cx, &tts) {
        Some(fname) => fname,
        None => return DummyResult::any(sp),
    };

    let path = Path::new(&cx.codemap().span_to_filename(sp)).parent().unwrap().join(&fname);

    let mut source = String::new();
    if let Err(e) = File::open(&path).map(|mut f| f.read_to_string(&mut source)) {
        cx.span_err(sp, &e.to_string());
        return DummyResult::any(sp);
    }

    cx.codemap().new_filemap(format!("{}", path.display()), "".to_string());

    expand_peg(cx, sp, ident, &source)
}

fn expand_peg(cx: &mut ExtCtxt, sp: codemap::Span, ident: ast::Ident, source: &str) -> Box<MacResult + 'static> {
    let code = match peg::compile(&source) {
        Ok(code) => code,
        Err(e) => {
          cx.span_err(sp, &format!("{}", e));
          return DummyResult::any(sp)
        }
    };

    let mut p = parse::new_parser_from_source_str(&cx.parse_sess, "<peg expansion>".into(), code);
    let tts = panictry!(p.parse_all_token_trees());

    let module = quote_item! { cx,
        mod $ident {
            $tts
        }
    }.unwrap();

    MacEager::items(SmallVector::one(module))
}

fn parse_arg(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<String> {
    use syntax::print::pprust;

    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec());
    // The `expand_expr` method is called so that any macro calls in the
    // parsed expression are expanded.
    let arg = cx.expander().fold_expr(panictry!(parser.parse_expr()));
    match arg.node {
        ast::ExprKind::Lit(ref spanned) => {
            match spanned.node {
                ast::LitKind::Str(ref n, _) => {
                    if !parser.eat(&token::Eof) {
                        cx.span_err(parser.span,
                                    "expected only one string literal");
                        return None
                    }
                    return Some(n.to_string())
                }
                _ => {}
            }
        }
        _ => {}
    }

    let err = format!("expected string literal but got `{}`",
                      pprust::expr_to_string(&*arg));
    cx.span_err(parser.span, &err);
    None
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

// force-host

#![crate_type="dylib"]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use syntax::feature_gate::Features;
use syntax::parse::token::{NtExpr, NtPat};
use syntax::ast::{Ident, Pat, NodeId};
use syntax::tokenstream::{TokenTree};
use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::ext::build::AstBuilder;
use syntax::ext::tt::quoted;
use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use syntax::ext::tt::macro_parser::{Success, Failure, Error};
use syntax::ext::tt::macro_parser::parse_failure_msg;
use syntax::ptr::P;
use syntax_pos::{Span, edition::Edition};
use rustc_plugin::Registry;

fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
        -> Box<MacResult + 'static> {

    let mbe_matcher = quote_tokens!(cx, $$matched:expr, $$($$pat:pat)|+);
    let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(),
                                    true,
                                    cx.parse_sess,
                                    &Features::new(),
                                    &[],
                                    Edition::Edition2015,
                                    // not used...
                                    NodeId::from_u32(0));
    let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) {
        Success(map) => map,
        Failure(_, tok) => {
            panic!("expected Success, but got Failure: {}", parse_failure_msg(tok));
        }
        Error(_, s) => {
            panic!("expected Success, but got Error: {}", s);
        }
    };

    let matched_nt = match *map[&Ident::from_str("matched")] {
        MatchedNonterminal(ref nt) => nt.clone(),
        _ => unreachable!(),
    };

    let mac_expr = match (&*matched_nt, &*map[&Ident::from_str("pat")]) {
        (&NtExpr(ref matched_expr), &MatchedSeq(ref pats, seq_sp)) => {
            let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt| {
                match *pat_nt {
                    MatchedNonterminal(ref nt) => match **nt {
                        NtPat(ref pat) => pat.clone(),
                        _ => unreachable!(),
                    },
                    _ => unreachable!(),
                }
            }).collect();
            let span = seq_sp.entire();
            let arm = cx.arm(span, pats, cx.expr_bool(span, true));

            quote_expr!(cx,
                match $matched_expr {
                    $arm
                    _ => false
                }
            )
        }
        _ => unreachable!()
    };

    MacEager::expr(mac_expr)
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("matches", expand_mbe_matches);
}
<commit_msg>Fix proc-macro test after internal API change<commit_after>// Copyright 2015 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.

// force-host

#![crate_type="dylib"]
#![feature(plugin_registrar, quote, rustc_private)]

extern crate syntax;
extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;

use syntax::feature_gate::Features;
use syntax::parse::token::{NtExpr, NtPat};
use syntax::ast::{Ident, Pat, NodeId};
use syntax::tokenstream::{TokenTree};
use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
use syntax::ext::build::AstBuilder;
use syntax::ext::tt::quoted;
use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
use syntax::ext::tt::macro_parser::{Success, Failure, Error};
use syntax::ext::tt::macro_parser::parse_failure_msg;
use syntax::ptr::P;
use syntax_pos::{Span, edition::Edition};
use rustc_plugin::Registry;

fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
        -> Box<MacResult + 'static> {

    let mbe_matcher = quote_tokens!(cx, $$matched:expr, $$($$pat:pat)|+);
    let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(),
                                    true,
                                    cx.parse_sess,
                                    &Features::new(),
                                    &[],
                                    Edition::Edition2015,
                                    // not used...
                                    NodeId::from_u32(0));
    let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) {
        Success(map) => map,
        Failure(_, tok, msg) => {
            panic!("expected Success, but got Failure: {} - {}", parse_failure_msg(tok), msg);
        }
        Error(_, s) => {
            panic!("expected Success, but got Error: {}", s);
        }
    };

    let matched_nt = match *map[&Ident::from_str("matched")] {
        MatchedNonterminal(ref nt) => nt.clone(),
        _ => unreachable!(),
    };

    let mac_expr = match (&*matched_nt, &*map[&Ident::from_str("pat")]) {
        (&NtExpr(ref matched_expr), &MatchedSeq(ref pats, seq_sp)) => {
            let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt| {
                match *pat_nt {
                    MatchedNonterminal(ref nt) => match **nt {
                        NtPat(ref pat) => pat.clone(),
                        _ => unreachable!(),
                    },
                    _ => unreachable!(),
                }
            }).collect();
            let span = seq_sp.entire();
            let arm = cx.arm(span, pats, cx.expr_bool(span, true));

            quote_expr!(cx,
                match $matched_expr {
                    $arm
                    _ => false
                }
            )
        }
        _ => unreachable!()
    };

    MacEager::expr(mac_expr)
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("matches", expand_mbe_matches);
}
<|endoftext|>


<commit_before><commit_msg>[vm] remove out of date preload_cache<commit_after><|endoftext|>


<commit_before>#![cfg(feature = "bytes")]

use std::fmt;
use std::ops::Deref;
use std::str;

use bytes::Bytes;

use crate::clear::Clear;

/// Thin wrapper around `Bytes` which guarantees that bytes are valid UTF-8 string.
/// Should be API-compatible to `String`.
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Chars(Bytes);

impl Chars {
    /// New empty object.
    pub fn new() -> Chars {
        Chars(Bytes::new())
    }

    /// Try convert from `Bytes`
    pub fn from_bytes(bytes: Bytes) -> Result<Chars, str::Utf8Error> {
        str::from_utf8(&bytes)?;

        Ok(Chars(bytes))
    }

    /// Len in bytes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl<'a> From<&'a str> for Chars {
    fn from(src: &'a str) -> Chars {
        Chars(Bytes::from(src))
    }
}

impl From<String> for Chars {
    fn from(src: String) -> Chars {
        Chars(Bytes::from(src))
    }
}

impl Into<String> for Chars {
    fn into(self) -> String {
        unsafe {
            // TODO: copies here
            String::from_utf8_unchecked(self.0.as_ref().to_owned())
        }
    }
}

impl Default for Chars {
    fn default() -> Self {
        Chars::new()
    }
}

impl Deref for Chars {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl Clear for Chars {
    fn clear(&mut self) {
        self.0.clear();
    }
}

impl fmt::Display for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl fmt::Debug for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

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

    #[test]
    fn test_display_and_debug() {
        let s = "test";
        let string: String = s.into();
        let chars: Chars = s.into();

        assert_eq!(format!("{}", string), format!("{}", chars));
        assert_eq!(format!("{:?}", string), format!("{:?}", chars));
    }
}
<commit_msg>Missing doc<commit_after>#![cfg(feature = "bytes")]

use std::fmt;
use std::ops::Deref;
use std::str;

use bytes::Bytes;

use crate::clear::Clear;

/// Thin wrapper around `Bytes` which guarantees that bytes are valid UTF-8 string.
/// Should be API-compatible to `String`.
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Chars(Bytes);

impl Chars {
    /// New empty object.
    pub fn new() -> Chars {
        Chars(Bytes::new())
    }

    /// Try convert from `Bytes`
    pub fn from_bytes(bytes: Bytes) -> Result<Chars, str::Utf8Error> {
        str::from_utf8(&bytes)?;

        Ok(Chars(bytes))
    }

    /// Len in bytes.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Self-explanatory
    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}

impl<'a> From<&'a str> for Chars {
    fn from(src: &'a str) -> Chars {
        Chars(Bytes::from(src))
    }
}

impl From<String> for Chars {
    fn from(src: String) -> Chars {
        Chars(Bytes::from(src))
    }
}

impl Into<String> for Chars {
    fn into(self) -> String {
        unsafe {
            // TODO: copies here
            String::from_utf8_unchecked(self.0.as_ref().to_owned())
        }
    }
}

impl Default for Chars {
    fn default() -> Self {
        Chars::new()
    }
}

impl Deref for Chars {
    type Target = str;

    fn deref(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.0) }
    }
}

impl Clear for Chars {
    fn clear(&mut self) {
        self.0.clear();
    }
}

impl fmt::Display for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl fmt::Debug for Chars {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, f)
    }
}

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

    #[test]
    fn test_display_and_debug() {
        let s = "test";
        let string: String = s.into();
        let chars: Chars = s.into();

        assert_eq!(format!("{}", string), format!("{}", chars));
        assert_eq!(format!("{:?}", string), format!("{:?}", chars));
    }
}
<|endoftext|>


<commit_before>extern crate phf;

#[cfg(feature = "flate2")]
extern crate flate2;

use std::borrow::{Borrow, Cow};
use std::io::{self, BufReader, Cursor, Error, ErrorKind, Read};
use std::fs::File;
use std::sync::atomic::{AtomicBool, Ordering};

#[cfg(feature = "flate2")]
use flate2::bufread::GzDecoder;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Compression {
    None,
    Gzip
}

/// Runtime access to the included files
pub struct Files {
    // Do not access these fields, they are only public to allow for code generation!
    #[doc(hidden)]
    pub files: phf::Map<&'static str, (Compression, &'static [u8])>,
    #[doc(hidden)]
    pub passthrough: AtomicBool
}

#[cfg(windows)]
fn as_key(path: &str) -> Cow<str> {
    Cow::Owned(path.replace("\\", "/"))
}

#[cfg(not(windows))]
fn as_key(path: &str) -> Cow<str> {
    Cow::Borrowed(path)
}

impl Files {
    pub fn set_passthrough(&self, enabled: bool) {
        self.passthrough.store(enabled, Ordering::Relaxed);
    }

    pub fn is_available(&self, path: &str) -> bool {
        self.files.contains_key(path)
    }

    /// Returns an iterator over all available file names.  Does not
    /// decompress any compressed data.
    pub fn file_names(&'static self) -> FileNames {
        FileNames { iter: self.files.keys() }
    }

    pub fn get(&self, path: &str) -> io::Result<Cow<'static, [u8]>> {
        match self.get_raw(path) {
            Ok((Compression::None, data)) => Ok(data),
            #[cfg(feature = "flate2")]
            Ok((Compression::Gzip, compressed)) => {
                let mut r = GzDecoder::new(Cursor::new(compressed));
                let mut v = Vec::new();
                r.read_to_end(&mut v)?;
                Ok(Cow::Owned(v))
            },
            #[cfg(not(feature = "flate2"))]
            Ok((Compression::Gzip, _)) => panic!("Feature 'flate2' not enabled"),

            Err(e) => Err(e)
        }
    }

    pub fn get_raw(&self, path: &str) -> io::Result<(Compression, Cow<'static, [u8]>)> {
        if self.passthrough.load(Ordering::Relaxed) {
            let mut r = BufReader::new(File::open(path)?);
            let mut v = Vec::new();
            r.read_to_end(&mut v)?;
            return Ok((Compression::None, Cow::Owned(v)))
        }

        let key = as_key(path);

        self.files.get(key.borrow() as &str)
            .map( |(c,d)| (*c, Cow::Owned((*d).into())))
            .ok_or(Error::new(ErrorKind::NotFound, "Key not found"))
    }

    pub fn read(&self, path: &str) -> io::Result<Box<Read>> {
        if self.passthrough.load(Ordering::Relaxed) {
            return Ok(Box::new(BufReader::new(File::open(path)?)))
        }

        let key = as_key(path);
        match self.files.get(key.borrow() as &str) {
            Some(b) => {
                match b.0 {
                    Compression::None => Ok(Box::new(Cursor::new(b.1))),
                    #[cfg(feature = "flate2")]
                    Compression::Gzip => Ok(Box::new(GzDecoder::new(Cursor::new(b.1)))),
                    #[cfg(not(feature = "flate2"))]
                    Compression::Gzip => panic!("Feature 'flate2' not enabled"),
                }
            }
            None => Err(Error::new(ErrorKind::NotFound, "Key not found")),
        }
    }
}

/// Iterates over the file names available for `Files` object.
pub struct FileNames {
    // Our internal iterator.  We wrap this in a nice struct so our
    // caller doesn't need to know the details.
    iter: phf::map::Keys<'static, &'static str, (Compression, &'static [u8])>,
}

impl Iterator for FileNames {
    type Item = &'static str;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|s| *s)
    }
}
<commit_msg>make use of GZip a compile time error if flate2 is missing<commit_after>extern crate phf;

#[cfg(feature = "flate2")]
extern crate flate2;

use std::borrow::{Borrow, Cow};
use std::io::{self, BufReader, Cursor, Error, ErrorKind, Read};
use std::fs::File;
use std::sync::atomic::{AtomicBool, Ordering};

#[cfg(feature = "flate2")]
use flate2::bufread::GzDecoder;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Compression {
    None,
    #[cfg(feature = "flate2")]
    Gzip
}

/// Runtime access to the included files
pub struct Files {
    // Do not access these fields, they are only public to allow for code generation!
    #[doc(hidden)]
    pub files: phf::Map<&'static str, (Compression, &'static [u8])>,
    #[doc(hidden)]
    pub passthrough: AtomicBool
}

#[cfg(windows)]
fn as_key(path: &str) -> Cow<str> {
    Cow::Owned(path.replace("\\", "/"))
}

#[cfg(not(windows))]
fn as_key(path: &str) -> Cow<str> {
    Cow::Borrowed(path)
}

impl Files {
    pub fn set_passthrough(&self, enabled: bool) {
        self.passthrough.store(enabled, Ordering::Relaxed);
    }

    pub fn is_available(&self, path: &str) -> bool {
        self.files.contains_key(path)
    }

    /// Returns an iterator over all available file names.  Does not
    /// decompress any compressed data.
    pub fn file_names(&'static self) -> FileNames {
        FileNames { iter: self.files.keys() }
    }

    pub fn get(&self, path: &str) -> io::Result<Cow<'static, [u8]>> {
        match self.get_raw(path) {
            Ok((Compression::None, data)) => Ok(data),
            #[cfg(feature = "flate2")]
            Ok((Compression::Gzip, compressed)) => {
                let mut r = GzDecoder::new(Cursor::new(compressed));
                let mut v = Vec::new();
                r.read_to_end(&mut v)?;
                Ok(Cow::Owned(v))
            },
            #[cfg(not(feature = "flate2"))]
            Ok((Compression::Gzip, _)) => panic!("Feature 'flate2' not enabled"),

            Err(e) => Err(e)
        }
    }

    pub fn get_raw(&self, path: &str) -> io::Result<(Compression, Cow<'static, [u8]>)> {
        if self.passthrough.load(Ordering::Relaxed) {
            let mut r = BufReader::new(File::open(path)?);
            let mut v = Vec::new();
            r.read_to_end(&mut v)?;
            return Ok((Compression::None, Cow::Owned(v)))
        }

        let key = as_key(path);

        self.files.get(key.borrow() as &str)
            .map( |(c,d)| (*c, Cow::Owned((*d).into())))
            .ok_or(Error::new(ErrorKind::NotFound, "Key not found"))
    }

    pub fn read(&self, path: &str) -> io::Result<Box<Read>> {
        if self.passthrough.load(Ordering::Relaxed) {
            return Ok(Box::new(BufReader::new(File::open(path)?)))
        }

        let key = as_key(path);
        match self.files.get(key.borrow() as &str) {
            Some(b) => {
                match b.0 {
                    Compression::None => Ok(Box::new(Cursor::new(b.1))),
                    #[cfg(feature = "flate2")]
                    Compression::Gzip => Ok(Box::new(GzDecoder::new(Cursor::new(b.1)))),
                }
            }
            None => Err(Error::new(ErrorKind::NotFound, "Key not found")),
        }
    }
}

/// Iterates over the file names available for `Files` object.
pub struct FileNames {
    // Our internal iterator.  We wrap this in a nice struct so our
    // caller doesn't need to know the details.
    iter: phf::map::Keys<'static, &'static str, (Compression, &'static [u8])>,
}

impl Iterator for FileNames {
    type Item = &'static str;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|s| *s)
    }
}
<|endoftext|>


<commit_before>use cranelift_module::*;
use crate::prelude::*;
use crate::rustc::mir::interpret::{
    read_target_uint, AllocId, AllocType, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use crate::rustc::ty::Const;
use crate::rustc_mir::interpret::{EvalContext, Machine, Memory, MemoryKind, OpTy, PlaceTy};

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.module.pointer_type(), func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
            (),
        );
        let op = ecx.const_to_op(const_)?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack)?;
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory.get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable =
        if let crate::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
            true
        } else {
            !tcx.type_of(def_id)
                .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
        };
    module
        .declare_data(&*symbol_name, Linkage::Export, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx
        .bcx
        .ins()
        .global_value(fx.module.pointer_type(), local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, reloc) in alloc.relocations.iter() {
            let reloc_offset = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Function(instance) => {
                    let (func_name, sig) = crate::abi::get_function_name_and_sig(tcx, instance);
                    let func_id = module
                        .declare_function(&func_name, Linkage::Import, &sig)
                        .unwrap();
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(reloc_offset as u32, local_func_id);
                    continue;
                }
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryData = ();
    type MemoryKinds = ();
    const MUT_STATIC_KIND: Option<()> = None;

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: crate::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: DefId,
    ) -> EvalResult<'tcx, &'tcx Allocation> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }
}
<commit_msg>Rustup to rustc 1.31.0-nightly (96cafc53c 2018-10-09)<commit_after>use cranelift_module::*;
use crate::prelude::*;
use crate::rustc::mir::interpret::{
    read_target_uint, AllocId, AllocType, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use crate::rustc::ty::Const;
use crate::rustc_mir::interpret::{EvalContext, Machine, Memory, MemoryKind, OpTy, PlaceTy};

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        })).unwrap();

    let const_ = force_eval_const(fx, const_);
    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> &'tcx Const<'tcx> {
    match const_.val {
        ConstValue::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        _ => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.module.pointer_type(), func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
            (),
        );
        let op = ecx.const_to_op(const_)?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack)?;
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory.get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable =
        if let crate::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
            true
        } else {
            !tcx.type_of(def_id)
                .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
        };
    module
        .declare_data(&*symbol_name, Linkage::Export, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx
        .bcx
        .ins()
        .global_value(fx.module.pointer_type(), local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP), ());

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, reloc) in alloc.relocations.iter() {
            let reloc_offset = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocType::Function(instance) => {
                    let (func_name, sig) = crate::abi::get_function_name_and_sig(tcx, instance);
                    let func_id = module
                        .declare_function(&func_name, Linkage::Import, &sig)
                        .unwrap();
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(reloc_offset as u32, local_func_id);
                    continue;
                }
                AllocType::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocType::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryData = ();
    type MemoryKinds = ();
    const MUT_STATIC_KIND: Option<()> = None;
    const ENFORCE_VALIDITY: bool = true;

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: crate::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: DefId,
    ) -> EvalResult<'tcx, &'tcx Allocation> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }
}
<|endoftext|>


<commit_before>mod object;
mod pointer;

pub use self::{
    object::{Builtin, Closure, Data, Int, Object, Struct, Symbol, Text},
    pointer::Pointer,
};
use crate::builtin_functions::BuiltinFunction;
use itertools::Itertools;
use num_bigint::BigInt;
use std::{cmp::Ordering, collections::HashMap};

#[derive(Clone)]
pub struct Heap {
    objects: HashMap<Pointer, Object>,
    next_address: Pointer,
}

impl std::fmt::Debug for Heap {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut objects = self.objects.iter().collect_vec();
        objects.sort_by_key(|(address, _)| address.raw());

        writeln!(f, "{{")?;
        for (address, object) in objects {
            writeln!(
                f,
                "{address}: {} {}",
                object.reference_count,
                object.format(self),
            )?;
        }
        write!(f, "}}")
    }
}

impl Default for Heap {
    fn default() -> Self {
        Self {
            objects: HashMap::new(),
            next_address: Pointer::from_raw(1),
        }
    }
}
impl Heap {
    pub fn get(&self, address: Pointer) -> &Object {
        self.objects
            .get(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }
    pub fn get_mut(&mut self, address: Pointer) -> &mut Object {
        self.objects
            .get_mut(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }

    pub fn dup(&mut self, address: Pointer) {
        self.get_mut(address).reference_count += 1;
        log::trace!(
            "RefCount of {address} increased to {}. Value: {}",
            self.get(address).reference_count,
            address.format(self),
        );
    }
    pub fn drop(&mut self, address: Pointer) {
        let formatted_value = address.format(self);
        let object = self.get_mut(address);
        object.reference_count -= 1;
        log::trace!(
            "RefCount of {address} reduced to {}. Value: {formatted_value}",
            object.reference_count,
        );
        if object.reference_count == 0 {
            self.free(address);
        }
    }

    pub fn create(&mut self, object: Data) -> Pointer {
        let address = self.next_address;
        self.objects.insert(
            address,
            Object {
                reference_count: 1,
                data: object,
            },
        );
        log::trace!("Created object {} at {address}.", address.format(self));
        self.next_address = Pointer::from_raw(self.next_address.raw() + 1);
        address
    }
    pub fn free(&mut self, address: Pointer) {
        let object = self.objects.remove(&address).unwrap();
        log::trace!("Freeing object at {address}.");
        assert_eq!(object.reference_count, 0);
        for child in object.children() {
            self.drop(child);
        }
    }

    /// Clones all objects at the `root_addresses` into the `other` heap and
    /// returns a list of their addresses in the other heap.
    pub fn clone_multiple_to_other_heap(
        &self,
        other: &mut Heap,
        addresses: &[Pointer],
    ) -> Vec<Pointer> {
        let mut objects_to_refcounts = HashMap::new();
        for address in addresses {
            self.gather_objects_to_clone(&mut objects_to_refcounts, *address);
        }
        let num_objects = objects_to_refcounts.len();

        let address_map: HashMap<Pointer, Pointer> = objects_to_refcounts
            .keys()
            .copied()
            .zip(
                (other.next_address.raw()..other.next_address.raw() + num_objects)
                    .map(Pointer::from_raw),
            )
            .collect();

        for (address, refcount) in objects_to_refcounts {
            other.objects.insert(
                address_map[&address],
                Object {
                    reference_count: refcount,
                    data: Self::map_addresses_in_data(&address_map, &self.get(address).data),
                },
            );
        }
        other.next_address = Pointer::from_raw(other.next_address.raw() + num_objects);

        addresses
            .iter()
            .map(|address| address_map[address])
            .collect()
    }
    fn gather_objects_to_clone(
        &self,
        objects_to_refcounts: &mut HashMap<Pointer, usize>,
        address: Pointer,
    ) {
        *objects_to_refcounts.entry(address).or_default() += 1;
        for child in self.get(address).children() {
            self.gather_objects_to_clone(objects_to_refcounts, child);
        }
    }
    fn map_addresses_in_data(address_map: &HashMap<Pointer, Pointer>, data: &Data) -> Data {
        match data {
            Data::Int(int) => Data::Int(int.clone()),
            Data::Text(text) => Data::Text(text.clone()),
            Data::Symbol(symbol) => Data::Symbol(symbol.clone()),
            Data::Struct(struct_) => Data::Struct(Struct {
                fields: struct_
                    .fields
                    .iter()
                    .map(|(hash, key, value)| (*hash, address_map[key], address_map[value]))
                    .collect_vec(),
            }),
            Data::Closure(closure) => Data::Closure(Closure {
                captured: closure
                    .captured
                    .iter()
                    .map(|address| address_map[address])
                    .collect(),
                num_args: closure.num_args,
                body: closure.body.clone(),
            }),
            Data::Builtin(builtin) => Data::Builtin(builtin.clone()),
        }
    }
    pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer {
        self.clone_multiple_to_other_heap(other, &[address])
            .pop()
            .unwrap()
    }

    pub fn create_int(&mut self, int: BigInt) -> Pointer {
        self.create(Data::Int(Int { value: int }))
    }
    pub fn create_text(&mut self, text: String) -> Pointer {
        self.create(Data::Text(Text { value: text }))
    }
    pub fn create_symbol(&mut self, symbol: String) -> Pointer {
        self.create(Data::Symbol(Symbol { value: symbol }))
    }
    pub fn create_struct(&mut self, fields: HashMap<Pointer, Pointer>) -> Pointer {
        self.create(Data::Struct(Struct::from_fields(self, fields)))
    }
    pub fn create_closure(&mut self, closure: Closure) -> Pointer {
        self.create(Data::Closure(closure))
    }
    pub fn create_builtin(&mut self, builtin: BuiltinFunction) -> Pointer {
        self.create(Data::Builtin(Builtin { function: builtin }))
    }
    pub fn create_nothing(&mut self) -> Pointer {
        self.create_symbol("Nothing".to_string())
    }
    pub fn create_list(&mut self, items: Vec<Pointer>) -> Pointer {
        let mut fields = vec![];
        for (index, item) in items.into_iter().enumerate() {
            fields.push((self.create_int(index.into()), item));
        }
        self.create_struct(fields.into_iter().collect())
    }
    pub fn create_bool(&mut self, value: bool) -> Pointer {
        self.create_symbol(if value { "True" } else { "False" }.to_string())
    }
    pub fn create_result(&mut self, result: Result<Pointer, Pointer>) -> Pointer {
        let (type_, value) = match result {
            Ok(it) => ("Ok".to_string(), it),
            Err(it) => ("Error".to_string(), it),
        };
        let fields = HashMap::from([
            (
                self.create_symbol("Type".to_string()),
                self.create_symbol(type_),
            ),
            (self.create_symbol("Value".to_string()), value),
        ]);
        self.create_struct(fields)
    }
    pub fn create_ordering(&mut self, ordering: Ordering) -> Pointer {
        self.create_symbol(
            match ordering {
                Ordering::Less => "Less",
                Ordering::Equal => "Equal",
                Ordering::Greater => "Greater",
            }
            .to_string(),
        )
    }
}
<commit_msg>Make Heap::create_list more efficient<commit_after>mod object;
mod pointer;

pub use self::{
    object::{Builtin, Closure, Data, Int, Object, Struct, Symbol, Text},
    pointer::Pointer,
};
use crate::builtin_functions::BuiltinFunction;
use itertools::Itertools;
use num_bigint::BigInt;
use std::{cmp::Ordering, collections::HashMap};

#[derive(Clone)]
pub struct Heap {
    objects: HashMap<Pointer, Object>,
    next_address: Pointer,
}

impl std::fmt::Debug for Heap {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut objects = self.objects.iter().collect_vec();
        objects.sort_by_key(|(address, _)| address.raw());

        writeln!(f, "{{")?;
        for (address, object) in objects {
            writeln!(
                f,
                "{address}: {} {}",
                object.reference_count,
                object.format(self),
            )?;
        }
        write!(f, "}}")
    }
}

impl Default for Heap {
    fn default() -> Self {
        Self {
            objects: HashMap::new(),
            next_address: Pointer::from_raw(1),
        }
    }
}
impl Heap {
    pub fn get(&self, address: Pointer) -> &Object {
        self.objects
            .get(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }
    pub fn get_mut(&mut self, address: Pointer) -> &mut Object {
        self.objects
            .get_mut(&address)
            .unwrap_or_else(|| panic!("Couldn't get object {address}."))
    }

    pub fn dup(&mut self, address: Pointer) {
        self.get_mut(address).reference_count += 1;
        log::trace!(
            "RefCount of {address} increased to {}. Value: {}",
            self.get(address).reference_count,
            address.format(self),
        );
    }
    pub fn drop(&mut self, address: Pointer) {
        let formatted_value = address.format(self);
        let object = self.get_mut(address);
        object.reference_count -= 1;
        log::trace!(
            "RefCount of {address} reduced to {}. Value: {formatted_value}",
            object.reference_count,
        );
        if object.reference_count == 0 {
            self.free(address);
        }
    }

    pub fn create(&mut self, object: Data) -> Pointer {
        let address = self.next_address;
        self.objects.insert(
            address,
            Object {
                reference_count: 1,
                data: object,
            },
        );
        log::trace!("Created object {} at {address}.", address.format(self));
        self.next_address = Pointer::from_raw(self.next_address.raw() + 1);
        address
    }
    pub fn free(&mut self, address: Pointer) {
        let object = self.objects.remove(&address).unwrap();
        log::trace!("Freeing object at {address}.");
        assert_eq!(object.reference_count, 0);
        for child in object.children() {
            self.drop(child);
        }
    }

    /// Clones all objects at the `root_addresses` into the `other` heap and
    /// returns a list of their addresses in the other heap.
    pub fn clone_multiple_to_other_heap(
        &self,
        other: &mut Heap,
        addresses: &[Pointer],
    ) -> Vec<Pointer> {
        let mut objects_to_refcounts = HashMap::new();
        for address in addresses {
            self.gather_objects_to_clone(&mut objects_to_refcounts, *address);
        }
        let num_objects = objects_to_refcounts.len();

        let address_map: HashMap<Pointer, Pointer> = objects_to_refcounts
            .keys()
            .copied()
            .zip(
                (other.next_address.raw()..other.next_address.raw() + num_objects)
                    .map(Pointer::from_raw),
            )
            .collect();

        for (address, refcount) in objects_to_refcounts {
            other.objects.insert(
                address_map[&address],
                Object {
                    reference_count: refcount,
                    data: Self::map_addresses_in_data(&address_map, &self.get(address).data),
                },
            );
        }
        other.next_address = Pointer::from_raw(other.next_address.raw() + num_objects);

        addresses
            .iter()
            .map(|address| address_map[address])
            .collect()
    }
    fn gather_objects_to_clone(
        &self,
        objects_to_refcounts: &mut HashMap<Pointer, usize>,
        address: Pointer,
    ) {
        *objects_to_refcounts.entry(address).or_default() += 1;
        for child in self.get(address).children() {
            self.gather_objects_to_clone(objects_to_refcounts, child);
        }
    }
    fn map_addresses_in_data(address_map: &HashMap<Pointer, Pointer>, data: &Data) -> Data {
        match data {
            Data::Int(int) => Data::Int(int.clone()),
            Data::Text(text) => Data::Text(text.clone()),
            Data::Symbol(symbol) => Data::Symbol(symbol.clone()),
            Data::Struct(struct_) => Data::Struct(Struct {
                fields: struct_
                    .fields
                    .iter()
                    .map(|(hash, key, value)| (*hash, address_map[key], address_map[value]))
                    .collect_vec(),
            }),
            Data::Closure(closure) => Data::Closure(Closure {
                captured: closure
                    .captured
                    .iter()
                    .map(|address| address_map[address])
                    .collect(),
                num_args: closure.num_args,
                body: closure.body.clone(),
            }),
            Data::Builtin(builtin) => Data::Builtin(builtin.clone()),
        }
    }
    pub fn clone_single_to_other_heap(&self, other: &mut Heap, address: Pointer) -> Pointer {
        self.clone_multiple_to_other_heap(other, &[address])
            .pop()
            .unwrap()
    }

    pub fn create_int(&mut self, int: BigInt) -> Pointer {
        self.create(Data::Int(Int { value: int }))
    }
    pub fn create_text(&mut self, text: String) -> Pointer {
        self.create(Data::Text(Text { value: text }))
    }
    pub fn create_symbol(&mut self, symbol: String) -> Pointer {
        self.create(Data::Symbol(Symbol { value: symbol }))
    }
    pub fn create_struct(&mut self, fields: HashMap<Pointer, Pointer>) -> Pointer {
        self.create(Data::Struct(Struct::from_fields(self, fields)))
    }
    pub fn create_closure(&mut self, closure: Closure) -> Pointer {
        self.create(Data::Closure(closure))
    }
    pub fn create_builtin(&mut self, builtin: BuiltinFunction) -> Pointer {
        self.create(Data::Builtin(Builtin { function: builtin }))
    }
    pub fn create_nothing(&mut self) -> Pointer {
        self.create_symbol("Nothing".to_string())
    }
    pub fn create_list(&mut self, items: Vec<Pointer>) -> Pointer {
        let fields = items
            .into_iter()
            .enumerate()
            .map(|(index, item)| (self.create_int(index.into()), item))
            .collect();
        self.create_struct(fields)
    }
    pub fn create_bool(&mut self, value: bool) -> Pointer {
        self.create_symbol(if value { "True" } else { "False" }.to_string())
    }
    pub fn create_result(&mut self, result: Result<Pointer, Pointer>) -> Pointer {
        let (type_, value) = match result {
            Ok(it) => ("Ok".to_string(), it),
            Err(it) => ("Error".to_string(), it),
        };
        let fields = HashMap::from([
            (
                self.create_symbol("Type".to_string()),
                self.create_symbol(type_),
            ),
            (self.create_symbol("Value".to_string()), value),
        ]);
        self.create_struct(fields)
    }
    pub fn create_ordering(&mut self, ordering: Ordering) -> Pointer {
        self.create_symbol(
            match ordering {
                Ordering::Less => "Less",
                Ordering::Equal => "Equal",
                Ordering::Greater => "Greater",
            }
            .to_string(),
        )
    }
}
<|endoftext|>