<commit_before>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program.as_str().unwrap_or("<not-utf8>")));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_string());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.unshift(path.display().to_string());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_string(), v.to_string());
            },
            None => {
                self.env.remove(&key.to_string());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        let program = self.program.as_str().unwrap_or("<not-utf8>");
        if self.args.len() == 0 {
            program.to_string()
        } else {
            format!("{} {}", program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_string(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: os::env().move_iter().collect()
    }
}
<commit_msg>Update to master<commit_after>use std::fmt;
use std::fmt::{Show, Formatter};
use std::os;
use std::c_str::CString;
use std::io::process::{Command, ProcessOutput, InheritFd};
use std::collections::HashMap;

use util::{ProcessError, process_error};

#[deriving(Clone,PartialEq)]
pub struct ProcessBuilder {
    program: CString,
    args: Vec<String>,
    path: Vec<String>,
    env: HashMap<String, String>,
    cwd: Path
}

impl Show for ProcessBuilder {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "`{}", self.program.as_str().unwrap_or("<not-utf8>")));

        if self.args.len() > 0 {
            try!(write!(f, " {}", self.args.connect(" ")));
        }

        write!(f, "`")
    }
}

// TODO: Upstream a Windows/Posix branch to Rust proper
#[cfg(unix)]
static PATH_SEP : &'static str = ":";
#[cfg(windows)]
static PATH_SEP : &'static str = ";";

impl ProcessBuilder {
    pub fn arg<T: Str>(mut self, arg: T) -> ProcessBuilder {
        self.args.push(arg.as_slice().to_string());
        self
    }

    pub fn args<T: Str>(mut self, arguments: &[T]) -> ProcessBuilder {
        self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect();
        self
    }

    pub fn get_args<'a>(&'a self) -> &'a [String] {
        self.args.as_slice()
    }

    pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
        // For now, just convert to a string, but we should do something better
        self.path.unshift(path.display().to_string());
        self
    }

    pub fn cwd(mut self, path: Path) -> ProcessBuilder {
        self.cwd = path;
        self
    }

    pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder {
        match val {
            Some(v) => {
                self.env.insert(key.to_string(), v.to_string());
            },
            None => {
                self.env.remove(&key.to_string());
            }
        }

        self
    }

    // TODO: should InheritFd be hardcoded?
    pub fn exec(&self) -> Result<(), ProcessError> {
        let mut command = self.build_command();
        command
            .env_set_all(self.build_env().as_slice())
            .stdout(InheritFd(1))
            .stderr(InheritFd(2));

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let exit = try!(command.status().map_err(|e|
            process_error(msg(), Some(e), None, None)));

        if exit.success() {
            Ok(())
        } else {
            Err(process_error(msg(), None, Some(&exit), None))
        }
    }

    pub fn exec_with_output(&self) -> Result<ProcessOutput, ProcessError> {
        let mut command = self.build_command();
        command.env_set_all(self.build_env().as_slice());

        let msg = || format!("Could not execute process `{}`",
                             self.debug_string());

        let output = try!(command.output().map_err(|e| {
            process_error(msg(), Some(e), None, None)
        }));

        if output.status.success() {
            Ok(output)
        } else {
            Err(process_error(msg(), None, Some(&output.status),
                              Some(&output)))
        }
    }

    pub fn build_command(&self) -> Command {
        let mut command = Command::new(self.program.as_bytes_no_nul());
        command.args(self.args.as_slice()).cwd(&self.cwd);
        command
    }

    fn debug_string(&self) -> String {
        let program = self.program.as_str().unwrap_or("<not-utf8>");
        if self.args.len() == 0 {
            program.to_string()
        } else {
            format!("{} {}", program, self.args.connect(" "))
        }
    }

    fn build_env(&self) -> Vec<(String, String)> {
        let mut ret = Vec::new();

        for (key, val) in self.env.iter() {
            // Skip path
            if key.as_slice() != "PATH" {
                ret.push((key.clone(), val.clone()));
            }
        }

        match self.build_path() {
            Some(path) => ret.push(("PATH".to_string(), path)),
            _ => ()
        }

        ret.as_slice().to_owned()
    }

    fn build_path(&self) -> Option<String> {
        let path = self.path.connect(PATH_SEP);

        match self.env.find_equiv(&("PATH")) {
            Some(existing) => {
                if self.path.is_empty() {
                    Some(existing.clone())
                } else {
                    Some(format!("{}{}{}", existing, PATH_SEP, path))
                }
            },
            None => {
                if self.path.is_empty() {
                    None
                } else {
                    Some(path)
                }
            }
        }
    }
}

pub fn process<T: ToCStr>(cmd: T) -> ProcessBuilder {
    ProcessBuilder {
        program: cmd.to_c_str(),
        args: vec!(),
        path: vec!(),
        cwd: os::getcwd(),
        env: os::env().move_iter().collect()
    }
}
<|endoftext|>


<commit_before>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

extern crate regex;
use regex::Regex;
use std::ascii::AsciiExt;
use std::collections;
use std::io;
use std::io::{BufferedReader, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => { Box::new(try!(File::create(&Path::new(x.as_slice())))) as Box<Writer> }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = collections::HashMap::<String, u32>::new();
    // let mut map = btree_map::BTreeMap::<String, u32>::new();
    let re = Regex::new(r"\w+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    let found = match map.get_mut(&word) {
                        Some(count) => { *count = *count + 1; true }
                        None => false,
                    };
                    if !found {
                        map.insert(word, 1);
                    }
                }
            }
        }
    }

    // Write counts
    let mut words: Vec<&String> = map.keys().collect();
    words.sort();
    for word in words.iter() {
        if let Some(count) = map.get(*word) {
            let line = format!("{}\t{}\n", count, word);
            try!(writer.write(line.as_bytes()));
        }
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<commit_msg>Use map.entry instead of map.get_mut<commit_after>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

extern crate regex;
use regex::Regex;
use std::ascii::AsciiExt;
use std::collections;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::io;
use std::io::{BufferedReader, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => { Box::new(try!(File::create(&Path::new(x.as_slice())))) as Box<Writer> }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = collections::HashMap::<String, u32>::new();
    // let mut map = btree_map::BTreeMap::<String, u32>::new();
    let re = Regex::new(r"\w+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    match map.entry(word) {
                        Occupied(mut view) => { *view.get_mut() += 1; }
                        Vacant(view) => { view.insert(1); }
                    }
                }
            }
        }
    }

    // Write counts
    let mut words: Vec<&String> = map.keys().collect();
    words.sort();
    for word in words.iter() {
        if let Some(count) = map.get(*word) {
            let line = format!("{}\t{}\n", count, word);
            try!(writer.write(line.as_bytes()));
        }
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<|endoftext|>


<commit_before>#![feature(proc_macro_hygiene)]
#![allow(unused_imports)]

extern crate dynasmrt;
extern crate dynasm;

use dynasm::dynasm;
use dynasmrt::DynasmApi;

#[test]
fn bugreport_1() {
     let mut ops = dynasmrt::x64::Assembler::new().unwrap();
     dynasm!(ops
        ; int 3
        ; mov Rq(8), rdi
        ; add Rq(8), 1
        ; mov rax, Rq(8)
        ; ret
     );
     let buf = ops.finalize().unwrap();
     let hex: Vec<String> = buf.iter().map(|x| format!("0x{:02X}", *x)).collect();
     let hex: String = hex.join(", ");
     assert_eq!(hex, "0xCD, 0x03, 0x49, 0x89, 0xF8, 0x49, 0x83, 0xC0, 0x01, 0x4C, 0x89, 0xC0, 0xC3", "bugreport_1");
}
<commit_msg>Add tests for the previous two commits<commit_after>#![feature(proc_macro_hygiene)]
#![allow(unused_imports)]

extern crate dynasmrt;
extern crate dynasm;

use dynasm::dynasm;
use dynasmrt::DynasmApi;

// basic dynamic register usage
#[test]
fn bugreport_1() {
    let mut ops = dynasmrt::x64::Assembler::new().unwrap();
    dynasm!(ops
       ; int 3
       ; mov Rq(8), rdi
       ; add Rq(8), 1
       ; mov rax, Rq(8)
       ; ret
    );
    let buf = ops.finalize().unwrap();
    let hex: Vec<String> = buf.iter().map(|x| format!("0x{:02X}", *x)).collect();
    let hex: String = hex.join(", ");
    assert_eq!(hex, "0xCD, 0x03, 0x49, 0x89, 0xF8, 0x49, 0x83, 0xC0, 0x01, 0x4C, 0x89, 0xC0, 0xC3", "bugreport_1");
}

// ensure RBP/RSP can be used as dynamic base register by always emitting the full SIB byte and a displacement
#[test]
fn bugreport_2() {
    let mut ops = dynasmrt::x64::Assembler::new().unwrap();
    dynasm!(ops
       ; inc [rsp]
       ; inc [Rq(4)]
       ; inc [Rq(4) + 1]
       ; inc [4 * rdx + Rq(4) + 1]
       ; inc [rbp]
       ; inc [Rq(5)]
       ; inc [Rq(5) + 1]
       ; inc [4 * rdx + Rq(5) + 1]
       ; inc [r12]
       ; inc [Rq(12)]
       ; inc [Rq(12) + 1]
       ; inc [4 * rdx + Rq(12) + 1]
       ; inc [r13]
       ; inc [Rq(13)]
       ; inc [Rq(13) + 1]
       ; inc [4 * rdx + Rq(13) + 1]
       ; inc [rcx]
       ; inc [Rq(1)]
       ; inc [Rq(1) + 1]
       ; inc [4 * rdx + Rq(1) + 1]
    );
    let buf = ops.finalize().unwrap();
    let hex: Vec<String> = buf.iter().map(|x| format!("0x{:02X}", *x)).collect();
    let hex: String = hex.join(", ");
    assert_eq!(hex, "0xFE, 0x04, 0x24, 0x40, 0xFE, 0x44, 0x24, 0x00, 0x40, 0xFE, 0x44, 0x24, 0x01, 0x40, 0xFE, 0x44, 0x94, 0x01, 0xFE, 0x45, 0x00, 0x40, 0xFE, 0x44, 0x25, 0x00, 0x40, 0xFE, 0x44, 0x25, 0x01, 0x40, 0xFE, 0x44, 0x95, 0x01, 0x41, 0xFE, 0x04, 0x24, 0x41, 0xFE, 0x44, 0x24, 0x00, 0x41, 0xFE, 0x44, 0x24, 0x01, 0x41, 0xFE, 0x44, 0x94, 0x01, 0x41, 0xFE, 0x45, 0x00, 0x41, 0xFE, 0x44, 0x25, 0x00, 0x41, 0xFE, 0x44, 0x25, 0x01, 0x41, 0xFE, 0x44, 0x95, 0x01, 0xFE, 0x01, 0x40, 0xFE, 0x44, 0x21, 0x00, 0x40, 0xFE, 0x44, 0x21, 0x01, 0x40, 0xFE, 0x44, 0x91, 0x01", "bugreport_2");
}

// ensure dynamic registers work correctly with VEX ops
#[test]
fn bugreport_3() {
    let mut ops = dynasmrt::x64::Assembler::new().unwrap();
    dynasm!(ops
       ; vaddsd Rx(1), Rx(2), Rx(3)
       ; vaddsd Rx(10), Rx(9), Rx(11)
    );
    let buf = ops.finalize().unwrap();
    let hex: Vec<String> = buf.iter().map(|x| format!("0x{:02X}", *x)).collect();
    let hex: String = hex.join(", ");
    assert_eq!(hex, "0xC4, 0xE1, 0x6B, 0x58, 0xCB, 0xC4, 0x41, 0x33, 0x58, 0xD3", "bugreport_3");
}
<|endoftext|>


<commit_before>#![no_std]
#![allow(dead_code)]

extern crate core;
extern crate frame_stack;

use core::prelude::*;
use self::frame_stack::{Frame, allocate_frame};

// for macros
mod std {
    pub use core::*;
}

#[macro_use]
mod macros;

#[macro_use]
mod bitflags;

/* for testing */
mod vga;

const PAGE_SIZE: u64 = 4096;

struct VirtualAddress(*const u8);
impl Copy for VirtualAddress{}

#[derive(PartialEq)]
struct Page {
    number: usize,
}
impl Copy for Page{}
struct PageIter(Page);

struct PageTablePage(Page);
struct PageTableField(*const u64);

bitflags! {
    flags PageTableFieldFlags: u64 {
        const NOT_FREE = 1 << 11,
        const PRESENT =         NOT_FREE.bits | 1 << 0,
        const WRITABLE =        NOT_FREE.bits | 1 << 1,
        const USER_ACCESSIBLE = NOT_FREE.bits | 1 << 2,
        const WRITE_THROUGH =   NOT_FREE.bits | 1 << 3,
        const NO_CACHE =        NOT_FREE.bits | 1 << 4,
        const ACCESSED =        NOT_FREE.bits | 1 << 5,
        const DIRTY =           NOT_FREE.bits | 1 << 6,
        const OTHER1 =          NOT_FREE.bits | 1 << 9,
        const OTHER2 =          NOT_FREE.bits | 1 << 10,
        const NO_EXECUTE =      NOT_FREE.bits | 1 << 63,
    }
}

struct Allocator {
    current_page: Page,
    next_byte: VirtualAddress,
}

static mut allocator: Option<Allocator> = None;
// first allocated address starts on second P4-Page
static FIRST_PAGE : Page = Page {
    number: 0o_001_000_000_000,
};

pub unsafe fn allocate(size: usize, align: usize) -> *const u8 {
    if allocator.is_none() {
        FIRST_PAGE.map_to_new_frame();
        allocator = Some(Allocator {
            next_byte: FIRST_PAGE.start_address(),
            current_page: FIRST_PAGE,
        });
    }
    allocator.as_mut().expect("allocator must be initialized").allocate(size, align).0
}

pub unsafe fn deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
    //print!("start: {:x}, size: {:x}, align: {:x}\n", _ptr as usize, _old_size, _align);
}

impl Allocator {
    unsafe fn allocate(&mut self, size: usize, align: usize) -> VirtualAddress {
        let addr = self.next_byte.0 as usize;

        //align
        if align > 0 && addr % align != 0 {
            self.next_byte = VirtualAddress((addr + align - (addr % align)) as *const u8);
        }

        //map unmapped pages if allocation is on new pages
        let end_page = VirtualAddress((addr + size - 1) as *const u8).page();
        for page in self.current_page.next_pages().take(
                end_page.number - self.current_page.number) {
            page.map_to_new_frame();
        }

        //allocate
        let start = self.next_byte;
        self.next_byte = VirtualAddress((addr + size) as *const u8);
        self.current_page = end_page;

        // DEBUGGING: zero allocated bytes
        for i in (0..size) {
            *((start.0 as usize + i) as *mut u8) = 0;
        }

        start
    }
}

impl Page {
    fn from_address(address: &VirtualAddress) -> Page {
        Page {
            number: address.0 as usize >> 12,
        }
    }

    fn start_address(&self) -> VirtualAddress {
        if self.number >= 0o400_000_000_000 {
            //sign extension
            VirtualAddress(((self.number << 12) | 0o177777_000_000_000_000_0000) as *const u8)
        } else {
            VirtualAddress((self.number << 12) as *const u8)
        }
    }

    fn p4_index(&self) -> usize {(self.number >> 27) & 0o777}
    fn p3_index(&self) -> usize {(self.number >> 18) & 0o777}
    fn p2_index(&self) -> usize {(self.number >> 9) & 0o777}
    fn p1_index(&self) -> usize {(self.number >> 0) & 0o777}

    fn p4_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_777_777_777,
        })
    }
    fn p3_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_777_777_000 | self.p4_index(),
        })
    }
    fn p2_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_777_000_000 | (self.p4_index() << 9) | self.p3_index(),
        })
    }
    fn p1_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_000_000_000 | (self.p4_index() << 18) | (self.p3_index() << 9)
                | self.p2_index(),
        })
    }

    unsafe fn map_to_new_frame(&self) {
        let p4_field = self.p4_page().field(self.p4_index());
        if p4_field.is_free() {
            p4_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
            self.p3_page().zero();
        }
        let p3_field = self.p3_page().field(self.p3_index());
        if p3_field.is_free() {
            p3_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
            self.p2_page().zero();
        }
        let p2_field = self.p2_page().field(self.p2_index());
        if p2_field.is_free() {
            p2_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
            self.p1_page().zero();
        }
        let p1_field = self.p1_page().field(self.p1_index());
        assert!(p1_field.is_free());
        p1_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
    }

    unsafe fn zero(&self) {
        let page = self.start_address().0 as *mut [u64; (PAGE_SIZE/64) as usize];
        *page = [0; (PAGE_SIZE/64) as usize];
    }

    fn next_pages(self) -> PageIter {
        PageIter(self)
    }
}

impl Iterator for PageIter {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        self.0.number += 1;
        Some(self.0)
    }
}

impl PageTablePage {
    fn field(&self, index: usize) -> PageTableField {
        //print!("index: {} pointer: {:o}\n", index, self.0.start_address().0 as usize + (index * 8));
        PageTableField((self.0.start_address().0 as usize + (index * 8)) as *const u64)
    }
    fn zero(&self) {unsafe{self.0.zero()}}
}

impl VirtualAddress {
    fn page(&self) -> Page {
        Page::from_address(self)
    }

    fn page_offset(&self) -> u32 {
        self.0 as u32 & 0xfff
    }
}

impl PageTableField {

    unsafe fn is(&self, flags: PageTableFieldFlags) -> bool {

        //print!("{:o}\n", self.0 as usize);
        PageTableFieldFlags::from_bits_truncate(*(self.0)).contains(flags)
    }

    unsafe fn add_flag(&self, flags: PageTableFieldFlags) {
        *(self.0 as *mut u64) |= flags.bits;
    }

    unsafe fn remove_flag(&self, flags: PageTableFieldFlags) {
        *(self.0 as *mut u64) &= !flags.bits;
    }

    unsafe fn is_free(&self) -> bool {
        !self.is(NOT_FREE)
    }

    unsafe fn pointed_frame(&self) -> Frame {
        Frame {
            number: (((*self.0) & 0x000fffff_fffff000) >> 12) as u32,
        }
    }

    unsafe fn set(&self, frame: Frame, flags: PageTableFieldFlags) {
        let f = self.0 as *mut u64;
        *f = (((frame.number as u64) << 12) & 0x000fffff_fffff000) | flags.bits();
    }
}
<commit_msg>small type fixes<commit_after>#![no_std]
#![allow(dead_code)]

extern crate core;
extern crate frame_stack;

use core::prelude::*;
use self::frame_stack::{Frame, allocate_frame};

// for macros
mod std {
    pub use core::*;
}

#[macro_use]
mod macros;

#[macro_use]
mod bitflags;

/* for testing */
mod vga;

const PAGE_SIZE: u64 = 4096;

struct VirtualAddress(*const u8);
impl Copy for VirtualAddress{}

#[derive(PartialEq)]
struct Page {
    number: usize,
}
impl Copy for Page{}
struct PageIter(Page);

struct PageTablePage(Page);
struct PageTableField(*const u64);

bitflags! {
    flags PageTableFieldFlags: u64 {
        const NOT_FREE = 1 << 11,
        const PRESENT =         NOT_FREE.bits | 1 << 0,
        const WRITABLE =        NOT_FREE.bits | 1 << 1,
        const USER_ACCESSIBLE = NOT_FREE.bits | 1 << 2,
        const WRITE_THROUGH =   NOT_FREE.bits | 1 << 3,
        const NO_CACHE =        NOT_FREE.bits | 1 << 4,
        const ACCESSED =        NOT_FREE.bits | 1 << 5,
        const DIRTY =           NOT_FREE.bits | 1 << 6,
        const OTHER1 =          NOT_FREE.bits | 1 << 9,
        const OTHER2 =          NOT_FREE.bits | 1 << 10,
        const NO_EXECUTE =      NOT_FREE.bits | 1 << 63,
    }
}

struct Allocator {
    current_page: Page,
    next_byte: VirtualAddress,
}

static mut allocator: Option<Allocator> = None;
// first allocated address starts on second P4-Page
static FIRST_PAGE : Page = Page {
    number: 0o_001_000_000_000,
};

pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
    if allocator.is_none() {
        FIRST_PAGE.map_to_new_frame();
        allocator = Some(Allocator {
            next_byte: FIRST_PAGE.start_address(),
            current_page: FIRST_PAGE,
        });
    }
    allocator.as_mut().expect("allocator must be initialized").allocate(size, align).0 as *mut u8
}

pub unsafe fn deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
    //print!("start: {:x}, size: {:x}, align: {:x}\n", _ptr as usize, _old_size, _align);
}

pub unsafe fn reallocate(_ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
    allocate(size, align)
}

pub unsafe fn reallocate_inplace(_ptr: *mut u8, _old_size: usize, _size: usize,
                                align: usize) -> usize {
    0
}

pub fn stats_print() {}

pub fn usable_size(size: usize, align: usize) -> usize {
    size
}

impl Allocator {
    unsafe fn allocate(&mut self, size: usize, align: usize) -> VirtualAddress {
        let addr = self.next_byte.0 as usize;

        //align
        if align > 0 && addr % align != 0 {
            self.next_byte = VirtualAddress((addr + align - (addr % align)) as *const u8);
        }

        //map unmapped pages if allocation is on new pages
        let end_page = VirtualAddress((addr + size - 1) as *const u8).page();
        for page in self.current_page.next_pages().take(
                end_page.number - self.current_page.number) {
            page.map_to_new_frame();
        }

        //allocate
        let start = self.next_byte;
        self.next_byte = VirtualAddress((addr + size) as *const u8);
        self.current_page = end_page;

        // DEBUGGING: zero allocated bytes
        for i in (0..size) {
            *((start.0 as usize + i) as *mut u8) = 0;
        }

        start
    }
}

impl Page {
    fn from_address(address: &VirtualAddress) -> Page {
        Page {
            number: address.0 as usize >> 12,
        }
    }

    fn start_address(&self) -> VirtualAddress {
        if self.number >= 0o400_000_000_000 {
            //sign extension
            VirtualAddress(((self.number << 12) | 0o177777_000_000_000_000_0000) as *const u8)
        } else {
            VirtualAddress((self.number << 12) as *const u8)
        }
    }

    fn p4_index(&self) -> usize {(self.number >> 27) & 0o777}
    fn p3_index(&self) -> usize {(self.number >> 18) & 0o777}
    fn p2_index(&self) -> usize {(self.number >> 9) & 0o777}
    fn p1_index(&self) -> usize {(self.number >> 0) & 0o777}

    fn p4_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_777_777_777,
        })
    }
    fn p3_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_777_777_000 | self.p4_index(),
        })
    }
    fn p2_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_777_000_000 | (self.p4_index() << 9) | self.p3_index(),
        })
    }
    fn p1_page(&self) -> PageTablePage {
        PageTablePage(Page {
            number: 0o_777_000_000_000 | (self.p4_index() << 18) | (self.p3_index() << 9)
                | self.p2_index(),
        })
    }

    unsafe fn map_to_new_frame(&self) {
        let p4_field = self.p4_page().field(self.p4_index());
        if p4_field.is_free() {
            p4_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
            self.p3_page().zero();
        }
        let p3_field = self.p3_page().field(self.p3_index());
        if p3_field.is_free() {
            p3_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
            self.p2_page().zero();
        }
        let p2_field = self.p2_page().field(self.p2_index());
        if p2_field.is_free() {
            p2_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
            self.p1_page().zero();
        }
        let p1_field = self.p1_page().field(self.p1_index());
        assert!(p1_field.is_free());
        p1_field.set(allocate_frame().expect("no frame allocated"), PRESENT | WRITABLE);
    }

    unsafe fn zero(&self) {
        let page = self.start_address().0 as *mut [u64; (PAGE_SIZE/64) as usize];
        *page = [0; (PAGE_SIZE/64) as usize];
    }

    fn next_pages(self) -> PageIter {
        PageIter(self)
    }
}

impl Iterator for PageIter {
    type Item = Page;

    fn next(&mut self) -> Option<Page> {
        self.0.number += 1;
        Some(self.0)
    }
}

impl PageTablePage {
    fn field(&self, index: usize) -> PageTableField {
        //print!("index: {} pointer: {:o}\n", index, self.0.start_address().0 as usize + (index * 8));
        PageTableField((self.0.start_address().0 as usize + (index * 8)) as *const u64)
    }
    fn zero(&self) {unsafe{self.0.zero()}}
}

impl VirtualAddress {
    fn page(&self) -> Page {
        Page::from_address(self)
    }

    fn page_offset(&self) -> u32 {
        self.0 as u32 & 0xfff
    }
}

impl PageTableField {

    unsafe fn is(&self, flags: PageTableFieldFlags) -> bool {

        //print!("{:o}\n", self.0 as usize56+56+56+56+);
        PageTableFieldFlags::from_bits_truncate(*(self.0)).contains(flags)
    }

    unsafe fn add_flag(&self, flags: PageTableFieldFlags) {
        *(self.0 as *mut u64) |= flags.bits;
    }

    unsafe fn remove_flag(&self, flags: PageTableFieldFlags) {
        *(self.0 as *mut u64) &= !flags.bits;
    }

    unsafe fn is_free(&self) -> bool {
        !self.is(NOT_FREE)
    }

    unsafe fn pointed_frame(&self) -> Frame {
        Frame {
            number: (((*self.0) & 0x000fffff_fffff000) >> 12) as u32,
        }
    }

    unsafe fn set(&self, frame: Frame, flags: PageTableFieldFlags) {
        let f = self.0 as *mut u64;
        *f = (((frame.number as u64) << 12) & 0x000fffff_fffff000) | flags.bits();
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use WindowWrapper;
use blob;
use std::sync::mpsc::Receiver;
use webrender::api::*;
use wrench::Wrench;

pub struct RawtestHarness<'a> {
    wrench: &'a mut Wrench,
    rx: Receiver<()>,
    window: &'a mut WindowWrapper,
}

impl<'a> RawtestHarness<'a> {
    pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: Receiver<()>) -> Self {
        RawtestHarness {
            wrench,
            rx,
            window,
        }
    }

    pub fn run(mut self) {
        self.retained_blob_images_test();
        self.blob_update_test();
        self.tile_decomposition();
        self.save_restore();
    }

    fn render_and_get_pixels(&mut self, window_rect: DeviceUintRect) -> Vec<u8> {
        self.rx.recv().unwrap();
        self.wrench.render();
        self.wrench.renderer.read_pixels_rgba8(window_rect)
    }

    fn tile_decomposition(&mut self) {
        // This exposes a crash in tile decomposition
        let layout_size = LayoutSize::new(800., 800.);
        let mut resources = ResourceUpdates::new();

        let blob_img = self.wrench.api.generate_image_key();
        resources.add_image(
            blob_img,
            ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true),
            ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
            Some(128),
        );

        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);

        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::new(448.899994, 74.0), LayoutSize::new(151.000031, 56.)));

        // setup some malicious image size parameters
        builder.push_image(
            &info,
            LayoutSize::new(151., 56.0),
            LayoutSize::new(151.0, 56.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            self.wrench.document_id,
            Epoch(0),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );
        self.wrench
            .api
            .generate_frame(self.wrench.document_id, None);

        self.rx.recv().unwrap();
        self.wrench.render();
    }

    fn retained_blob_images_test(&mut self) {
        let blob_img;
        let window_size = self.window.get_inner_size_pixels();
        let window_size = DeviceUintSize::new(window_size.0, window_size.1);

        let test_size = DeviceUintSize::new(400, 400);
        let document_id = self.wrench.document_id;

        let window_rect = DeviceUintRect::new(
            DeviceUintPoint::new(0, window_size.height - test_size.height),
            test_size,
        );
        let layout_size = LayoutSize::new(400., 400.);
        let mut resources = ResourceUpdates::new();
        {
            let api = &self.wrench.api;

            blob_img = api.generate_image_key();
            resources.add_image(
                blob_img,
                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
                ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                None,
            );
        }
        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        // draw the blob the first time
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::new(0.0, 60.0), LayoutSize::new(200.0, 200.0)));

        builder.push_image(
            &info,
            LayoutSize::new(200.0, 200.0),
            LayoutSize::new(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(0),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );
        self.wrench.api.generate_frame(document_id, None);

        // draw the blob image a second time at a different location

        // make a new display list that refers to the first image
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::new(1.0, 60.0), LayoutSize::new(200.0, 200.0)));
        builder.push_image(
            &info,
            LayoutSize::new(200.0, 200.0),
            LayoutSize::new(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(1),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            ResourceUpdates::new(),
        );

        self.wrench.api.generate_frame(document_id, None);

        let pixels_first = self.render_and_get_pixels(window_rect);
        let pixels_second = self.render_and_get_pixels(window_rect);

        // use png;
        // png::save_flipped("out1.png", &pixels_first, window_rect.size);
        // png::save_flipped("out2.png", &pixels_second, window_rect.size);

        assert!(pixels_first != pixels_second);
    }

    fn blob_update_test(&mut self) {
        let blob_img;
        let window_size = self.window.get_inner_size_pixels();
        let window_size = DeviceUintSize::new(window_size.0, window_size.1);

        let test_size = DeviceUintSize::new(400, 400);
        let document_id = self.wrench.document_id;

        let window_rect = DeviceUintRect::new(
            DeviceUintPoint::new(0, window_size.height - test_size.height),
            test_size,
        );
        let layout_size = LayoutSize::new(400., 400.);
        let mut resources = ResourceUpdates::new();
        {
            let api = &self.wrench.api;

            blob_img = api.generate_image_key();
            resources.add_image(
                blob_img,
                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
                ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                None,
            );
        }
        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        // draw the blob the first time
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::new(0.0, 60.0), LayoutSize::new(200.0, 200.0)));

        builder.push_image(
            &info,
            LayoutSize::new(200.0, 200.0),
            LayoutSize::new(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(0),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );
        self.wrench.api.generate_frame(document_id, None);
        let pixels_first = self.render_and_get_pixels(window_rect);

        // draw the blob image a second time after updating it with the same color
        let mut resources = ResourceUpdates::new();
        resources.update_image(
            blob_img,
            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
            ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
            Some(DeviceUintRect::new(DeviceUintPoint::new(100, 100), DeviceUintSize::new(100, 100))),
        );

        // make a new display list that refers to the first image
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::new(0.0, 60.0), LayoutSize::new(200.0, 200.0)));
        builder.push_image(
            &info,
            LayoutSize::new(200.0, 200.0),
            LayoutSize::new(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(1),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );

        self.wrench.api.generate_frame(document_id, None);
        let pixels_second = self.render_and_get_pixels(window_rect);

        // draw the blob image a third time after updating it with a different color
        let mut resources = ResourceUpdates::new();
        resources.update_image(
            blob_img,
            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
            ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
            Some(DeviceUintRect::new(DeviceUintPoint::new(200, 200), DeviceUintSize::new(100, 100))),
        );

        // make a new display list that refers to the first image
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(
            LayoutRect::new(LayoutPoint::new(0.0, 60.0), LayoutSize::new(200.0, 200.0)));
        builder.push_image(
            &info,
            LayoutSize::new(200.0, 200.0),
            LayoutSize::new(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(2),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );

        self.wrench.api.generate_frame(document_id, None);

        let pixels_third = self.render_and_get_pixels(window_rect);

        assert!(pixels_first == pixels_second);
        assert!(pixels_first != pixels_third);
    }

    // Ensures that content doing a save-restore produces the same results as not
    fn save_restore(&mut self) {
        fn rect(x: f32, y: f32, w: f32, h: f32) -> LayoutRect {
            LayoutRect::new(
                    LayoutPoint::new(x, y),
                    LayoutSize::new(w, h))
        }

        let window_size = self.window.get_inner_size_pixels();
        let window_size = DeviceUintSize::new(window_size.0, window_size.1);

        let test_size = DeviceUintSize::new(400, 400);

        let window_rect = DeviceUintRect::new(
            DeviceUintPoint::new(0, window_size.height - test_size.height),
            test_size,
        );
        let layout_size = LayoutSize::new(400., 400.);
        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        let mut do_test = |should_try_and_fail| {
            let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);

            let clip = builder.define_clip(None, rect(110., 120., 200., 200.),
                                           None::<ComplexClipRegion>, None);
            builder.push_clip_id(clip);
            builder.push_rect(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
                              ColorF::new(0.0, 0.0, 1.0, 1.0));

            if should_try_and_fail {
                builder.save();
                let clip = builder.define_clip(None, rect(80., 80., 90., 90.),
                                           None::<ComplexClipRegion>, None);
                builder.push_clip_id(clip);
                builder.push_rect(&PrimitiveInfo::new(rect(110., 110., 50., 50.)),
                              ColorF::new(0.0, 1.0, 0.0, 1.0));
                builder.push_shadow(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
                    Shadow {
                        offset: LayoutVector2D::new(1.0, 1.0),
                        blur_radius: 1.0,
                        color: ColorF::new(0.0, 0.0, 0.0, 1.0),
                    });
                builder.push_line(&PrimitiveInfo::new(rect(110., 110., 50., 2.)),
                                  0.0, LineOrientation::Horizontal,
                                  &ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid);
                builder.restore();
            }

            {
                builder.save();
                let clip = builder.define_clip(None, rect(80., 80., 100., 100.),
                                               None::<ComplexClipRegion>, None);
                builder.push_clip_id(clip);
                builder.push_rect(&PrimitiveInfo::new(rect(150., 150., 100., 100.)),
                                  ColorF::new(0.0, 0.0, 1.0, 1.0));

                builder.pop_clip_id();
                builder.clear_save();
            }

            builder.pop_clip_id();

            self.wrench.api.set_display_list(
                self.wrench.document_id,
                Epoch(0),
                root_background_color,
                layout_size,
                builder.finalize(),
                false,
                ResourceUpdates::new(),
            );
            self.wrench
                .api
                .generate_frame(self.wrench.document_id, None);

            self.render_and_get_pixels(window_rect)
        };

        let first = do_test(false);
        let second = do_test(true);

        assert_eq!(first, second);
    }
}
<commit_msg>Auto merge of #2206 - jrmuizel:rect-simplify, r=glennw<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use WindowWrapper;
use blob;
use euclid::{TypedRect, TypedSize2D, TypedPoint2D};
use std::sync::mpsc::Receiver;
use webrender::api::*;
use wrench::Wrench;

pub struct RawtestHarness<'a> {
    wrench: &'a mut Wrench,
    rx: Receiver<()>,
    window: &'a mut WindowWrapper,
}

fn point<T: Copy, U>(x: T, y: T) -> TypedPoint2D<T, U> {
    TypedPoint2D::new(x, y)
}

fn size<T: Copy, U>(x: T, y: T) -> TypedSize2D<T, U> {
    TypedSize2D::new(x, y)
}

fn rect<T: Copy, U>(x: T, y: T, width: T, height: T) -> TypedRect<T, U> {
    TypedRect::new(point(x, y), size(width, height))
}

impl<'a> RawtestHarness<'a> {
    pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: Receiver<()>) -> Self {
        RawtestHarness {
            wrench,
            rx,
            window,
        }
    }

    pub fn run(mut self) {
        self.retained_blob_images_test();
        self.blob_update_test();
        self.tile_decomposition();
        self.save_restore();
    }

    fn render_and_get_pixels(&mut self, window_rect: DeviceUintRect) -> Vec<u8> {
        self.rx.recv().unwrap();
        self.wrench.render();
        self.wrench.renderer.read_pixels_rgba8(window_rect)
    }

    fn tile_decomposition(&mut self) {
        // This exposes a crash in tile decomposition
        let layout_size = LayoutSize::new(800., 800.);
        let mut resources = ResourceUpdates::new();

        let blob_img = self.wrench.api.generate_image_key();
        resources.add_image(
            blob_img,
            ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true),
            ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
            Some(128),
        );

        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);

        let info = LayoutPrimitiveInfo::new(rect(448.899994, 74.0, 151.000031, 56.));

        // setup some malicious image size parameters
        builder.push_image(
            &info,
            size(151., 56.0),
            size(151.0, 56.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            self.wrench.document_id,
            Epoch(0),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );
        self.wrench
            .api
            .generate_frame(self.wrench.document_id, None);

        self.rx.recv().unwrap();
        self.wrench.render();
    }

    fn retained_blob_images_test(&mut self) {
        let blob_img;
        let window_size = self.window.get_inner_size_pixels();
        let window_size = DeviceUintSize::new(window_size.0, window_size.1);

        let test_size = DeviceUintSize::new(400, 400);
        let document_id = self.wrench.document_id;

        let window_rect = DeviceUintRect::new(
            DeviceUintPoint::new(0, window_size.height - test_size.height),
            test_size,
        );
        let layout_size = LayoutSize::new(400., 400.);
        let mut resources = ResourceUpdates::new();
        {
            let api = &self.wrench.api;

            blob_img = api.generate_image_key();
            resources.add_image(
                blob_img,
                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
                ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                None,
            );
        }
        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        // draw the blob the first time
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));

        builder.push_image(
            &info,
            size(200.0, 200.0),
            size(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(0),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );
        self.wrench.api.generate_frame(document_id, None);

        // draw the blob image a second time at a different location

        // make a new display list that refers to the first image
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(rect(1.0, 60.0, 200.0, 200.0));
        builder.push_image(
            &info,
            size(200.0, 200.0),
            size(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(1),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            ResourceUpdates::new(),
        );

        self.wrench.api.generate_frame(document_id, None);

        let pixels_first = self.render_and_get_pixels(window_rect);
        let pixels_second = self.render_and_get_pixels(window_rect);

        // use png;
        // png::save_flipped("out1.png", &pixels_first, window_rect.size);
        // png::save_flipped("out2.png", &pixels_second, window_rect.size);

        assert!(pixels_first != pixels_second);
    }

    fn blob_update_test(&mut self) {
        let blob_img;
        let window_size = self.window.get_inner_size_pixels();
        let window_size = DeviceUintSize::new(window_size.0, window_size.1);

        let test_size = DeviceUintSize::new(400, 400);
        let document_id = self.wrench.document_id;

        let window_rect = DeviceUintRect::new(
            point(0, window_size.height - test_size.height),
            test_size,
        );
        let layout_size = LayoutSize::new(400., 400.);
        let mut resources = ResourceUpdates::new();
        {
            let api = &self.wrench.api;

            blob_img = api.generate_image_key();
            resources.add_image(
                blob_img,
                ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
                ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
                None,
            );
        }
        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        // draw the blob the first time
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));

        builder.push_image(
            &info,
            size(200.0, 200.0),
            size(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(0),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );
        self.wrench.api.generate_frame(document_id, None);
        let pixels_first = self.render_and_get_pixels(window_rect);

        // draw the blob image a second time after updating it with the same color
        let mut resources = ResourceUpdates::new();
        resources.update_image(
            blob_img,
            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
            ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
            Some(rect(100, 100, 100, 100)),
        );

        // make a new display list that refers to the first image
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));
        builder.push_image(
            &info,
            size(200.0, 200.0),
            size(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(1),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );

        self.wrench.api.generate_frame(document_id, None);
        let pixels_second = self.render_and_get_pixels(window_rect);

        // draw the blob image a third time after updating it with a different color
        let mut resources = ResourceUpdates::new();
        resources.update_image(
            blob_img,
            ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true),
            ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
            Some(rect(200, 200, 100, 100)),
        );

        // make a new display list that refers to the first image
        let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
        let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));
        builder.push_image(
            &info,
            size(200.0, 200.0),
            size(0.0, 0.0),
            ImageRendering::Auto,
            blob_img,
        );

        self.wrench.api.set_display_list(
            document_id,
            Epoch(2),
            root_background_color,
            layout_size,
            builder.finalize(),
            false,
            resources,
        );

        self.wrench.api.generate_frame(document_id, None);

        let pixels_third = self.render_and_get_pixels(window_rect);

        assert!(pixels_first == pixels_second);
        assert!(pixels_first != pixels_third);
    }

    // Ensures that content doing a save-restore produces the same results as not
    fn save_restore(&mut self) {
        let window_size = self.window.get_inner_size_pixels();
        let window_size = DeviceUintSize::new(window_size.0, window_size.1);

        let test_size = DeviceUintSize::new(400, 400);

        let window_rect = DeviceUintRect::new(
            DeviceUintPoint::new(0, window_size.height - test_size.height),
            test_size,
        );
        let layout_size = LayoutSize::new(400., 400.);
        let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));

        let mut do_test = |should_try_and_fail| {
            let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);

            let clip = builder.define_clip(None, rect(110., 120., 200., 200.),
                                           None::<ComplexClipRegion>, None);
            builder.push_clip_id(clip);
            builder.push_rect(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
                              ColorF::new(0.0, 0.0, 1.0, 1.0));

            if should_try_and_fail {
                builder.save();
                let clip = builder.define_clip(None, rect(80., 80., 90., 90.),
                                           None::<ComplexClipRegion>, None);
                builder.push_clip_id(clip);
                builder.push_rect(&PrimitiveInfo::new(rect(110., 110., 50., 50.)),
                              ColorF::new(0.0, 1.0, 0.0, 1.0));
                builder.push_shadow(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
                    Shadow {
                        offset: LayoutVector2D::new(1.0, 1.0),
                        blur_radius: 1.0,
                        color: ColorF::new(0.0, 0.0, 0.0, 1.0),
                    });
                builder.push_line(&PrimitiveInfo::new(rect(110., 110., 50., 2.)),
                                  0.0, LineOrientation::Horizontal,
                                  &ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid);
                builder.restore();
            }

            {
                builder.save();
                let clip = builder.define_clip(None, rect(80., 80., 100., 100.),
                                               None::<ComplexClipRegion>, None);
                builder.push_clip_id(clip);
                builder.push_rect(&PrimitiveInfo::new(rect(150., 150., 100., 100.)),
                                  ColorF::new(0.0, 0.0, 1.0, 1.0));

                builder.pop_clip_id();
                builder.clear_save();
            }

            builder.pop_clip_id();

            self.wrench.api.set_display_list(
                self.wrench.document_id,
                Epoch(0),
                root_background_color,
                layout_size,
                builder.finalize(),
                false,
                ResourceUpdates::new(),
            );
            self.wrench
                .api
                .generate_frame(self.wrench.document_id, None);

            self.render_and_get_pixels(window_rect)
        };

        let first = do_test(false);
        let second = do_test(true);

        assert_eq!(first, second);
    }
}
<|endoftext|>


<commit_before>//! This module defines the `DepNode` type which the compiler uses to represent
//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable
//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes
//! uniquely identify a given commit and has a few advantages:
//!
//! * A `DepNode` can simply be serialized to disk and loaded in another session
//!   without the need to do any "rebasing (like we have to do for Spans and
//!   NodeIds) or "retracing" like we had to do for `DefId` in earlier
//!   implementations of the dependency graph.
//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
//!   implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
//!   memory without any post-processing (e.g., "abomination-style" pointer
//!   reconstruction).
//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that
//!   refer to things that do not exist anymore. In previous implementations
//!   `DepNode` contained a `DefId`. A `DepNode` referring to something that
//!   had been removed between the previous and the current compilation session
//!   could not be instantiated because the current compilation session
//!   contained no `DefId` for thing that had been removed.
//!
//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at
//! runtime in order to construct a valid `DepNode` fingerprint.
//!
//! Because the macro sees what parameters a given `DepKind` requires, it can
//! "infer" some properties for each kind of `DepNode`:
//!
//! * Whether a `DepNode` of a given kind has any parameters at all. Some
//!   `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//!   given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//!   in which case it is possible to map the node's fingerprint back to the
//!   `DefId` it was computed from. In other cases, too much information gets
//!   lost during fingerprint computation.
//!
//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only
//! valid `DepNode` instances can be constructed. For example, the API does not
//! allow for constructing parameterless `DepNode`s with anything other
//! than a zeroed out fingerprint. More generally speaking, it relieves the
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.

use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
use crate::traits::query::{
    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_span::symbol::Symbol;
use std::hash::Hash;

pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};

// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e., which sub-expression of the macro we are in) but don't need
// to actually use any of the arguments.
macro_rules! erase {
    ($x:tt) => {{}};
}

macro_rules! is_anon_attr {
    (anon) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! is_eval_always_attr {
    (eval_always) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! contains_anon_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
}

macro_rules! contains_eval_always_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
}

macro_rules! define_dep_nodes {
    (<$tcx:tt>
    $(
        [$($attrs:tt)*]
        $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
      ,)*
    ) => (
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
                 RustcEncodable, RustcDecodable)]
        #[allow(non_camel_case_types)]
        pub enum DepKind {
            $($variant),*
        }

        impl DepKind {
            #[allow(unreachable_code)]
            pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            if contains_anon_attr!($($attrs)*) {
                                return false;
                            }

                            // tuple args
                            $({
                                return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
                                    ::can_reconstruct_query_key();
                            })*

                            true
                        }
                    )*
                }
            }

            pub fn is_anon(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
                    )*
                }
            }

            pub fn is_eval_always(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
                    )*
                }
            }

            #[allow(unreachable_code)]
            pub fn has_params(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            // tuple args
                            $({
                                erase!($tuple_arg_ty);
                                return true;
                            })*

                            false
                        }
                    )*
                }
            }
        }

        pub struct DepConstructor;

        #[allow(non_camel_case_types)]
        impl DepConstructor {
            $(
                #[inline(always)]
                #[allow(unreachable_code, non_snake_case)]
                pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
                    // tuple args
                    $({
                        erase!($tuple_arg_ty);
                        return DepNode::construct(_tcx, DepKind::$variant, &arg)
                    })*

                    return DepNode::construct(_tcx, DepKind::$variant, &())
                }
            )*
        }

        pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;

        pub trait DepNodeExt: Sized {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash)
                -> Result<Self, ()>;

            /// Used in testing
            fn has_label_string(label: &str) -> bool;
        }

        impl DepNodeExt for DepNode {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
                debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
                DepNode {
                    kind,
                    hash: def_path_hash.0,
                }
            }

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
                if self.kind.can_reconstruct_query_key() {
                    let def_path_hash = DefPathHash(self.hash);
                    tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
                } else {
                    None
                }
            }

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
                let kind = match label {
                    $(
                        stringify!($variant) => DepKind::$variant,
                    )*
                    _ => return Err(()),
                };

                if !kind.can_reconstruct_query_key() {
                    return Err(());
                }

                if kind.has_params() {
                    Ok(DepNode::from_def_path_hash(def_path_hash, kind))
                } else {
                    Ok(DepNode::new_no_params(kind))
                }
            }

            /// Used in testing
            fn has_label_string(label: &str) -> bool {
                match label {
                    $(
                        stringify!($variant) => true,
                    )*
                    _ => false,
                }
            }
        }

        /// Contains variant => str representations for constructing
        /// DepNode groups for tests.
        #[allow(dead_code, non_upper_case_globals)]
        pub mod label_strs {
           $(
                pub const $variant: &str = stringify!($variant);
            )*
        }
    );
}

rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
    // We use this for most things when incr. comp. is turned off.
    [] Null,

    // Represents metadata from an extern crate.
    [eval_always] CrateMetadata(CrateNum),

    [anon] TraitSelect,

    [] CompileCodegenUnit(Symbol),
]);

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        tcx.def_path_hash(*self).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.def_path_str(*self)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        self.to_def_id().to_fingerprint(tcx)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        self.to_def_id().to_debug_str(tcx)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
        tcx.def_path_hash(def_id).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.crate_name(*self).to_string()
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.krate)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let (def_id_0, def_id_1) = *self;

        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
        let def_path_hash_1 = tcx.def_path_hash(def_id_1);

        def_path_hash_0.0.combine(def_path_hash_1.0)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        let (def_id_0, def_id_1) = *self;

        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let HirId { owner, local_id } = *self;

        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
        let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());

        def_path_hash.0.combine(local_id)
    }
}
<commit_msg>Edit docs for rustc_middle::dep_graph::dep_node<commit_after>//! This module defines the `DepNode` type which the compiler uses to represent
//! nodes in the dependency graph.
//!
//! A `DepNode` consists of a `DepKind` (which
//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
//! and a `Fingerprint`, a 128-bit hash value the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable
//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes
//! uniquely identify a given commit and has a few advantages:
//!
//! * A `DepNode` can simply be serialized to disk and loaded in another session
//!   without the need to do any "rebasing" (like we have to do for Spans and
//!   NodeIds) or "retracing" (like we had to do for `DefId` in earlier
//!   implementations of the dependency graph).
//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to
//!   implement `Copy`, `Sync`, `Send`, `Freeze`, etc.
//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into
//!   memory without any post-processing (e.g., "abomination-style" pointer
//!   reconstruction).
//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that
//!   refer to things that do not exist anymore. In previous implementations
//!   `DepNode` contained a `DefId`. A `DepNode` referring to something that
//!   had been removed between the previous and the current compilation session
//!   could not be instantiated because the current compilation session
//!   contained no `DefId` for thing that had been removed.
//!
//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at
//! runtime in order to construct a valid `DepNode` fingerprint.
//!
//! Because the macro sees what parameters a given `DepKind` requires, it can
//! "infer" some properties for each kind of `DepNode`:
//!
//! * Whether a `DepNode` of a given kind has any parameters at all. Some
//!   `DepNode`s could represent global concepts with only one value.
//! * Whether it is possible, in principle, to reconstruct a query key from a
//!   given `DepNode`. Many `DepKind`s only require a single `DefId` parameter,
//!   in which case it is possible to map the node's fingerprint back to the
//!   `DefId` it was computed from. In other cases, too much information gets
//!   lost during fingerprint computation.
//!
//! The `DepConstructor` enum, together with `DepNode::new()`, ensures that only
//! valid `DepNode` instances can be constructed. For example, the API does not
//! allow for constructing parameterless `DepNode`s with anything other
//! than a zeroed out fingerprint. More generally speaking, it relieves the
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.

use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
use crate::traits::query::{
    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_span::symbol::Symbol;
use std::hash::Hash;

pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};

// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e., which sub-expression of the macro we are in) but don't need
// to actually use any of the arguments.
macro_rules! erase {
    ($x:tt) => {{}};
}

macro_rules! is_anon_attr {
    (anon) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! is_eval_always_attr {
    (eval_always) => {
        true
    };
    ($attr:ident) => {
        false
    };
}

macro_rules! contains_anon_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_anon_attr!($attr) | )* false});
}

macro_rules! contains_eval_always_attr {
    ($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
}

macro_rules! define_dep_nodes {
    (<$tcx:tt>
    $(
        [$($attrs:tt)*]
        $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
      ,)*
    ) => (
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
                 RustcEncodable, RustcDecodable)]
        #[allow(non_camel_case_types)]
        pub enum DepKind {
            $($variant),*
        }

        impl DepKind {
            #[allow(unreachable_code)]
            pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            if contains_anon_attr!($($attrs)*) {
                                return false;
                            }

                            // tuple args
                            $({
                                return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
                                    ::can_reconstruct_query_key();
                            })*

                            true
                        }
                    )*
                }
            }

            pub fn is_anon(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
                    )*
                }
            }

            pub fn is_eval_always(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
                    )*
                }
            }

            #[allow(unreachable_code)]
            pub fn has_params(&self) -> bool {
                match *self {
                    $(
                        DepKind :: $variant => {
                            // tuple args
                            $({
                                erase!($tuple_arg_ty);
                                return true;
                            })*

                            false
                        }
                    )*
                }
            }
        }

        pub struct DepConstructor;

        #[allow(non_camel_case_types)]
        impl DepConstructor {
            $(
                #[inline(always)]
                #[allow(unreachable_code, non_snake_case)]
                pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
                    // tuple args
                    $({
                        erase!($tuple_arg_ty);
                        return DepNode::construct(_tcx, DepKind::$variant, &arg)
                    })*

                    return DepNode::construct(_tcx, DepKind::$variant, &())
                }
            )*
        }

        pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;

        pub trait DepNodeExt: Sized {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash)
                -> Result<Self, ()>;

            /// Used in testing
            fn has_label_string(label: &str) -> bool;
        }

        impl DepNodeExt for DepNode {
            /// Construct a DepNode from the given DepKind and DefPathHash. This
            /// method will assert that the given DepKind actually requires a
            /// single DefId/DefPathHash parameter.
            fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
                debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
                DepNode {
                    kind,
                    hash: def_path_hash.0,
                }
            }

            /// Extracts the DefId corresponding to this DepNode. This will work
            /// if two conditions are met:
            ///
            /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
            /// 2. the item that the DefPath refers to exists in the current tcx.
            ///
            /// Condition (1) is determined by the DepKind variant of the
            /// DepNode. Condition (2) might not be fulfilled if a DepNode
            /// refers to something from the previous compilation session that
            /// has been removed.
            fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
                if self.kind.can_reconstruct_query_key() {
                    let def_path_hash = DefPathHash(self.hash);
                    tcx.def_path_hash_to_def_id.as_ref()?.get(&def_path_hash).cloned()
                } else {
                    None
                }
            }

            /// Used in testing
            fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
                let kind = match label {
                    $(
                        stringify!($variant) => DepKind::$variant,
                    )*
                    _ => return Err(()),
                };

                if !kind.can_reconstruct_query_key() {
                    return Err(());
                }

                if kind.has_params() {
                    Ok(DepNode::from_def_path_hash(def_path_hash, kind))
                } else {
                    Ok(DepNode::new_no_params(kind))
                }
            }

            /// Used in testing
            fn has_label_string(label: &str) -> bool {
                match label {
                    $(
                        stringify!($variant) => true,
                    )*
                    _ => false,
                }
            }
        }

        /// Contains variant => str representations for constructing
        /// DepNode groups for tests.
        #[allow(dead_code, non_upper_case_globals)]
        pub mod label_strs {
           $(
                pub const $variant: &str = stringify!($variant);
            )*
        }
    );
}

rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
    // We use this for most things when incr. comp. is turned off.
    [] Null,

    // Represents metadata from an extern crate.
    [eval_always] CrateMetadata(CrateNum),

    [anon] TraitSelect,

    [] CompileCodegenUnit(Symbol),
]);

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        tcx.def_path_hash(*self).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.def_path_str(*self)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        self.to_def_id().to_fingerprint(tcx)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        self.to_def_id().to_debug_str(tcx)
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.expect_local())
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        true
    }

    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let def_id = DefId { krate: *self, index: CRATE_DEF_INDEX };
        tcx.def_path_hash(def_id).0
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        tcx.crate_name(*self).to_string()
    }

    fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
        dep_node.extract_def_id(tcx).map(|id| id.krate)
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let (def_id_0, def_id_1) = *self;

        let def_path_hash_0 = tcx.def_path_hash(def_id_0);
        let def_path_hash_1 = tcx.def_path_hash(def_id_1);

        def_path_hash_0.0.combine(def_path_hash_1.0)
    }

    fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
        let (def_id_0, def_id_1) = *self;

        format!("({}, {})", tcx.def_path_debug_str(def_id_0), tcx.def_path_debug_str(def_id_1))
    }
}

impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
    #[inline]
    fn can_reconstruct_query_key() -> bool {
        false
    }

    // We actually would not need to specialize the implementation of this
    // method but it's faster to combine the hashes than to instantiate a full
    // hashing context and stable-hashing state.
    fn to_fingerprint(&self, tcx: TyCtxt<'tcx>) -> Fingerprint {
        let HirId { owner, local_id } = *self;

        let def_path_hash = tcx.def_path_hash(owner.to_def_id());
        let local_id = Fingerprint::from_smaller_hash(local_id.as_u32().into());

        def_path_hash.0.combine(local_id)
    }
}
<|endoftext|>


<commit_before>mod common;
mod contracts;
mod genesis;
mod params;

pub mod miner;
pub mod solc;

use clap::{App, Arg};
use genesis::GenesisCreator;

fn main() {
    let matches = App::new("CITA genesis creator")
        .version("1.0")
        .author("Cryptape Technologies")
        .arg(
            Arg::with_name("contract_dir")
                .help("The directory of contracts.")
                .required(true),
        )
        .arg(
            Arg::with_name("contract_docs_dir")
                .help("The directory of generated documents for contracts.")
                .required(true),
        )
        .arg(
            Arg::with_name("params_path")
                .help("Path of the file for initialization data of contracts.")
                .required(true),
        )
        .arg(
            Arg::with_name("genesis_path")
                .help("Set created genesis path")
                .required(true),
        )
        .arg(
            Arg::with_name("timestamp")
                .help("Specify a timestamp to use.")
                .required(true),
        )
        .arg(
            Arg::with_name("init_token")
                .help("Init token for this chain")
                .required(true),
        )
        .arg(
            Arg::with_name("prevhash")
                .help("Prevhash of genesis.")
                .required(true),
        )
        .get_matches();

    let contract_dir = matches.value_of("contract_dir").unwrap();
    let contract_docs_dir = matches.value_of("contract_docs_dir").unwrap();
    let params_path = matches.value_of("params_path").unwrap();
    let genesis_path = matches.value_of("genesis_path").unwrap();
    let timestamp = matches.value_of("timestamp").unwrap();
    let init_token = matches.value_of("init_token").unwrap();
    let prevhash = matches.value_of("prevhash").unwrap();
    let mut creator = GenesisCreator::new(
        contract_dir,
        contract_docs_dir,
        params_path,
        genesis_path,
        timestamp.parse::<u64>().unwrap(),
        init_token,
        prevhash,
    );

    creator.create();
}
<commit_msg>chore: update version<commit_after>mod common;
mod contracts;
mod genesis;
mod params;

pub mod miner;
pub mod solc;

use clap::{App, Arg};
use genesis::GenesisCreator;

fn main() {
    let matches = App::new("CITA genesis creator")
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .arg(
            Arg::with_name("contract_dir")
                .help("The directory of contracts.")
                .required(true),
        )
        .arg(
            Arg::with_name("contract_docs_dir")
                .help("The directory of generated documents for contracts.")
                .required(true),
        )
        .arg(
            Arg::with_name("params_path")
                .help("Path of the file for initialization data of contracts.")
                .required(true),
        )
        .arg(
            Arg::with_name("genesis_path")
                .help("Set created genesis path")
                .required(true),
        )
        .arg(
            Arg::with_name("timestamp")
                .help("Specify a timestamp to use.")
                .required(true),
        )
        .arg(
            Arg::with_name("init_token")
                .help("Init token for this chain")
                .required(true),
        )
        .arg(
            Arg::with_name("prevhash")
                .help("Prevhash of genesis.")
                .required(true),
        )
        .get_matches();

    let contract_dir = matches.value_of("contract_dir").unwrap();
    let contract_docs_dir = matches.value_of("contract_docs_dir").unwrap();
    let params_path = matches.value_of("params_path").unwrap();
    let genesis_path = matches.value_of("genesis_path").unwrap();
    let timestamp = matches.value_of("timestamp").unwrap();
    let init_token = matches.value_of("init_token").unwrap();
    let prevhash = matches.value_of("prevhash").unwrap();
    let mut creator = GenesisCreator::new(
        contract_dir,
        contract_docs_dir,
        params_path,
        genesis_path,
        timestamp.parse::<u64>().unwrap(),
        init_token,
        prevhash,
    );

    creator.create();
}
<|endoftext|>


<commit_before>use futures::executor::block_on;
use futures::future::{Future, FutureExt};
use futures::stream::{self, StreamExt, TryStreamExt};
use futures::io::{AsyncBufReadExt, Cursor};
use futures::task::Poll;
use futures_test::io::AsyncReadTestExt;
use futures_test::task::noop_context;

#[test]
fn read_until() {
    let mut buf = Cursor::new(b"12");
    let mut v = Vec::new();
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 2);
    assert_eq!(v, b"12");

    let mut buf = Cursor::new(b"1233");
    let mut v = Vec::new();
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 3);
    assert_eq!(v, b"123");
    v.truncate(0);
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 1);
    assert_eq!(v, b"3");
    v.truncate(0);
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 0);
    assert_eq!(v, []);
}

fn run<F: Future + Unpin>(mut f: F) -> F::Output {
    let mut cx = noop_context();
    loop {
        if let Poll::Ready(x) = f.poll_unpin(&mut cx) {
            return x;
        }
    }
}

#[test]
fn maybe_pending() {
    let mut buf = b"12".interleave_pending();
    let mut v = Vec::new();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 2);
    assert_eq!(v, b"12");

    let mut buf = stream::iter(vec![&b"12"[..], &b"33"[..], &b"3"[..]])
        .map(Ok)
        .into_async_read()
        .interleave_pending();
    let mut v = Vec::new();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 3);
    assert_eq!(v, b"123");
    v.clear();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 1);
    assert_eq!(v, b"3");
    v.clear();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 1);
    assert_eq!(v, b"3");
    v.clear();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 0);
    assert_eq!(v, []);
}
<commit_msg>futures: tests/io_read_until.rs: Don't break w/o features<commit_after>#[cfg(feature = "executor")]
#[test]
fn read_until() {
    use futures::executor::block_on;
    use futures::io::{AsyncBufReadExt, Cursor};

    let mut buf = Cursor::new(b"12");
    let mut v = Vec::new();
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 2);
    assert_eq!(v, b"12");

    let mut buf = Cursor::new(b"1233");
    let mut v = Vec::new();
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 3);
    assert_eq!(v, b"123");
    v.truncate(0);
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 1);
    assert_eq!(v, b"3");
    v.truncate(0);
    assert_eq!(block_on(buf.read_until(b'3', &mut v)).unwrap(), 0);
    assert_eq!(v, []);
}

#[cfg(feature = "std")]
#[test]
fn maybe_pending() {
    use futures::future::Future;

    fn run<F: Future + Unpin>(mut f: F) -> F::Output {
        use futures::future::FutureExt;
        use futures_test::task::noop_context;
        use futures::task::Poll;

        let mut cx = noop_context();
        loop {
            if let Poll::Ready(x) = f.poll_unpin(&mut cx) {
                return x;
            }
        }
    }

    use futures::stream::{self, StreamExt, TryStreamExt};
    use futures::io::AsyncBufReadExt;
    use futures_test::io::AsyncReadTestExt;

    let mut buf = b"12".interleave_pending();
    let mut v = Vec::new();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 2);
    assert_eq!(v, b"12");

    let mut buf = stream::iter(vec![&b"12"[..], &b"33"[..], &b"3"[..]])
        .map(Ok)
        .into_async_read()
        .interleave_pending();
    let mut v = Vec::new();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 3);
    assert_eq!(v, b"123");
    v.clear();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 1);
    assert_eq!(v, b"3");
    v.clear();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 1);
    assert_eq!(v, b"3");
    v.clear();
    assert_eq!(run(buf.read_until(b'3', &mut v)).unwrap(), 0);
    assert_eq!(v, []);
}
<|endoftext|>