<commit_before>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import geom::matrix::Matrix4;
import layers::*;
import scene::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{DOUBLE, check_loop, create_window, destroy_window, display_func, init};
import glut::{init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send};
import libc::c_uint;
import os::{getenv, setenv};
import task::task_builder;

struct Renderer {
    mut layer: @TiledImageLayer;
    //mut layer: @ImageLayer;
    mut t: f32;
    mut delta: f32;
    mut render_context: option<RenderContext>;
    mut image: option<@Image>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        self.image = none;

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        let (width, height) = (cairo_image.width() as uint, cairo_image.height() as uint);
        let (tile_width, tile_height) = (width / 4, height / 4);
        let cairo_data = cairo_image.data();

        let tiles = dvec();
        for 4.timesi |y| {
            for 4.timesi |x| {
                // Extract the relevant part of the image.
                let data = dvec();

                let mut scanline_start = (y * tile_height * width + x * tile_width) * 4;
                for tile_height.times {
                    for (tile_width * 4).timesi |offset| {
                        data.push(cairo_data[scanline_start + offset]);
                    }

                    scanline_start += width * 4;
                }

                let data = convert_rgb32_to_rgb24(vec::from_mut(dvec::unwrap(data)));
                let image = @Image(tile_width, tile_height, RGB24Format, data);
                self.image = some(image);
                tiles.push(image);
            }
        }

        let tiles = dvec::unwrap(tiles);
        self.layer = @TiledImageLayer(tiles, 4);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        match self.render_context {
            none => {
                self.render_context = some(init_render_context());
            }
            some(_) => {
                // Nothing to do.
            }
        }
        let context = match self.render_context {
            none => fail,
            some(ctx) => ctx
        };

        let t = self.t;
        self.layer.common.transform = Matrix4(400.0f32 * t, 0.0f32,       0.0f32, 0.0f32,
                                              0.0f32,       300.0f32 * t, 0.0f32, 0.0f32,
                                              0.0f32,       0.0f32,       1.0f32, 0.0f32,
                                              0.0f32,       0.0f32,       0.0f32, 1.0f32);

        let mut scene = Scene(TiledImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        //let mut scene = Scene(ImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        render_scene(context, scene);

        //self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::platform_thread);

    let po: port<()> = port();
    let ch = chan(po);
    let _result_ch: chan<()> = do builder.spawn_listener |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(DOUBLE as c_uint);
        let window = create_window(~"Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(30000) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<commit_msg>Fix more breakage<commit_after>use glut;
use azure;
use geom;

import geom::point::Point2D;
import geom::rect::Rect;
import geom::size::Size2D;
import geom::matrix::Matrix4;
import layers::*;
import scene::*;
import rendergl::*;
import util::convert_rgb32_to_rgb24;

import glut::{DOUBLE, check_loop, create_window, destroy_window, display_func, init};
import glut::{init_display_mode, post_redisplay, swap_buffers, timer_func};

import azure::cairo::CAIRO_FORMAT_RGB24;
import CairoContext = azure::cairo_hl::Context;
import azure::azure_hl::{Color, ColorPattern, DrawTarget};
import azure::cairo_hl::ImageSurface;

import comm::{chan, peek, port, recv, send, Port, Chan};
import libc::c_uint;
import os::{getenv, setenv};
import task::TaskBuilder;

struct Renderer {
    mut layer: @TiledImageLayer;
    //mut layer: @ImageLayer;
    mut t: f32;
    mut delta: f32;
    mut render_context: option<RenderContext>;
    mut image: option<@Image>;

    new() {
        let cairo_image = ImageSurface(CAIRO_FORMAT_RGB24, 500, 704);

        self.image = none;

        let draw_target = DrawTarget(cairo_image);
        draw_target.fill_rect(Rect(Point2D(50.0f32, 50.0f32), Size2D(300.0f32, 284.0f32)),
                              ColorPattern(Color(1.0f32, 1.0f32, 0.0f32, 1.0f32)));
        draw_target.flush();

        let (width, height) = (cairo_image.width() as uint, cairo_image.height() as uint);
        let (tile_width, tile_height) = (width / 4, height / 4);
        let cairo_data = cairo_image.data();

        let tiles = dvec();
        for 4.timesi |y| {
            for 4.timesi |x| {
                // Extract the relevant part of the image.
                let data = dvec();

                let mut scanline_start = (y * tile_height * width + x * tile_width) * 4;
                for tile_height.times {
                    for (tile_width * 4).timesi |offset| {
                        data.push(cairo_data[scanline_start + offset]);
                    }

                    scanline_start += width * 4;
                }

                let data = convert_rgb32_to_rgb24(vec::from_mut(dvec::unwrap(data)));
                let image = @Image(tile_width, tile_height, RGB24Format, data);
                self.image = some(image);
                tiles.push(image);
            }
        }

        let tiles = dvec::unwrap(tiles);
        self.layer = @TiledImageLayer(tiles, 4);

        self.t = 1.0f32;
        self.delta = -0.001f32;

        self.render_context = none;
    }

    fn get_display_callback(this: @Renderer) -> fn@() {
        fn@() {
            (*this).display_callback();
        }
    }

    fn display_callback() {
        match self.render_context {
            none => {
                self.render_context = some(init_render_context());
            }
            some(_) => {
                // Nothing to do.
            }
        }
        let context = match self.render_context {
            none => fail,
            some(ctx) => ctx
        };

        let t = self.t;
        self.layer.common.transform = Matrix4(400.0f32 * t, 0.0f32,       0.0f32, 0.0f32,
                                              0.0f32,       300.0f32 * t, 0.0f32, 0.0f32,
                                              0.0f32,       0.0f32,       1.0f32, 0.0f32,
                                              0.0f32,       0.0f32,       0.0f32, 1.0f32);

        let mut scene = Scene(TiledImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        //let mut scene = Scene(ImageLayerKind(self.layer), Size2D(400.0f32, 300.0f32));
        render_scene(context, scene);

        //self.t += self.delta;
        if self.t < 0.0f32 || self.t > 1.0f32 {
            self.delta = -self.delta;
        }

        swap_buffers();

        post_redisplay();
    }
}

#[test]
fn test_triangle_and_square() unsafe {
    let builder = task::task().sched_mode(task::PlatformThread);

    let po: Port<()> = port();
    let ch = chan(po);
    let _result_ch: Chan<()> = do builder.spawn_listener |_po| {
        let renderer = @Renderer();

        init();
        init_display_mode(DOUBLE as c_uint);
        let window = create_window(~"Rust Layers");
        display_func(renderer.get_display_callback(renderer));

        let wakeup = port();
        let wakeup_chan = chan(wakeup);
        do timer_func(30000) {
            send(wakeup_chan, ());
        }

        loop {
            check_loop();

            if peek(wakeup) {
                recv(wakeup);
                send(ch, ());
                destroy_window(window);
                break;
            }
        }

        send(ch, ());
    };

    recv(po);
}

<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Based off of libcss's examples/example1.c
mod example1 {

    use CssResult;
    use CssProperty;
    use types::*;
    use hint::*;
    use select::*;
    use util::VoidPtrLike;
    use wapcaplet::LwcString;
    use std::libc;
    use std::cast;

    struct MyDomNode {
        name: @LwcString
    }

    impl VoidPtrLike for MyDomNode {
        fn from_void_ptr(node: *libc::c_void) -> MyDomNode {
            assert!(node.is_not_null());
            MyDomNode {
                name: unsafe {
                    let box = cast::transmute(node);
                    cast::bump_box_refcount(box);
                    box
                }
            }
        }

        fn to_void_ptr(&self) -> *libc::c_void {
            unsafe { cast::transmute(self.name) }
        }
    }

    #[test]
    fn run() {
        use super::super::stylesheet::{CssUrlResolutionFn, CssStylesheetParams, CssStylesheet,
                                       css_stylesheet_create, CssStylesheetParamsVersion1};
        use super::super::computed::CssComputedStyle;
        use super::super::values::{CssColorColor, CssColorInherit};
        use super::super::ll::types::{CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, CSS_MEDIA_SCREEN};
        use super::super::conversions::ToLl;
        use wapcaplet::{LwcString, from_rust_string};

        let data = "h1 { color: red; }\
                    h4 { color: #321; }\
                    h4, h5 { color: #123456; }";

        let resolve: CssUrlResolutionFn = |a,b| resolve_url(a, b);

        let params: CssStylesheetParams = CssStylesheetParams {
            params_version: CssStylesheetParamsVersion1,
            level: CssLevel21,
            charset: ~"UTF-8",
            url: ~"foo",
            title: ~"foo",
            allow_quirks: false,
            inline_style: false,
            resolve: Some(resolve),
            import: None,
            color: None,
            font: None,
        };

        let mut sheet: CssStylesheet = css_stylesheet_create(&params);
        debug!("stylesheet: %?", sheet);
        debug!("stylesheet size: %?", sheet.size());

        sheet.append_data(data.as_bytes().to_owned());
        sheet.data_done();
        debug!("stylesheet size: %?", sheet.size());

        let mut select_ctx: CssSelectCtx = css_select_ctx_create();
        assert!(select_ctx.count_sheets() == 0);
        select_ctx.append_sheet(sheet, CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL);
        debug!("count sheets: %?", select_ctx.count_sheets());
        assert!(select_ctx.count_sheets() == 1);

        for hh in range(1, 7) {
            let element = fmt!("h%u", hh);
            let element_name: @LwcString = @from_rust_string(element);
            let node = MyDomNode { name: element_name };
            let select_handler = SelectHandler { bogus: () };
            let style: CssSelectResults = select_ctx.select_style(&node,
                                                                  CSS_MEDIA_SCREEN,
                                                                  None,
                                                                  &select_handler);

            let computed: CssComputedStyle = style.computed_style(CssPseudoElementNone);

            match computed.color() {
                CssColorInherit => {
                    debug!("color of h%u is 'inherit'", hh);
                }
                CssColorColor(color) => {
                    debug!("color of h%u is %x", hh, color.to_ll() as uint);
                }
            }
        }
    }

    fn resolve_url(_base: &str, _rel: &LwcString) -> CssResult<LwcString> {
        fail!(~"resolving url");
    }

    struct SelectHandler {
        bogus: ()
    }

    impl CssSelectHandler<MyDomNode> for SelectHandler {
        fn node_name(&self, node: &MyDomNode) -> CssQName {
            debug!("HL node_name!");
            debug!("SS %?", (*node.name).to_str());

            CssQName {
                ns: None,
                name: (*node.name).clone()
            }
        }

        fn node_classes(&self, _node: &MyDomNode) -> Option<~[LwcString]> { None }

        fn node_id(&self, _node: &MyDomNode) -> Option<LwcString> { None }

        fn named_parent_node(&self, _node: &MyDomNode, _qname: &CssQName) -> Option<MyDomNode> {
            None
        }

        fn parent_node(&self, _node: &MyDomNode) -> Option<MyDomNode> {
            None
        }

        fn node_has_class(&self, _node: &MyDomNode, _name: LwcString) -> bool { false }

        fn node_has_id(&self, _node: &MyDomNode, _name: LwcString) -> bool { false }

        fn named_ancestor_node(&self, _node: &MyDomNode, _qname: &CssQName) -> Option<MyDomNode> {
            None
        }

        fn node_is_root(&self, _node: &MyDomNode) -> bool { false }

        fn node_is_link(&self, _node: &MyDomNode) -> bool { false }

        fn node_is_visited(&self, _node: &MyDomNode) -> bool { false }

        fn ua_default_for_property(&self, property: CssProperty) -> CssHint {
            match property {
                _ => CssHintDefault
            }
        }
    }
}

#[test]
fn test_arc() {
    use extra::arc::ARC;
    use stylesheet::*;
    use types::CssLevel21;
    use wapcaplet::LwcString;
    use super::CssResult;

    let resolve: CssUrlResolutionFn = |a,b| resolve_url(a, b);
    let params: CssStylesheetParams = CssStylesheetParams {
        params_version: CssStylesheetParamsVersion1,
        level: CssLevel21,
        charset: ~"UTF-8",
        url: ~"foo",
        title: ~"foo",
        allow_quirks: false,
        inline_style: false,
        resolve: Some(resolve),
        import: None,
        color: None,
        font: None,
    };

    let sheet: CssStylesheet = css_stylesheet_create(&params);
    let _arc = ARC(sheet);

    fn resolve_url(_base: &str, _rel: &LwcString) -> CssResult<LwcString> {
        fail!(~"resolving url");
    }
}
<commit_msg>Update tests for new Rust<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Based off of libcss's examples/example1.c
mod example1 {

    use CssResult;
    use CssProperty;
    use types::*;
    use hint::*;
    use select::*;
    use util::VoidPtrLike;
    use wapcaplet::LwcString;
    use std::libc;
    use std::cast;

    struct MyDomNode {
        name: @LwcString
    }

    impl VoidPtrLike for MyDomNode {
        fn from_void_ptr(node: *libc::c_void) -> MyDomNode {
            assert!(node.is_not_null());
            MyDomNode {
                name: unsafe {
                    let box = cast::transmute(node);
                    cast::bump_box_refcount(box);
                    box
                }
            }
        }

        fn to_void_ptr(&self) -> *libc::c_void {
            unsafe { cast::transmute(self.name) }
        }
    }

    #[test]
    fn run() {
        use super::super::stylesheet::{CssUrlResolutionFn, CssStylesheetParams, CssStylesheet,
                                       css_stylesheet_create, CssStylesheetParamsVersion1};
        use super::super::computed::CssComputedStyle;
        use super::super::values::{CssColorColor, CssColorInherit};
        use super::super::ll::types::{CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL, CSS_MEDIA_SCREEN};
        use super::super::conversions::ToLl;
        use wapcaplet::{LwcString, from_rust_string};

        let data = "h1 { color: red; }\
                    h4 { color: #321; }\
                    h4, h5 { color: #123456; }";

        let resolve: CssUrlResolutionFn = |a,b| resolve_url(a, b);

        let params: CssStylesheetParams = CssStylesheetParams {
            params_version: CssStylesheetParamsVersion1,
            level: CssLevel21,
            charset: ~"UTF-8",
            url: ~"foo",
            title: ~"foo",
            allow_quirks: false,
            inline_style: false,
            resolve: Some(resolve),
            import: None,
            color: None,
            font: None,
        };

        let mut sheet: CssStylesheet = css_stylesheet_create(&params);
        debug!("stylesheet: %?", sheet);
        debug!("stylesheet size: %?", sheet.size());

        sheet.append_data(data.as_bytes().to_owned());
        sheet.data_done();
        debug!("stylesheet size: %?", sheet.size());

        let mut select_ctx: CssSelectCtx = css_select_ctx_create();
        assert!(select_ctx.count_sheets() == 0);
        select_ctx.append_sheet(sheet, CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL);
        debug!("count sheets: %?", select_ctx.count_sheets());
        assert!(select_ctx.count_sheets() == 1);

        for hh in range(1u, 7u) {
            let element = fmt!("h%u", hh);
            let element_name: @LwcString = @from_rust_string(element);
            let node = MyDomNode { name: element_name };
            let select_handler = SelectHandler { bogus: () };
            let style: CssSelectResults = select_ctx.select_style(&node,
                                                                  CSS_MEDIA_SCREEN,
                                                                  None,
                                                                  &select_handler);

            let computed: CssComputedStyle = style.computed_style(CssPseudoElementNone);

            match computed.color() {
                CssColorInherit => {
                    debug!("color of h%u is 'inherit'", hh);
                }
                CssColorColor(color) => {
                    debug!("color of h%u is %x", hh, color.to_ll() as uint);
                }
            }
        }
    }

    fn resolve_url(_base: &str, _rel: &LwcString) -> CssResult<LwcString> {
        fail!(~"resolving url");
    }

    struct SelectHandler {
        bogus: ()
    }

    impl CssSelectHandler<MyDomNode> for SelectHandler {
        fn node_name(&self, node: &MyDomNode) -> CssQName {
            debug!("HL node_name!");
            debug!("SS %?", (*node.name).to_str());

            CssQName {
                ns: None,
                name: (*node.name).clone()
            }
        }

        fn node_classes(&self, _node: &MyDomNode) -> Option<~[LwcString]> { None }

        fn node_id(&self, _node: &MyDomNode) -> Option<LwcString> { None }

        fn named_parent_node(&self, _node: &MyDomNode, _qname: &CssQName) -> Option<MyDomNode> {
            None
        }

        fn parent_node(&self, _node: &MyDomNode) -> Option<MyDomNode> {
            None
        }

        fn node_has_class(&self, _node: &MyDomNode, _name: LwcString) -> bool { false }

        fn node_has_id(&self, _node: &MyDomNode, _name: LwcString) -> bool { false }

        fn named_ancestor_node(&self, _node: &MyDomNode, _qname: &CssQName) -> Option<MyDomNode> {
            None
        }

        fn node_is_root(&self, _node: &MyDomNode) -> bool { false }

        fn node_is_link(&self, _node: &MyDomNode) -> bool { false }

        fn node_is_visited(&self, _node: &MyDomNode) -> bool { false }

        fn ua_default_for_property(&self, property: CssProperty) -> CssHint {
            match property {
                _ => CssHintDefault
            }
        }
    }
}

#[test]
fn test_arc() {
    use extra::arc::Arc;
    use stylesheet::*;
    use types::CssLevel21;
    use wapcaplet::LwcString;
    use super::CssResult;

    let resolve: CssUrlResolutionFn = |a,b| resolve_url(a, b);
    let params: CssStylesheetParams = CssStylesheetParams {
        params_version: CssStylesheetParamsVersion1,
        level: CssLevel21,
        charset: ~"UTF-8",
        url: ~"foo",
        title: ~"foo",
        allow_quirks: false,
        inline_style: false,
        resolve: Some(resolve),
        import: None,
        color: None,
        font: None,
    };

    let sheet: CssStylesheet = css_stylesheet_create(&params);
    let _arc = Arc::new(sheet);

    fn resolve_url(_base: &str, _rel: &LwcString) -> CssResult<LwcString> {
        fail!(~"resolving url");
    }
}
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * kit/kernel/paging/mod.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 ******************************************************************************/

//! Kernel page management.

use core::prelude::*;
use core::cell::*;

use memory::{Box, Rc};
use memory::rc::Contents as RcContents;

pub mod generic;

pub use self::generic::Pageset as GenericPageset;
pub use self::generic::{PageType, PagesetExt};

#[cfg(any(doc, target_arch = "x86_64"))]
pub mod x86_64;

#[cfg(target_arch = "x86_64")]
pub use self::x86_64 as target;

pub use self::target::{Pageset, Error};

static mut INITIALIZED: bool = false;

static mut KERNEL_PAGESET: Option<*mut Pageset> = None;

static mut CURRENT_PAGESET: Option<*mut RcContents<RefCell<Pageset>>> = None;

/// # Safety
///
/// Modifying or making assumptions about the kernel pageset can result in
/// system instability, data loss, and/or pointer aliasing.
///
/// Simultaneous (aliased) access to the kernel pageset is allowed, because it's
/// necessary. As such, it isn't wrapped in a RefCell.
pub unsafe fn kernel_pageset() -> &'static mut Pageset {
    &mut *KERNEL_PAGESET.expect("paging not initialized")
}

/// # Safety
///
/// Modifying or making assumptions about the current pageset without checking
/// what the current pageset belongs to (i.e., the current process) is
/// dangerous.
pub unsafe fn current_pageset() -> Option<Rc<RefCell<Pageset>>> {
    CURRENT_PAGESET.map(|ptr| {
        let rc1 = Rc::from_raw(ptr);
        let rc2 = rc1.clone();
        let _   = rc1.into_raw();

        rc2
    })
}

/// # Safety
///
/// `process` assumes that the current pageset is the current process's pageset,
/// and that if there is no current process, the kernel pageset is active.
pub unsafe fn set_current_pageset(pageset: Option<Rc<RefCell<Pageset>>>) {
    let old = CURRENT_PAGESET.map(|ptr| Rc::from_raw(ptr));

    if let Some(pageset) = pageset {
        pageset.borrow_mut().load_into_hw();

        CURRENT_PAGESET = Some(pageset.into_raw());
    } else {
        kernel_pageset().load_into_hw();

        CURRENT_PAGESET = None;
    }

    drop(old); // explicitly drop it here
}

pub fn initialized() -> bool {
    unsafe { INITIALIZED }
}

/// Call this on system initialization.
pub unsafe fn initialize() {
    if INITIALIZED {
        panic!("paging already initialized");
    }

    KERNEL_PAGESET = Some(Box::new(Pageset::new_kernel()).into_raw());

    assert!(kernel_pageset().lookup(initialized as usize).is_some());

    kernel_pageset().load_into_hw();

    INITIALIZED     = true;
}

/// C interface. See `kit/kernel/include/paging.h`.
pub mod ffi {
    use core::prelude::*;
    use core::cell::*;
    use core::iter::{iterate, repeat};
    use core::default::Default;
    use core::ptr;

    use libc::c_void;

    use memory::Rc;
    use memory::rc::Contents as RcContents;

    use super::*;

    pub type PagesetCRef = *mut RcContents<RefCell<Pageset>>;

    fn from_flags(flags: u8) -> PageType {
        let readonly   = 0x01;
        let user       = 0x02;
        let executable = 0x04;

        let mut page_type = PageType::default();

        if flags & readonly   == 0 { page_type = page_type.writable(); }
        if flags & user       != 0 { page_type = page_type.user(); }
        if flags & executable != 0 { page_type = page_type.executable(); }

        page_type
    }

    fn to_flags(page_type: PageType) -> u8 {
        let readonly   = 0x01;
        let user       = 0x02;
        let executable = 0x04;

        let mut flags = 0;

        if !page_type.is_writable()   { flags |= readonly; }
        if  page_type.is_user()       { flags |= user; }
        if  page_type.is_executable() { flags |= executable; }

        flags
    }

    fn to_page_count(result: Result<(), Error>,
                     vaddr:  usize,
                     pages:  usize) -> u64 {
        use super::Error::*;

        let page_size = Pageset::page_size();

        (match result {
            Err(OutOfKernelRange(last_vaddr)) =>
                (last_vaddr - vaddr) / page_size,
            Err(OutOfUserRange(last_vaddr)) =>
                (last_vaddr - vaddr) / page_size,
            Ok(()) =>
                pages
        }) as u64
    }

    unsafe fn unpack(pageset: PagesetCRef) -> Option<Rc<RefCell<Pageset>>> {
        if pageset.is_null() {
            None
        } else {
            let rc1 = Rc::from_raw(pageset);
            let rc2 = rc1.clone();
            let _   = rc1.into_raw();

            Some(rc2)
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_create_pageset(pageset: *mut PagesetCRef) {
        *pageset = Pageset::alloc().into_raw();
    }

    #[no_mangle]
    pub unsafe extern fn paging_clone_ref(pageset: PagesetCRef) -> PagesetCRef {
        if pageset.is_null() {
            pageset
        } else {
            let rc1 = Rc::from_raw(pageset);
            let rc2 = rc1.clone();
            let _   = rc1.into_raw();

            rc2.into_raw()
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_drop_ref(pageset: *mut PagesetCRef) {
        if !(*pageset).is_null() {
            drop(Rc::from_raw(*pageset));

            *pageset = 0xdead as PagesetCRef; // to make it obvious if used
        }
    }

    #[no_mangle]
    pub unsafe extern fn
        paging_resolve_linear_address(pageset: PagesetCRef,
                                      linear_address: *const c_void,
                                      physical_address: *mut u64) -> i8 {
        let pageset = unpack(pageset);
        let pageset = pageset.as_ref().map(|x| x.borrow());
        let pageset = pageset.as_ref().map(|x| &**x)
                                      .unwrap_or(kernel_pageset());
        let vaddr   = linear_address as usize;

        if let Some(paddr) = pageset.lookup(vaddr) {
            *physical_address = paddr as u64;
            1
        } else {
            0
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_map(pageset: PagesetCRef,
                                    linear_address: *const c_void,
                                    physical_address: u64,
                                    pages: u64,
                                    flags: u8) -> u64 {
        let pageset     = unpack(pageset);
        let mut pageset = pageset.as_ref().map(|x| x.borrow_mut());
        let pageset     = pageset.as_mut().map(|x| &mut **x)
                                          .unwrap_or(kernel_pageset());

        let vaddr       = linear_address as usize;
        let paddr       = physical_address as usize;
        let pages       = pages as usize;
        let page_size   = Pageset::page_size();

        to_page_count(
            pageset.map_pages_with_type(
                vaddr,
                iterate(paddr, |paddr| paddr + page_size).take(pages),
                from_flags(flags)),
            vaddr, pages)
    }

    #[no_mangle]
    pub unsafe extern fn paging_unmap(pageset: PagesetCRef,
                                      linear_address: *const c_void,
                                      pages: u64) -> u64 {
        let pageset     = unpack(pageset);
        let mut pageset = pageset.as_ref().map(|x| x.borrow_mut());
        let pageset     = pageset.as_mut().map(|x| &mut **x)
                                          .unwrap_or(kernel_pageset());

        let vaddr       = linear_address as usize;
        let pages       = pages as usize;

        to_page_count(pageset.unmap_pages(vaddr, pages), vaddr, pages)
    }

    #[no_mangle]
    pub unsafe extern fn paging_get_flags(pageset: PagesetCRef,
                                          linear_address: *const c_void,
                                          flags: *mut u8) -> i8 {
        let pageset = unpack(pageset);
        let pageset = pageset.as_ref().map(|x| x.borrow());
        let pageset = pageset.as_ref().map(|x| &**x)
                                      .unwrap_or(kernel_pageset());

        let vaddr   = linear_address as usize;

        if let Some((_, page_type)) = pageset.get(vaddr) {
            *flags = to_flags(page_type);
            1
        } else {
            0
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_set_flags(pageset: PagesetCRef,
                                          linear_address: *const c_void,
                                          pages: u64,
                                          flags: u8) -> u64 {
        let pageset     = unpack(pageset);
        let mut pageset = pageset.as_ref().map(|x| x.borrow_mut());
        let pageset     = pageset.as_mut().map(|x| &mut **x)
                                          .unwrap_or(kernel_pageset());

        let vaddr       = linear_address as usize;
        let pages       = pages as usize;

        to_page_count(
            pageset.set_page_types(vaddr,
                                   repeat(from_flags(flags)).take(pages)),
            vaddr, pages)
    }

    #[no_mangle]
    pub unsafe extern fn paging_get_current_pageset() -> PagesetCRef {
        let null: *const RcContents<RefCell<Pageset>> = ptr::null();
        let null = null as PagesetCRef;

        current_pageset().map(|p| p.into_raw()).unwrap_or(null)
    }

    #[no_mangle]
    pub unsafe extern fn paging_set_current_pageset(pageset: PagesetCRef) {
        set_current_pageset(unpack(pageset));
    }
}
<commit_msg>[kernel::paging] type RcPageset = Rc<RefCell<Pageset>><commit_after>/*******************************************************************************
 *
 * kit/kernel/paging/mod.rs
 *
 * vim:ft=rust:ts=4:sw=4:et:tw=80
 *
 * Copyright (C) 2015, Devyn Cairns
 * Redistribution of this file is permitted under the terms of the simplified
 * BSD license. See LICENSE for more information.
 *
 ******************************************************************************/

//! Kernel page management.

use core::prelude::*;
use core::cell::*;

use memory::{Box, Rc};
use memory::rc::Contents as RcContents;

pub mod generic;

pub use self::generic::Pageset as GenericPageset;
pub use self::generic::{PageType, PagesetExt};

#[cfg(any(doc, target_arch = "x86_64"))]
pub mod x86_64;

#[cfg(target_arch = "x86_64")]
pub use self::x86_64 as target;

pub use self::target::{Pageset, Error};

static mut INITIALIZED: bool = false;

static mut KERNEL_PAGESET: Option<*mut Pageset> = None;

static mut CURRENT_PAGESET: Option<*mut RcContents<RefCell<Pageset>>> = None;

/// A reference-counted, shared pageset.
///
/// This is required in order to be able to set a pageset as the current
/// pageset, because we need to be able to guarantee that it will still be valid
/// while the hardware is using it.
pub type RcPageset = Rc<RefCell<Pageset>>;

/// # Safety
///
/// Modifying or making assumptions about the kernel pageset can result in
/// system instability, data loss, and/or pointer aliasing.
///
/// Simultaneous (aliased) access to the kernel pageset is allowed, because it's
/// necessary. As such, it isn't wrapped in a RefCell.
pub unsafe fn kernel_pageset() -> &'static mut Pageset {
    &mut *KERNEL_PAGESET.expect("paging not initialized")
}

/// # Safety
///
/// Modifying or making assumptions about the current pageset without checking
/// what the current pageset belongs to (i.e., the current process) is
/// dangerous.
pub unsafe fn current_pageset() -> Option<RcPageset> {
    CURRENT_PAGESET.map(|ptr| {
        let rc1 = Rc::from_raw(ptr);
        let rc2 = rc1.clone();
        let _   = rc1.into_raw();

        rc2
    })
}

/// # Safety
///
/// `process` assumes that the current pageset is the current process's pageset,
/// and that if there is no current process, the kernel pageset is active.
pub unsafe fn set_current_pageset(pageset: Option<RcPageset>) {
    let old = CURRENT_PAGESET.map(|ptr| Rc::from_raw(ptr));

    if let Some(pageset) = pageset {
        pageset.borrow_mut().load_into_hw();

        CURRENT_PAGESET = Some(pageset.into_raw());
    } else {
        kernel_pageset().load_into_hw();

        CURRENT_PAGESET = None;
    }

    drop(old); // explicitly drop it here
}

pub fn initialized() -> bool {
    unsafe { INITIALIZED }
}

/// Call this on system initialization.
pub unsafe fn initialize() {
    if INITIALIZED {
        panic!("paging already initialized");
    }

    KERNEL_PAGESET = Some(Box::new(Pageset::new_kernel()).into_raw());

    assert!(kernel_pageset().lookup(initialized as usize).is_some());

    kernel_pageset().load_into_hw();

    INITIALIZED     = true;
}

/// C interface. See `kit/kernel/include/paging.h`.
pub mod ffi {
    use core::prelude::*;
    use core::cell::*;
    use core::iter::{iterate, repeat};
    use core::default::Default;
    use core::ptr;

    use libc::c_void;

    use memory::Rc;
    use memory::rc::Contents as RcContents;

    use super::*;

    pub type PagesetCRef = *mut RcContents<RefCell<Pageset>>;

    fn from_flags(flags: u8) -> PageType {
        let readonly   = 0x01;
        let user       = 0x02;
        let executable = 0x04;

        let mut page_type = PageType::default();

        if flags & readonly   == 0 { page_type = page_type.writable(); }
        if flags & user       != 0 { page_type = page_type.user(); }
        if flags & executable != 0 { page_type = page_type.executable(); }

        page_type
    }

    fn to_flags(page_type: PageType) -> u8 {
        let readonly   = 0x01;
        let user       = 0x02;
        let executable = 0x04;

        let mut flags = 0;

        if !page_type.is_writable()   { flags |= readonly; }
        if  page_type.is_user()       { flags |= user; }
        if  page_type.is_executable() { flags |= executable; }

        flags
    }

    fn to_page_count(result: Result<(), Error>,
                     vaddr:  usize,
                     pages:  usize) -> u64 {
        use super::Error::*;

        let page_size = Pageset::page_size();

        (match result {
            Err(OutOfKernelRange(last_vaddr)) =>
                (last_vaddr - vaddr) / page_size,
            Err(OutOfUserRange(last_vaddr)) =>
                (last_vaddr - vaddr) / page_size,
            Ok(()) =>
                pages
        }) as u64
    }

    unsafe fn unpack(pageset: PagesetCRef) -> Option<RcPageset> {
        if pageset.is_null() {
            None
        } else {
            let rc1 = Rc::from_raw(pageset);
            let rc2 = rc1.clone();
            let _   = rc1.into_raw();

            Some(rc2)
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_create_pageset(pageset: *mut PagesetCRef) {
        *pageset = Pageset::alloc().into_raw();
    }

    #[no_mangle]
    pub unsafe extern fn paging_clone_ref(pageset: PagesetCRef) -> PagesetCRef {
        if pageset.is_null() {
            pageset
        } else {
            let rc1 = Rc::from_raw(pageset);
            let rc2 = rc1.clone();
            let _   = rc1.into_raw();

            rc2.into_raw()
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_drop_ref(pageset: *mut PagesetCRef) {
        if !(*pageset).is_null() {
            drop(Rc::from_raw(*pageset));

            *pageset = 0xdead as PagesetCRef; // to make it obvious if used
        }
    }

    #[no_mangle]
    pub unsafe extern fn
        paging_resolve_linear_address(pageset: PagesetCRef,
                                      linear_address: *const c_void,
                                      physical_address: *mut u64) -> i8 {
        let pageset = unpack(pageset);
        let pageset = pageset.as_ref().map(|x| x.borrow());
        let pageset = pageset.as_ref().map(|x| &**x)
                                      .unwrap_or(kernel_pageset());
        let vaddr   = linear_address as usize;

        if let Some(paddr) = pageset.lookup(vaddr) {
            *physical_address = paddr as u64;
            1
        } else {
            0
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_map(pageset: PagesetCRef,
                                    linear_address: *const c_void,
                                    physical_address: u64,
                                    pages: u64,
                                    flags: u8) -> u64 {
        let pageset     = unpack(pageset);
        let mut pageset = pageset.as_ref().map(|x| x.borrow_mut());
        let pageset     = pageset.as_mut().map(|x| &mut **x)
                                          .unwrap_or(kernel_pageset());

        let vaddr       = linear_address as usize;
        let paddr       = physical_address as usize;
        let pages       = pages as usize;
        let page_size   = Pageset::page_size();

        to_page_count(
            pageset.map_pages_with_type(
                vaddr,
                iterate(paddr, |paddr| paddr + page_size).take(pages),
                from_flags(flags)),
            vaddr, pages)
    }

    #[no_mangle]
    pub unsafe extern fn paging_unmap(pageset: PagesetCRef,
                                      linear_address: *const c_void,
                                      pages: u64) -> u64 {
        let pageset     = unpack(pageset);
        let mut pageset = pageset.as_ref().map(|x| x.borrow_mut());
        let pageset     = pageset.as_mut().map(|x| &mut **x)
                                          .unwrap_or(kernel_pageset());

        let vaddr       = linear_address as usize;
        let pages       = pages as usize;

        to_page_count(pageset.unmap_pages(vaddr, pages), vaddr, pages)
    }

    #[no_mangle]
    pub unsafe extern fn paging_get_flags(pageset: PagesetCRef,
                                          linear_address: *const c_void,
                                          flags: *mut u8) -> i8 {
        let pageset = unpack(pageset);
        let pageset = pageset.as_ref().map(|x| x.borrow());
        let pageset = pageset.as_ref().map(|x| &**x)
                                      .unwrap_or(kernel_pageset());

        let vaddr   = linear_address as usize;

        if let Some((_, page_type)) = pageset.get(vaddr) {
            *flags = to_flags(page_type);
            1
        } else {
            0
        }
    }

    #[no_mangle]
    pub unsafe extern fn paging_set_flags(pageset: PagesetCRef,
                                          linear_address: *const c_void,
                                          pages: u64,
                                          flags: u8) -> u64 {
        let pageset     = unpack(pageset);
        let mut pageset = pageset.as_ref().map(|x| x.borrow_mut());
        let pageset     = pageset.as_mut().map(|x| &mut **x)
                                          .unwrap_or(kernel_pageset());

        let vaddr       = linear_address as usize;
        let pages       = pages as usize;

        to_page_count(
            pageset.set_page_types(vaddr,
                                   repeat(from_flags(flags)).take(pages)),
            vaddr, pages)
    }

    #[no_mangle]
    pub unsafe extern fn paging_get_current_pageset() -> PagesetCRef {
        let null: *const RcContents<RefCell<Pageset>> = ptr::null();
        let null = null as PagesetCRef;

        current_pageset().map(|p| p.into_raw()).unwrap_or(null)
    }

    #[no_mangle]
    pub unsafe extern fn paging_set_current_pageset(pageset: PagesetCRef) {
        set_current_pageset(unpack(pageset));
    }
}
<|endoftext|>


<commit_before>use crate::{prelude::SignedBlock, serializer::*};
use std::convert::{TryFrom, TryInto};
use std::io::{self, Cursor, Error, Read};

#[repr(u8)]
pub enum MsgType {
    Error = 0,
    GetBlock = 1,
}

pub enum MsgRequest {
    GetBlock(u64), // height
}

impl MsgRequest {
    pub fn serialize(self) -> Vec<u8> {
        match self {
            MsgRequest::GetBlock(height) => {
                let mut buf = Vec::with_capacity(9);
                buf.push(MsgType::GetBlock as u8);
                buf.push_u64(height);
                buf
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::GetBlock as u8 => {
                let height = cursor.take_u64()?;
                Ok(MsgRequest::GetBlock(height))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg request",
            )),
        }
    }
}

#[derive(Copy, Clone, Debug)]
#[repr(u16)]
pub enum ErrorKind {
    UnknownError = 0,
    InvalidHeight = 1,
}

impl TryFrom<u16> for ErrorKind {
    type Error = Error;

    fn try_from(value: u16) -> Result<ErrorKind, Error> {
        match value {
            e if e == ErrorKind::UnknownError as u16 => Ok(ErrorKind::UnknownError),
            e if e == ErrorKind::InvalidHeight as u16 => Ok(ErrorKind::InvalidHeight),
            _ => Err(Error::new(io::ErrorKind::InvalidData, "unknown error kind")),
        }
    }
}

#[derive(Clone, Debug)]
pub enum MsgResponse {
    Error(ErrorKind, Option<String>), // code, message
    GetBlock(SignedBlock),
}

impl MsgResponse {
    pub fn serialize(self) -> Vec<u8> {
        match self {
            MsgResponse::Error(code, msg) => match msg {
                Some(msg) => {
                    let mut buf = Vec::with_capacity(3 + msg.len());
                    buf.push(MsgType::Error as u8);
                    buf.push_u16(code as u16);
                    buf.push_bytes(msg.as_bytes());
                    buf
                }
                None => {
                    let mut buf = Vec::with_capacity(7);
                    buf.push(MsgType::Error as u8);
                    buf.push_u16(code as u16);
                    buf.push_bytes(&[]);
                    buf
                }
            },
            MsgResponse::GetBlock(block) => {
                let mut buf = Vec::with_capacity(1_048_576);
                buf.push(MsgType::GetBlock as u8);
                block.encode_with_tx(&mut buf);
                buf
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::Error as u8 => {
                let kind = cursor.take_u16()?.try_into()?;
                let msg = {
                    let mut buf = Vec::with_capacity(1024);
                    let read = cursor.read_to_end(&mut buf)?;
                    if read > 0 {
                        Some(String::from_utf8_lossy(&buf).into_owned())
                    } else {
                        None
                    }
                };
                Ok(MsgResponse::Error(kind, msg))
            }
            t if t == MsgType::GetBlock as u8 => {
                let block = SignedBlock::decode_with_tx(cursor)
                    .ok_or_else(|| Error::from(io::ErrorKind::UnexpectedEof))?;
                Ok(MsgResponse::GetBlock(block))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg response",
            )),
        }
    }
}
<commit_msg>Fix error response message deserialization<commit_after>use crate::{prelude::SignedBlock, serializer::*};
use std::convert::{TryFrom, TryInto};
use std::io::{self, Cursor, Error};

#[repr(u8)]
pub enum MsgType {
    Error = 0,
    GetBlock = 1,
}

pub enum MsgRequest {
    GetBlock(u64), // height
}

impl MsgRequest {
    pub fn serialize(self) -> Vec<u8> {
        match self {
            MsgRequest::GetBlock(height) => {
                let mut buf = Vec::with_capacity(9);
                buf.push(MsgType::GetBlock as u8);
                buf.push_u64(height);
                buf
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::GetBlock as u8 => {
                let height = cursor.take_u64()?;
                Ok(MsgRequest::GetBlock(height))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg request",
            )),
        }
    }
}

#[derive(Copy, Clone, Debug)]
#[repr(u16)]
pub enum ErrorKind {
    UnknownError = 0,
    InvalidHeight = 1,
}

impl TryFrom<u16> for ErrorKind {
    type Error = Error;

    fn try_from(value: u16) -> Result<ErrorKind, Error> {
        match value {
            e if e == ErrorKind::UnknownError as u16 => Ok(ErrorKind::UnknownError),
            e if e == ErrorKind::InvalidHeight as u16 => Ok(ErrorKind::InvalidHeight),
            _ => Err(Error::new(io::ErrorKind::InvalidData, "unknown error kind")),
        }
    }
}

#[derive(Clone, Debug)]
pub enum MsgResponse {
    Error(ErrorKind, Option<String>), // code, message
    GetBlock(SignedBlock),
}

impl MsgResponse {
    pub fn serialize(self) -> Vec<u8> {
        match self {
            MsgResponse::Error(code, msg) => match msg {
                Some(msg) => {
                    let mut buf = Vec::with_capacity(3 + msg.len());
                    buf.push(MsgType::Error as u8);
                    buf.push_u16(code as u16);
                    buf.push_bytes(msg.as_bytes());
                    buf
                }
                None => {
                    let mut buf = Vec::with_capacity(7);
                    buf.push(MsgType::Error as u8);
                    buf.push_u16(code as u16);
                    buf.push_bytes(&[]);
                    buf
                }
            },
            MsgResponse::GetBlock(block) => {
                let mut buf = Vec::with_capacity(1_048_576);
                buf.push(MsgType::GetBlock as u8);
                block.encode_with_tx(&mut buf);
                buf
            }
        }
    }

    pub fn deserialize(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
        let tag = cursor.take_u8()?;
        match tag {
            t if t == MsgType::Error as u8 => {
                let kind = cursor.take_u16()?.try_into()?;
                let msg = {
                    let buf = cursor.take_bytes()?;
                    if buf.len() > 0 {
                        Some(String::from_utf8_lossy(&buf).into_owned())
                    } else {
                        None
                    }
                };
                Ok(MsgResponse::Error(kind, msg))
            }
            t if t == MsgType::GetBlock as u8 => {
                let block = SignedBlock::decode_with_tx(cursor)
                    .ok_or_else(|| Error::from(io::ErrorKind::UnexpectedEof))?;
                Ok(MsgResponse::GetBlock(block))
            }
            _ => Err(Error::new(
                io::ErrorKind::InvalidData,
                "invalid msg response",
            )),
        }
    }
}
<|endoftext|>


<commit_before>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;

use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::env;

fn string(s: &str) -> TokenTree {
    Literal::string(s).into()
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
    if tokens.len() != 3 {
        panic!("expected #[simd_test(enable = \"feature\")]");
    }
    match &tokens[0] {
        TokenTree::Ident(tt) if *tt == "enable" => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    match &tokens[1] {
        TokenTree::Punct(tt) if tt.as_char() == '=' => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    let enable_feature = match &tokens[2] {
        TokenTree::Literal(tt) => tt.to_string(),
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    };
    let enable_feature = enable_feature.trim_start_matches('"').trim_end_matches('"');
    let target_features: Vec<String> = enable_feature
        .replace('+', "")
        .split(',')
        .map(String::from)
        .collect();

    let enable_feature = string(enable_feature);
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name
        .to_string()
        .parse()
        .unwrap_or_else(|_| panic!("failed to parse name: {}", name.to_string()));

    let target = env::var("TARGET").expect("TARGET environment variable should be set for rustc");
    let mut force_test = false;
    let macro_test = match target
        .split('-')
        .next()
        .unwrap_or_else(|| panic!("target triple contained no \"-\": {}", target))
    {
        "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
        "arm" | "armv7" => "is_arm_feature_detected",
        "aarch64" => "is_aarch64_feature_detected",
        "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
        "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
        "mips" | "mipsel" => {
            // FIXME:
            // On MIPS CI run-time feature detection always returns false due
            // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
            //
            // This is a workaround to force the MIPS tests to always run on
            // CI.
            force_test = true;
            "is_mips_feature_detected"
        }
        "mips64" | "mips64el" => {
            // FIXME: see above
            force_test = true;
            "is_mips64_feature_detected"
        }
        t => panic!("unknown target: {}", t),
    };
    let macro_test = Ident::new(macro_test, Span::call_site());

    let mut cfg_target_features = TokenStream::new();
    for feature in target_features {
        let q = quote_spanned! {
            proc_macro2::Span::call_site() =>
            #macro_test!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote! { true };
    q.to_tokens(&mut cfg_target_features);

    let test_norun = std::env::var("STDSIMD_TEST_NORUN").is_ok();
    let maybe_ignore = if test_norun {
        quote! { #[ignore] }
    } else {
        TokenStream::new()
    };

    let ret: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[allow(non_snake_case)]
        #[test]
        #maybe_ignore
        fn #name() {
            if #force_test | (#cfg_target_features) {
                return unsafe { #name() };
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature(enable = #enable_feature)]
            #item
        }
    };
    ret.into()
}

fn find_name(item: TokenStream) -> Ident {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenTree::Ident(word) = tok {
            if word == "fn" {
                break;
            }
        }
    }

    match tokens.next() {
        Some(TokenTree::Ident(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<commit_msg>Automatically insert emms after running each MMX test<commit_after>//! Implementation of the `#[simd_test]` macro
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.

extern crate proc_macro;
extern crate proc_macro2;
#[macro_use]
extern crate quote;

use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
use quote::ToTokens;
use std::env;

fn string(s: &str) -> TokenTree {
    Literal::string(s).into()
}

#[proc_macro_attribute]
pub fn simd_test(
    attr: proc_macro::TokenStream,
    item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
    if tokens.len() != 3 {
        panic!("expected #[simd_test(enable = \"feature\")]");
    }
    match &tokens[0] {
        TokenTree::Ident(tt) if *tt == "enable" => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    match &tokens[1] {
        TokenTree::Punct(tt) if tt.as_char() == '=' => {}
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    }
    let enable_feature = match &tokens[2] {
        TokenTree::Literal(tt) => tt.to_string(),
        _ => panic!("expected #[simd_test(enable = \"feature\")]"),
    };
    let enable_feature = enable_feature.trim_start_matches('"').trim_end_matches('"');
    let target_features: Vec<String> = enable_feature
        .replace('+', "")
        .split(',')
        .map(String::from)
        .collect();

    let mmx = target_features.iter().any(|s| s.starts_with("mmx"));

    let enable_feature = string(enable_feature);
    let item = TokenStream::from(item);
    let name = find_name(item.clone());

    let name: TokenStream = name
        .to_string()
        .parse()
        .unwrap_or_else(|_| panic!("failed to parse name: {}", name.to_string()));

    let target = env::var("TARGET").expect("TARGET environment variable should be set for rustc");
    let mut force_test = false;
    let macro_test = match target
        .split('-')
        .next()
        .unwrap_or_else(|| panic!("target triple contained no \"-\": {}", target))
    {
        "i686" | "x86_64" | "i586" => "is_x86_feature_detected",
        "arm" | "armv7" => "is_arm_feature_detected",
        "aarch64" => "is_aarch64_feature_detected",
        "powerpc" | "powerpcle" => "is_powerpc_feature_detected",
        "powerpc64" | "powerpc64le" => "is_powerpc64_feature_detected",
        "mips" | "mipsel" => {
            // FIXME:
            // On MIPS CI run-time feature detection always returns false due
            // to this qemu bug: https://bugs.launchpad.net/qemu/+bug/1754372
            //
            // This is a workaround to force the MIPS tests to always run on
            // CI.
            force_test = true;
            "is_mips_feature_detected"
        }
        "mips64" | "mips64el" => {
            // FIXME: see above
            force_test = true;
            "is_mips64_feature_detected"
        }
        t => panic!("unknown target: {}", t),
    };
    let macro_test = Ident::new(macro_test, Span::call_site());

    let mut cfg_target_features = TokenStream::new();
    for feature in target_features {
        let q = quote_spanned! {
            proc_macro2::Span::call_site() =>
            #macro_test!(#feature) &&
        };
        q.to_tokens(&mut cfg_target_features);
    }
    let q = quote! { true };
    q.to_tokens(&mut cfg_target_features);

    let test_norun = std::env::var("STDSIMD_TEST_NORUN").is_ok();
    let maybe_ignore = if test_norun {
        quote! { #[ignore] }
    } else {
        TokenStream::new()
    };

    let emms = if mmx {
        // note: if the test requires MMX we need to clear the FPU
        // registers once the test finishes before interfacing with
        // other x87 code:
        quote! { unsafe { super::_mm_empty() }; }
    } else {
        TokenStream::new()
    };

    let ret: TokenStream = quote_spanned! {
        proc_macro2::Span::call_site() =>
        #[allow(non_snake_case)]
        #[test]
        #maybe_ignore
        fn #name() {
            if #force_test | (#cfg_target_features) {
                let v = unsafe { #name() };
                #emms
                return v;
            } else {
                ::stdsimd_test::assert_skip_test_ok(stringify!(#name));
            }

            #[target_feature(enable = #enable_feature)]
            #item
        }
    };
    ret.into()
}

fn find_name(item: TokenStream) -> Ident {
    let mut tokens = item.into_iter();
    while let Some(tok) = tokens.next() {
        if let TokenTree::Ident(word) = tok {
            if word == "fn" {
                break;
            }
        }
    }

    match tokens.next() {
        Some(TokenTree::Ident(word)) => word,
        _ => panic!("failed to find function name"),
    }
}
<|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/. */

#![crate_name = "devtools"]
#![crate_type = "rlib"]

#![allow(non_snake_case)]
#![allow(missing_copy_implementations)]

#![feature(phase)]

#![feature(phase)]
#[phase(plugin, link)]
extern crate log;

/// An actor-based remote devtools server implementation. Only tested with nightly Firefox
/// versions at time of writing. Largely based on reverse-engineering of Firefox chrome
/// devtool logs and reading of [code](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/).

extern crate collections;
extern crate core;
extern crate devtools_traits;
extern crate serialize;
extern crate "msg" as servo_msg;
extern crate "util" as servo_util;

use actor::{Actor, ActorRegistry};
use actors::console::ConsoleActor;
use actors::inspector::InspectorActor;
use actors::root::RootActor;
use actors::tab::TabActor;
use protocol::JsonPacketStream;

use devtools_traits::{ServerExitMsg, DevtoolsControlMsg, NewGlobal, DevtoolScriptControlMsg, DevtoolsPageInfo};
use servo_msg::constellation_msg::PipelineId;
use servo_util::task::spawn_named;

use std::cell::RefCell;
use std::collections::HashMap;
use std::comm;
use std::comm::{Disconnected, Empty};
use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener, TimedOut};
use std::sync::{Arc, Mutex};

mod actor;
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
mod actors {
    pub mod console;
    pub mod inspector;
    pub mod root;
    pub mod tab;
}
mod protocol;

/// Spin up a devtools server that listens for connections on the specified port.
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
    let (sender, receiver) = comm::channel();
    spawn_named("Devtools", proc() {
        run_server(receiver, port)
    });
    sender
}

static POLL_TIMEOUT: u64 = 300;

fn run_server(receiver: Receiver<DevtoolsControlMsg>, port: u16) {
    let listener = TcpListener::bind(format!("{}:{}", "127.0.0.1", port).as_slice());

    // bind the listener to the specified address
    let mut acceptor = listener.listen().unwrap();
    acceptor.set_timeout(Some(POLL_TIMEOUT));

    let mut registry = ActorRegistry::new();

    let root = box RootActor {
        tabs: vec!(),
    };

    registry.register(root);
    registry.find::<RootActor>("root");

    let actors = Arc::new(Mutex::new(registry));

    let mut accepted_connections: Vec<TcpStream> = Vec::new();

    let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new();

    /// Process the input from a single devtools client until EOF.
    fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
        println!("connection established to {}", stream.peer_name().unwrap());
        {
            let actors = actors.lock();
            let msg = actors.find::<RootActor>("root").encodable();
            stream.write_json_packet(&msg);
        }

        'outer: loop {
            match stream.read_json_packet() {
                Ok(json_packet) => {
                    match actors.lock().handle_message(json_packet.as_object().unwrap(),
                                                       &mut stream) {
                        Ok(()) => {},
                        Err(()) => {
                            println!("error: devtools actor stopped responding");
                            let _ = stream.close_read();
                            let _ = stream.close_write();
                            break 'outer
                        }
                    }
                }
                Err(e) => {
                    println!("error: {}", e.desc);
                    break 'outer
                }
            }
        }
    }

    // We need separate actor representations for each script global that exists;
    // clients can theoretically connect to multiple globals simultaneously.
    // TODO: move this into the root or tab modules?
    fn handle_new_global(actors: Arc<Mutex<ActorRegistry>>,
                         pipeline: PipelineId,
                         sender: Sender<DevtoolScriptControlMsg>,
                         actor_pipelines: &mut HashMap<PipelineId, String>,
                         page_info: DevtoolsPageInfo) {
        let mut actors = actors.lock();

        //TODO: move all this actor creation into a constructor method on TabActor
        let (tab, console, inspector) = {
            let console = ConsoleActor {
                name: actors.new_name("console"),
                script_chan: sender.clone(),
                pipeline: pipeline,
                streams: RefCell::new(Vec::new()),
            };
            let inspector = InspectorActor {
                name: actors.new_name("inspector"),
                walker: RefCell::new(None),
                pageStyle: RefCell::new(None),
                highlighter: RefCell::new(None),
                script_chan: sender,
                pipeline: pipeline,
            };

            let DevtoolsPageInfo { title, url } = page_info;
            let tab = TabActor {
                name: actors.new_name("tab"),
                title: title,
                url: url.serialize(),
                console: console.name(),
                inspector: inspector.name(),
            };

            let root = actors.find_mut::<RootActor>("root");
            root.tabs.push(tab.name.clone());
            (tab, console, inspector)
        };

        actor_pipelines.insert(pipeline, tab.name.clone());
        actors.register(box tab);
        actors.register(box console);
        actors.register(box inspector);
    }

    //TODO: figure out some system that allows us to watch for new connections,
    //      shut down existing ones at arbitrary times, and also watch for messages
    //      from multiple script tasks simultaneously. Polling for new connections
    //      for 300ms and then checking the receiver is not a good compromise
    //      (and makes Servo hang on exit if there's an open connection, no less).
    // accept connections and process them, spawning a new tasks for each one
    loop {
        match acceptor.accept() {
            Err(ref e) if e.kind == TimedOut => {
                match receiver.try_recv() {
                    Ok(ServerExitMsg) | Err(Disconnected) => break,
                    Ok(NewGlobal(id, sender, pageinfo)) => handle_new_global(actors.clone(), id, sender, &mut actor_pipelines, pageinfo),
                    Err(Empty) => acceptor.set_timeout(Some(POLL_TIMEOUT)),
                }
            }
            Err(_e) => { /* connection failed */ }
            Ok(stream) => {
                let actors = actors.clone();
                accepted_connections.push(stream.clone());
                spawn_named("DevtoolsClientHandler", proc() {
                    // connection succeeded
                    handle_client(actors, stream.clone())
                })
            }
        }
    }

    for connection in accepted_connections.iter_mut() {
        let _read = connection.close_read();
        let _write = connection.close_write();
    }
}
<commit_msg>auto merge of #4612 : Ms2ger/servo/devtools-doc, r=saneyuki<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/. */

//! An actor-based remote devtools server implementation. Only tested with
//! nightly Firefox versions at time of writing. Largely based on
//! reverse-engineering of Firefox chrome devtool logs and reading of
//! [code](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/).

#![crate_name = "devtools"]
#![crate_type = "rlib"]

#![allow(non_snake_case)]
#![allow(missing_copy_implementations)]

#![feature(phase)]

#[phase(plugin, link)]
extern crate log;

extern crate collections;
extern crate core;
extern crate devtools_traits;
extern crate serialize;
extern crate "msg" as servo_msg;
extern crate "util" as servo_util;

use actor::{Actor, ActorRegistry};
use actors::console::ConsoleActor;
use actors::inspector::InspectorActor;
use actors::root::RootActor;
use actors::tab::TabActor;
use protocol::JsonPacketStream;

use devtools_traits::{ServerExitMsg, DevtoolsControlMsg, NewGlobal, DevtoolScriptControlMsg, DevtoolsPageInfo};
use servo_msg::constellation_msg::PipelineId;
use servo_util::task::spawn_named;

use std::cell::RefCell;
use std::collections::HashMap;
use std::comm;
use std::comm::{Disconnected, Empty};
use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener, TimedOut};
use std::sync::{Arc, Mutex};

mod actor;
/// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/
mod actors {
    pub mod console;
    pub mod inspector;
    pub mod root;
    pub mod tab;
}
mod protocol;

/// Spin up a devtools server that listens for connections on the specified port.
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
    let (sender, receiver) = comm::channel();
    spawn_named("Devtools", proc() {
        run_server(receiver, port)
    });
    sender
}

static POLL_TIMEOUT: u64 = 300;

fn run_server(receiver: Receiver<DevtoolsControlMsg>, port: u16) {
    let listener = TcpListener::bind(format!("{}:{}", "127.0.0.1", port).as_slice());

    // bind the listener to the specified address
    let mut acceptor = listener.listen().unwrap();
    acceptor.set_timeout(Some(POLL_TIMEOUT));

    let mut registry = ActorRegistry::new();

    let root = box RootActor {
        tabs: vec!(),
    };

    registry.register(root);
    registry.find::<RootActor>("root");

    let actors = Arc::new(Mutex::new(registry));

    let mut accepted_connections: Vec<TcpStream> = Vec::new();

    let mut actor_pipelines: HashMap<PipelineId, String> = HashMap::new();

    /// Process the input from a single devtools client until EOF.
    fn handle_client(actors: Arc<Mutex<ActorRegistry>>, mut stream: TcpStream) {
        println!("connection established to {}", stream.peer_name().unwrap());
        {
            let actors = actors.lock();
            let msg = actors.find::<RootActor>("root").encodable();
            stream.write_json_packet(&msg);
        }

        'outer: loop {
            match stream.read_json_packet() {
                Ok(json_packet) => {
                    match actors.lock().handle_message(json_packet.as_object().unwrap(),
                                                       &mut stream) {
                        Ok(()) => {},
                        Err(()) => {
                            println!("error: devtools actor stopped responding");
                            let _ = stream.close_read();
                            let _ = stream.close_write();
                            break 'outer
                        }
                    }
                }
                Err(e) => {
                    println!("error: {}", e.desc);
                    break 'outer
                }
            }
        }
    }

    // We need separate actor representations for each script global that exists;
    // clients can theoretically connect to multiple globals simultaneously.
    // TODO: move this into the root or tab modules?
    fn handle_new_global(actors: Arc<Mutex<ActorRegistry>>,
                         pipeline: PipelineId,
                         sender: Sender<DevtoolScriptControlMsg>,
                         actor_pipelines: &mut HashMap<PipelineId, String>,
                         page_info: DevtoolsPageInfo) {
        let mut actors = actors.lock();

        //TODO: move all this actor creation into a constructor method on TabActor
        let (tab, console, inspector) = {
            let console = ConsoleActor {
                name: actors.new_name("console"),
                script_chan: sender.clone(),
                pipeline: pipeline,
                streams: RefCell::new(Vec::new()),
            };
            let inspector = InspectorActor {
                name: actors.new_name("inspector"),
                walker: RefCell::new(None),
                pageStyle: RefCell::new(None),
                highlighter: RefCell::new(None),
                script_chan: sender,
                pipeline: pipeline,
            };

            let DevtoolsPageInfo { title, url } = page_info;
            let tab = TabActor {
                name: actors.new_name("tab"),
                title: title,
                url: url.serialize(),
                console: console.name(),
                inspector: inspector.name(),
            };

            let root = actors.find_mut::<RootActor>("root");
            root.tabs.push(tab.name.clone());
            (tab, console, inspector)
        };

        actor_pipelines.insert(pipeline, tab.name.clone());
        actors.register(box tab);
        actors.register(box console);
        actors.register(box inspector);
    }

    //TODO: figure out some system that allows us to watch for new connections,
    //      shut down existing ones at arbitrary times, and also watch for messages
    //      from multiple script tasks simultaneously. Polling for new connections
    //      for 300ms and then checking the receiver is not a good compromise
    //      (and makes Servo hang on exit if there's an open connection, no less).
    // accept connections and process them, spawning a new tasks for each one
    loop {
        match acceptor.accept() {
            Err(ref e) if e.kind == TimedOut => {
                match receiver.try_recv() {
                    Ok(ServerExitMsg) | Err(Disconnected) => break,
                    Ok(NewGlobal(id, sender, pageinfo)) => handle_new_global(actors.clone(), id, sender, &mut actor_pipelines, pageinfo),
                    Err(Empty) => acceptor.set_timeout(Some(POLL_TIMEOUT)),
                }
            }
            Err(_e) => { /* connection failed */ }
            Ok(stream) => {
                let actors = actors.clone();
                accepted_connections.push(stream.clone());
                spawn_named("DevtoolsClientHandler", proc() {
                    // connection succeeded
                    handle_client(actors, stream.clone())
                })
            }
        }
    }

    for connection in accepted_connections.iter_mut() {
        let _read = connection.close_read();
        let _write = connection.close_write();
    }
}
<|endoftext|>


<commit_before>use std::mem::size_of;

use baseline;
use baseline::dora_native::{finish_native_call, start_native_call};
use baseline::fct::{BailoutInfo, JitBaselineFct, JitDescriptor, JitFct};
use baseline::map::CodeDescriptor;
use class::TypeParams;
use cpu::{Mem, FREG_PARAMS, REG_FP, REG_PARAMS, REG_RESULT, REG_SP, REG_THREAD, REG_TMP1};
use ctxt::{get_ctxt, FctId, SemContext};
use exception::DoraToNativeInfo;
use gc::Address;
use masm::MacroAssembler;
use mem;
use object::Obj;
use ty::MachineMode;

pub fn generate<'a, 'ast: 'a>(ctxt: &'a SemContext<'ast>) -> Address {
    let ngen = DoraCompileGen {
        ctxt: ctxt,
        masm: MacroAssembler::new(),
        dbg: ctxt.args.flag_emit_debug_compile,
    };

    let jit_fct = ngen.generate();
    let addr = Address::from_ptr(jit_fct.fct_ptr());
    ctxt.insert_code_map(
        jit_fct.ptr_start(),
        jit_fct.ptr_end(),
        CodeDescriptor::CompilerThunk,
    );
    ctxt.jit_fcts.push(JitFct::Base(jit_fct));

    addr
}

struct DoraCompileGen<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    masm: MacroAssembler,
    dbg: bool,
}

impl<'a, 'ast> DoraCompileGen<'a, 'ast>
where
    'ast: 'a,
{
    pub fn generate(mut self) -> JitBaselineFct {
        let framesize = size_of::<DoraToNativeInfo>() as i32
            + (REG_PARAMS.len() + FREG_PARAMS.len() + 2) as i32 * mem::ptr_width();
        let framesize = mem::align_i32(framesize, 16) as i32;

        let offset_params = 0;
        let offset_tmp =
            offset_params + (FREG_PARAMS.len() + REG_PARAMS.len()) as i32 * mem::ptr_width();
        let offset_thread = offset_tmp + mem::ptr_width();

        if self.dbg {
            self.masm.debug();
        }

        self.masm.copy_ra(REG_TMP1);
        self.masm.prolog(framesize);

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_thread),
            REG_THREAD.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_tmp),
            REG_TMP1.into(),
        );
        self.store_params(offset_params);

        self.masm.copy_reg(MachineMode::Ptr, REG_PARAMS[0], REG_FP);
        self.masm.copy_pc(REG_PARAMS[1]);
        self.masm.raw_call(start_native_call as *const u8);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_PARAMS[0].into(),
            Mem::Base(REG_SP, offset_tmp),
        );
        self.masm.load_mem(
            MachineMode::Ptr,
            REG_PARAMS[1].into(),
            Mem::Base(REG_SP, offset_params),
        );
        self.masm.raw_call(compile_request as *const u8);
        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_tmp),
            REG_RESULT.into(),
        );

        self.masm.raw_call(finish_native_call as *const u8);

        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_SP, offset_tmp),
        );
        self.masm.load_mem(
            MachineMode::Ptr,
            REG_THREAD.into(),
            Mem::Base(REG_SP, offset_thread),
        );
        self.load_params(offset_params);
        self.masm.epilog_without_return(framesize);
        self.masm.jump_reg(REG_TMP1);

        self.masm
            .jit(self.ctxt, framesize, JitDescriptor::CompilerThunk, false)
    }

    fn store_params(&mut self, mut offset: i32) {
        for reg in &REG_PARAMS {
            self.masm
                .store_mem(MachineMode::Ptr, Mem::Base(REG_SP, offset), (*reg).into());
            offset += mem::ptr_width();
        }

        for reg in &FREG_PARAMS {
            self.masm.store_mem(
                MachineMode::Float64,
                Mem::Base(REG_SP, offset),
                (*reg).into(),
            );
            offset += mem::ptr_width();
        }
    }

    fn load_params(&mut self, mut offset: i32) {
        for reg in &REG_PARAMS {
            self.masm
                .load_mem(MachineMode::Ptr, (*reg).into(), Mem::Base(REG_SP, offset));
            offset += mem::ptr_width();
        }

        for reg in &FREG_PARAMS {
            self.masm.load_mem(
                MachineMode::Float64,
                (*reg).into(),
                Mem::Base(REG_SP, offset),
            );
            offset += mem::ptr_width();
        }
    }
}

fn compile_request(ra: usize, receiver: Address) -> Address {
    let ctxt = get_ctxt();

    let bailout = {
        let data = {
            let code_map = ctxt.code_map.lock().unwrap();
            code_map
                .get(ra as *const u8)
                .expect("return address not found")
        };

        let fct_id = match data {
            CodeDescriptor::DoraFct(fct_id) => fct_id,
            _ => panic!("expected function for code"),
        };

        let jit_fct = ctxt.jit_fcts[fct_id].borrow();

        let offset = ra - jit_fct.fct_ptr() as usize;
        let jit_fct = jit_fct.to_base().expect("baseline expected");
        jit_fct
            .bailouts
            .get(offset as i32)
            .expect("bailout info not found")
            .clone()
    };

    match bailout {
        BailoutInfo::Compile(fct_id, disp, ref cls_tps, ref fct_tps) => {
            patch_fct_call(ctxt, ra, fct_id, cls_tps, fct_tps, disp)
        }

        BailoutInfo::VirtCompile(vtable_index, ref fct_tps) => {
            patch_vtable_call(ctxt, receiver, vtable_index, fct_tps)
        }
    }
}

fn patch_vtable_call(
    ctxt: &SemContext,
    receiver: Address,
    vtable_index: u32,
    fct_tps: &TypeParams,
) -> Address {
    let obj = unsafe { &mut *receiver.to_mut_ptr::<Obj>() };
    let vtable = obj.header().vtbl();
    let cls_id = vtable.class().cls_id;
    let cls = ctxt.classes[cls_id].borrow();

    let mut fct_ptr = Address::null();

    for &fct_id in &cls.methods {
        let fct = ctxt.fcts[fct_id].borrow();

        if Some(vtable_index) == fct.vtable_index {
            let empty = TypeParams::empty();
            fct_ptr = Address::from_ptr(baseline::generate(ctxt, fct_id, &empty, fct_tps));
            break;
        }
    }

    let methodtable = vtable.table_mut();
    methodtable[vtable_index as usize] = fct_ptr.to_usize();

    fct_ptr
}

fn patch_fct_call(
    ctxt: &SemContext,
    ra: usize,
    fct_id: FctId,
    cls_tps: &TypeParams,
    fct_tps: &TypeParams,
    disp: i32,
) -> Address {
    let fct_ptr = baseline::generate(ctxt, fct_id, cls_tps, fct_tps);
    let fct_addr: *mut usize = (ra as isize - disp as isize) as *mut _;

    // update function pointer in data segment
    unsafe {
        *fct_addr = fct_ptr as usize;
    }

    Address::from_ptr(fct_ptr)
}
<commit_msg>document compiler thunk a bit more<commit_after>use std::mem::size_of;

use baseline;
use baseline::dora_native::{finish_native_call, start_native_call};
use baseline::fct::{BailoutInfo, JitBaselineFct, JitDescriptor, JitFct};
use baseline::map::CodeDescriptor;
use class::TypeParams;
use cpu::{Mem, FREG_PARAMS, REG_FP, REG_PARAMS, REG_RESULT, REG_SP, REG_THREAD, REG_TMP1};
use ctxt::{get_ctxt, FctId, SemContext};
use exception::DoraToNativeInfo;
use gc::Address;
use masm::MacroAssembler;
use mem;
use object::Obj;
use ty::MachineMode;

// This code generates the compiler thunk, there should only be one instance
// of this function be used in Dora. It is necessary for lazy compilation, where
// functions are only compiled on their first invocation. The compiler can use
// the address of this thunk for invocations of functions that have not been compiled
// yet. The thunk compiles the function and patches the call site to invoke the
// now-compiled function directly on the next invocation. In the end the function is
// executed.

pub fn generate<'a, 'ast: 'a>(ctxt: &'a SemContext<'ast>) -> Address {
    let ngen = DoraCompileGen {
        ctxt: ctxt,
        masm: MacroAssembler::new(),
        dbg: ctxt.args.flag_emit_debug_compile,
    };

    let jit_fct = ngen.generate();
    let addr = Address::from_ptr(jit_fct.fct_ptr());
    ctxt.insert_code_map(
        jit_fct.ptr_start(),
        jit_fct.ptr_end(),
        CodeDescriptor::CompilerThunk,
    );
    ctxt.jit_fcts.push(JitFct::Base(jit_fct));

    addr
}

struct DoraCompileGen<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    masm: MacroAssembler,
    dbg: bool,
}

impl<'a, 'ast> DoraCompileGen<'a, 'ast>
where
    'ast: 'a,
{
    pub fn generate(mut self) -> JitBaselineFct {
        let framesize = size_of::<DoraToNativeInfo>() as i32
            + (REG_PARAMS.len() + FREG_PARAMS.len() + 2) as i32 * mem::ptr_width();
        let framesize = mem::align_i32(framesize, 16) as i32;

        let offset_params = 0;
        let offset_tmp =
            offset_params + (FREG_PARAMS.len() + REG_PARAMS.len()) as i32 * mem::ptr_width();
        let offset_thread = offset_tmp + mem::ptr_width();

        if self.dbg {
            self.masm.debug();
        }

        // the return address is the call-site we need to patch
        self.masm.copy_ra(REG_TMP1);
        self.masm.prolog(framesize);

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_thread),
            REG_THREAD.into(),
        );

        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_tmp),
            REG_TMP1.into(),
        );

        // store params passed in registers on the stack
        self.store_params(offset_params);

        // prepare the native call
        self.masm.copy_reg(MachineMode::Ptr, REG_PARAMS[0], REG_FP);
        self.masm.copy_pc(REG_PARAMS[1]);
        self.masm.raw_call(start_native_call as *const u8);

        // invoke the compiler for the call site
        self.masm.load_mem(
            MachineMode::Ptr,
            REG_PARAMS[0].into(),
            Mem::Base(REG_SP, offset_tmp),
        );
        self.masm.load_mem(
            MachineMode::Ptr,
            REG_PARAMS[1].into(),
            Mem::Base(REG_SP, offset_params),
        );
        self.masm.raw_call(compile_request as *const u8);
        self.masm.store_mem(
            MachineMode::Ptr,
            Mem::Base(REG_SP, offset_tmp),
            REG_RESULT.into(),
        );

        // undo the previous native call
        self.masm.raw_call(finish_native_call as *const u8);

        // load the address of the compiled function into REG_TMP1
        self.masm.load_mem(
            MachineMode::Ptr,
            REG_TMP1.into(),
            Mem::Base(REG_SP, offset_tmp),
        );

        // restore thread register
        self.masm.load_mem(
            MachineMode::Ptr,
            REG_THREAD.into(),
            Mem::Base(REG_SP, offset_thread),
        );

        // restore argument registers from the stack
        self.load_params(offset_params);

        // remove the stack frame
        self.masm.epilog_without_return(framesize);

        // jump to compiled function
        self.masm.jump_reg(REG_TMP1);

        self.masm
            .jit(self.ctxt, framesize, JitDescriptor::CompilerThunk, false)
    }

    fn store_params(&mut self, mut offset: i32) {
        for reg in &REG_PARAMS {
            self.masm
                .store_mem(MachineMode::Ptr, Mem::Base(REG_SP, offset), (*reg).into());
            offset += mem::ptr_width();
        }

        for reg in &FREG_PARAMS {
            self.masm.store_mem(
                MachineMode::Float64,
                Mem::Base(REG_SP, offset),
                (*reg).into(),
            );
            offset += mem::ptr_width();
        }
    }

    fn load_params(&mut self, mut offset: i32) {
        for reg in &REG_PARAMS {
            self.masm
                .load_mem(MachineMode::Ptr, (*reg).into(), Mem::Base(REG_SP, offset));
            offset += mem::ptr_width();
        }

        for reg in &FREG_PARAMS {
            self.masm.load_mem(
                MachineMode::Float64,
                (*reg).into(),
                Mem::Base(REG_SP, offset),
            );
            offset += mem::ptr_width();
        }
    }
}

fn compile_request(ra: usize, receiver: Address) -> Address {
    let ctxt = get_ctxt();

    let bailout = {
        let data = {
            let code_map = ctxt.code_map.lock().unwrap();
            code_map
                .get(ra as *const u8)
                .expect("return address not found")
        };

        let fct_id = match data {
            CodeDescriptor::DoraFct(fct_id) => fct_id,
            _ => panic!("expected function for code"),
        };

        let jit_fct = ctxt.jit_fcts[fct_id].borrow();

        let offset = ra - jit_fct.fct_ptr() as usize;
        let jit_fct = jit_fct.to_base().expect("baseline expected");
        jit_fct
            .bailouts
            .get(offset as i32)
            .expect("bailout info not found")
            .clone()
    };

    match bailout {
        BailoutInfo::Compile(fct_id, disp, ref cls_tps, ref fct_tps) => {
            patch_fct_call(ctxt, ra, fct_id, cls_tps, fct_tps, disp)
        }

        BailoutInfo::VirtCompile(vtable_index, ref fct_tps) => {
            patch_vtable_call(ctxt, receiver, vtable_index, fct_tps)
        }
    }
}

fn patch_vtable_call(
    ctxt: &SemContext,
    receiver: Address,
    vtable_index: u32,
    fct_tps: &TypeParams,
) -> Address {
    let obj = unsafe { &mut *receiver.to_mut_ptr::<Obj>() };
    let vtable = obj.header().vtbl();
    let cls_id = vtable.class().cls_id;
    let cls = ctxt.classes[cls_id].borrow();

    let mut fct_ptr = Address::null();

    for &fct_id in &cls.methods {
        let fct = ctxt.fcts[fct_id].borrow();

        if Some(vtable_index) == fct.vtable_index {
            let empty = TypeParams::empty();
            fct_ptr = Address::from_ptr(baseline::generate(ctxt, fct_id, &empty, fct_tps));
            break;
        }
    }

    let methodtable = vtable.table_mut();
    methodtable[vtable_index as usize] = fct_ptr.to_usize();

    fct_ptr
}

fn patch_fct_call(
    ctxt: &SemContext,
    ra: usize,
    fct_id: FctId,
    cls_tps: &TypeParams,
    fct_tps: &TypeParams,
    disp: i32,
) -> Address {
    let fct_ptr = baseline::generate(ctxt, fct_id, cls_tps, fct_tps);
    let fct_addr: *mut usize = (ra as isize - disp as isize) as *mut _;

    // update function pointer in data segment
    unsafe {
        *fct_addr = fct_ptr as usize;
    }

    Address::from_ptr(fct_ptr)
}
<|endoftext|>


<commit_before>//! Runs enqueued background jobs
//!
//! This binary will loop until interrupted. It will run all jobs in the
//! background queue, sleeping for 1 second whenever the queue is empty. If we
//! are unable to spawn workers to run jobs (either because we couldn't connect
//! to the DB, an error occurred while loading, or we just never heard back from
//! the worker thread), we will rebuild the runner and try again up to 5 times.
//! After the 5th occurrance, we will panic.
//!
//! Usage:
//!      cargo run --bin background-worker

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::git::{Repository, RepositoryConfig};
use cargo_registry::{background_jobs::*, db};
use diesel::r2d2;
use reqwest::blocking::Client;
use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    println!("Booting runner");

    let config = cargo_registry::Config::default();
    let db_url = db::connection_url(&config.db_url);

    let job_start_timeout = dotenv::var("BACKGROUND_JOB_TIMEOUT")
        .unwrap_or_else(|_| "30".into())
        .parse()
        .expect("Invalid value for `BACKGROUND_JOB_TIMEOUT`");

    println!("Cloning index");

    let repository_config = RepositoryConfig::from_environment();
    let repository = Arc::new(Mutex::new(
        Repository::open(&repository_config).expect("Failed to clone index"),
    ));
    println!("Index cloned");

    let build_runner = || {
        let environment =
            Environment::new_shared(repository.clone(), config.uploader.clone(), Client::new());
        let db_config = r2d2::Pool::builder().min_idle(Some(0));
        swirl::Runner::builder(environment)
            .connection_pool_builder(&db_url, db_config)
            .job_start_timeout(Duration::from_secs(job_start_timeout))
            .build()
    };
    let mut runner = build_runner();

    println!("Runner booted, running jobs");

    let mut failure_count = 0;

    loop {
        if let Err(e) = runner.run_all_pending_jobs() {
            failure_count += 1;
            if failure_count < 5 {
                eprintln!(
                    "Error running jobs (n = {}) -- retrying: {:?}",
                    failure_count, e,
                );
                runner = build_runner();
            } else {
                panic!("Failed to begin running jobs 5 times. Restarting the process");
            }
        }
        sleep(Duration::from_secs(1));
    }
}
<commit_msg>Increase HTTP request timeout for background jobs<commit_after>//! Runs enqueued background jobs
//!
//! This binary will loop until interrupted. It will run all jobs in the
//! background queue, sleeping for 1 second whenever the queue is empty. If we
//! are unable to spawn workers to run jobs (either because we couldn't connect
//! to the DB, an error occurred while loading, or we just never heard back from
//! the worker thread), we will rebuild the runner and try again up to 5 times.
//! After the 5th occurrance, we will panic.
//!
//! Usage:
//!      cargo run --bin background-worker

#![warn(clippy::all, rust_2018_idioms)]

use cargo_registry::git::{Repository, RepositoryConfig};
use cargo_registry::{background_jobs::*, db};
use diesel::r2d2;
use reqwest::blocking::Client;
use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    println!("Booting runner");

    let config = cargo_registry::Config::default();
    let db_url = db::connection_url(&config.db_url);

    let job_start_timeout = dotenv::var("BACKGROUND_JOB_TIMEOUT")
        .unwrap_or_else(|_| "30".into())
        .parse()
        .expect("Invalid value for `BACKGROUND_JOB_TIMEOUT`");

    println!("Cloning index");

    let repository_config = RepositoryConfig::from_environment();
    let repository = Arc::new(Mutex::new(
        Repository::open(&repository_config).expect("Failed to clone index"),
    ));
    println!("Index cloned");

    let build_runner = || {
        let client = Client::builder()
            .timeout(Duration::from_secs(45))
            .build()
            .expect("Couldn't build client");
        let environment =
            Environment::new_shared(repository.clone(), config.uploader.clone(), client);
        let db_config = r2d2::Pool::builder().min_idle(Some(0));
        swirl::Runner::builder(environment)
            .connection_pool_builder(&db_url, db_config)
            .job_start_timeout(Duration::from_secs(job_start_timeout))
            .build()
    };
    let mut runner = build_runner();

    println!("Runner booted, running jobs");

    let mut failure_count = 0;

    loop {
        if let Err(e) = runner.run_all_pending_jobs() {
            failure_count += 1;
            if failure_count < 5 {
                eprintln!(
                    "Error running jobs (n = {}) -- retrying: {:?}",
                    failure_count, e,
                );
                runner = build_runner();
            } else {
                panic!("Failed to begin running jobs 5 times. Restarting the process");
            }
        }
        sleep(Duration::from_secs(1));
    }
}
<|endoftext|>