<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::collections::BTreeMap;
use std::sync::Arc;

use base::Event;
use devices::serial_device::{SerialHardware, SerialParameters, SerialType};
use devices::{Bus, ProxyDevice, Serial};
use hypervisor::ProtectionType;
use minijail::Minijail;
use remain::sorted;
use sync::Mutex;
use thiserror::Error as ThisError;

use crate::DeviceRegistrationError;

/// Add the default serial parameters for serial ports that have not already been specified.
///
/// This ensures that `serial_parameters` will contain parameters for each of the four PC-style
/// serial ports (COM1-COM4).
///
/// It also sets the first `SerialHardware::Serial` to be the default console device if no other
/// serial parameters exist with console=true and the first serial device has not already been
/// configured explicitly.
pub fn set_default_serial_parameters(
    serial_parameters: &mut BTreeMap<(SerialHardware, u8), SerialParameters>,
    is_vhost_user_console_enabled: bool,
) {
    // If no console device exists and the first serial port has not been specified,
    // set the first serial port as a stdout+stdin console.
    let default_console = (SerialHardware::Serial, 1);
    if !serial_parameters.iter().any(|(_, p)| p.console) && !is_vhost_user_console_enabled {
        serial_parameters
            .entry(default_console)
            .or_insert(SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::Serial,
                path: None,
                input: None,
                num: 1,
                console: true,
                earlycon: false,
                stdin: true,
                out_timestamp: false,
                ..Default::default()
            });
    }

    // Ensure all four of the COM ports exist.
    // If one of these four SerialHardware::Serial port was not configured by the user,
    // set it up as a sink.
    for num in 1..=4 {
        let key = (SerialHardware::Serial, num);
        serial_parameters.entry(key).or_insert(SerialParameters {
            type_: SerialType::Sink,
            hardware: SerialHardware::Serial,
            path: None,
            input: None,
            num,
            console: false,
            earlycon: false,
            stdin: false,
            out_timestamp: false,
            ..Default::default()
        });
    }
}

/// Address for Serial ports in x86
pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];

/// Adds serial devices to the provided bus based on the serial parameters given.
///
/// Only devices with hardware type `SerialHardware::Serial` are added by this function.
///
/// # Arguments
///
/// * `io_bus` - Bus to add the devices to
/// * `com_evt_1_3` - event for com1 and com3
/// * `com_evt_1_4` - event for com2 and com4
/// * `io_bus` - Bus to add the devices to
/// * `serial_parameters` - definitions of serial parameter configurations.
///   All four of the traditional PC-style serial ports (COM1-COM4) must be specified.
pub fn add_serial_devices(
    protected_vm: ProtectionType,
    io_bus: &Bus,
    com_evt_1_3: &Event,
    com_evt_2_4: &Event,
    serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
    serial_jail: Option<Minijail>,
) -> Result<(), DeviceRegistrationError> {
    for x in 0..=3 {
        let com_evt = match x {
            0 => com_evt_1_3,
            1 => com_evt_2_4,
            2 => com_evt_1_3,
            3 => com_evt_2_4,
            _ => com_evt_1_3,
        };

        let param = serial_parameters
            .get(&(SerialHardware::Serial, x + 1))
            .ok_or(DeviceRegistrationError::MissingRequiredSerialDevice(x + 1))?;

        let mut preserved_fds = Vec::new();
        let com = param
            .create_serial_device::<Serial>(protected_vm, com_evt, &mut preserved_fds)
            .map_err(DeviceRegistrationError::CreateSerialDevice)?;

        match serial_jail.as_ref() {
            Some(jail) => {
                let com = Arc::new(Mutex::new(
                    ProxyDevice::new(
                        com,
                        &jail
                            .try_clone()
                            .map_err(DeviceRegistrationError::CloneJail)?,
                        preserved_fds,
                    )
                    .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
                ));
                io_bus
                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8)
                    .unwrap();
            }
            None => {
                let com = Arc::new(Mutex::new(com));
                io_bus
                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8)
                    .unwrap();
            }
        }
    }

    Ok(())
}

#[sorted]
#[derive(ThisError, Debug)]
pub enum GetSerialCmdlineError {
    #[error("Error appending to cmdline: {0}")]
    KernelCmdline(kernel_cmdline::Error),
    #[error("Hardware {0} not supported as earlycon")]
    UnsupportedEarlyconHardware(SerialHardware),
}

pub type GetSerialCmdlineResult<T> = std::result::Result<T, GetSerialCmdlineError>;

/// Add serial options to the provided `cmdline` based on `serial_parameters`.
/// `serial_io_type` should be "io" if the platform uses x86-style I/O ports for serial devices
/// or "mmio" if the serial ports are memory mapped.
// TODO(b/227407433): Support cases where vhost-user console is specified.
pub fn get_serial_cmdline(
    cmdline: &mut kernel_cmdline::Cmdline,
    serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
    serial_io_type: &str,
) -> GetSerialCmdlineResult<()> {
    match serial_parameters
        .iter()
        .filter(|(_, p)| p.console)
        .map(|(k, _)| k)
        .next()
    {
        Some((SerialHardware::Serial, num)) => {
            cmdline
                .insert("console", &format!("ttyS{}", num - 1))
                .map_err(GetSerialCmdlineError::KernelCmdline)?;
        }
        Some((SerialHardware::VirtioConsole, num)) => {
            cmdline
                .insert("console", &format!("hvc{}", num - 1))
                .map_err(GetSerialCmdlineError::KernelCmdline)?;
        }
        Some((SerialHardware::Debugcon, _)) => {}
        None => {}
    }

    match serial_parameters
        .iter()
        .filter(|(_, p)| p.earlycon)
        .map(|(k, _)| k)
        .next()
    {
        Some((SerialHardware::Serial, num)) => {
            if let Some(addr) = SERIAL_ADDR.get(*num as usize - 1) {
                cmdline
                    .insert(
                        "earlycon",
                        &format!("uart8250,{},0x{:x}", serial_io_type, addr),
                    )
                    .map_err(GetSerialCmdlineError::KernelCmdline)?;
            }
        }
        Some((hw, _num)) => {
            return Err(GetSerialCmdlineError::UnsupportedEarlyconHardware(*hw));
        }
        None => {}
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel_cmdline::Cmdline;

    #[test]
    fn get_serial_cmdline_default() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect("get_serial_cmdline failed");

        let cmdline_str = cmdline.as_str();
        assert!(cmdline_str.contains("console=ttyS0"));
    }

    #[test]
    fn get_serial_cmdline_virtio_console() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        // Add a virtio-console device with console=true.
        serial_parameters.insert(
            (SerialHardware::VirtioConsole, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::VirtioConsole,
                path: None,
                input: None,
                num: 1,
                console: true,
                earlycon: false,
                stdin: true,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect("get_serial_cmdline failed");

        let cmdline_str = cmdline.as_str();
        assert!(cmdline_str.contains("console=hvc0"));
    }

    #[test]
    fn get_serial_cmdline_virtio_console_serial_earlycon() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        // Add a virtio-console device with console=true.
        serial_parameters.insert(
            (SerialHardware::VirtioConsole, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::VirtioConsole,
                path: None,
                input: None,
                num: 1,
                console: true,
                earlycon: false,
                stdin: true,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        // Override the default COM1 with an earlycon device.
        serial_parameters.insert(
            (SerialHardware::Serial, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::Serial,
                path: None,
                input: None,
                num: 1,
                console: false,
                earlycon: true,
                stdin: false,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect("get_serial_cmdline failed");

        let cmdline_str = cmdline.as_str();
        assert!(cmdline_str.contains("console=hvc0"));
        assert!(cmdline_str.contains("earlycon=uart8250,io,0x3f8"));
    }

    #[test]
    fn get_serial_cmdline_virtio_console_invalid_earlycon() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        // Try to add a virtio-console device with earlycon=true (unsupported).
        serial_parameters.insert(
            (SerialHardware::VirtioConsole, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::VirtioConsole,
                path: None,
                input: None,
                num: 1,
                console: false,
                earlycon: true,
                stdin: true,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect_err("get_serial_cmdline succeeded");
    }
}
<commit_msg>arch: add Windows bits to serial.<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::collections::BTreeMap;
use std::sync::Arc;
#[cfg(windows)]
use std::thread;
#[cfg(windows)]
use std::time::Duration;

#[cfg(windows)]
use std::io::Read;

use base::Event;
#[cfg(windows)]
use base::Result;
use devices::serial_device::{SerialHardware, SerialParameters, SerialType};
#[cfg(windows)]
use devices::Minijail;
#[cfg(unix)]
use devices::ProxyDevice;
use devices::{Bus, Serial};
use hypervisor::ProtectionType;
#[cfg(unix)]
use minijail::Minijail;
use remain::sorted;
use sync::Mutex;
use thiserror::Error as ThisError;

use crate::DeviceRegistrationError;

/// Add the default serial parameters for serial ports that have not already been specified.
///
/// This ensures that `serial_parameters` will contain parameters for each of the four PC-style
/// serial ports (COM1-COM4).
///
/// It also sets the first `SerialHardware::Serial` to be the default console device if no other
/// serial parameters exist with console=true and the first serial device has not already been
/// configured explicitly.
pub fn set_default_serial_parameters(
    serial_parameters: &mut BTreeMap<(SerialHardware, u8), SerialParameters>,
    is_vhost_user_console_enabled: bool,
) {
    // If no console device exists and the first serial port has not been specified,
    // set the first serial port as a stdout+stdin console.
    let default_console = (SerialHardware::Serial, 1);
    if !serial_parameters.iter().any(|(_, p)| p.console) && !is_vhost_user_console_enabled {
        serial_parameters
            .entry(default_console)
            .or_insert(SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::Serial,
                path: None,
                input: None,
                num: 1,
                console: true,
                earlycon: false,
                stdin: true,
                out_timestamp: false,
                ..Default::default()
            });
    }

    // Ensure all four of the COM ports exist.
    // If one of these four SerialHardware::Serial port was not configured by the user,
    // set it up as a sink.
    for num in 1..=4 {
        let key = (SerialHardware::Serial, num);
        serial_parameters.entry(key).or_insert(SerialParameters {
            type_: SerialType::Sink,
            hardware: SerialHardware::Serial,
            path: None,
            input: None,
            num,
            console: false,
            earlycon: false,
            stdin: false,
            out_timestamp: false,
            ..Default::default()
        });
    }
}

/// Address for Serial ports in x86
pub const SERIAL_ADDR: [u64; 4] = [0x3f8, 0x2f8, 0x3e8, 0x2e8];

/// A type for queueing input bytes to a serial device that abstracts if the device is local or part
/// of a sandboxed device process.
/// TODO(b/160806152) rizhang: Move to different file for readability.
#[cfg(windows)]
pub enum SerialInput {
    #[doc(hidden)]
    Local(Arc<Mutex<Serial>>),
}

#[cfg(windows)]
impl SerialInput {
    /// Creates a `SerialInput` that trivially forwards queued bytes to the device in the local
    /// process.
    pub fn new_local(serial: Arc<Mutex<Serial>>) -> SerialInput {
        SerialInput::Local(serial)
    }

    /// Just like `Serial::queue_input_bytes`, but abstracted over local and sandboxed serial
    /// devices.
    pub fn queue_input_bytes(&self, bytes: &[u8]) -> Result<()> {
        match self {
            SerialInput::Local(device) => device.lock().queue_input_bytes(bytes),
        }
    }
}

/// Adds serial devices to the provided bus based on the serial parameters given.
///
/// Only devices with hardware type `SerialHardware::Serial` are added by this function.
///
/// # Arguments
///
/// * `io_bus` - Bus to add the devices to
/// * `com_evt_1_3` - event for com1 and com3
/// * `com_evt_1_4` - event for com2 and com4
/// * `io_bus` - Bus to add the devices to
/// * `serial_parameters` - definitions of serial parameter configurations.
///   All four of the traditional PC-style serial ports (COM1-COM4) must be specified.
pub fn add_serial_devices(
    protected_vm: ProtectionType,
    io_bus: &Bus,
    com_evt_1_3: &Event,
    com_evt_2_4: &Event,
    serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
    serial_jail: Option<Minijail>,
) -> std::result::Result<(), DeviceRegistrationError> {
    for x in 0..=3 {
        let com_evt = match x {
            0 => &com_evt_1_3,
            1 => &com_evt_2_4,
            2 => &com_evt_1_3,
            3 => &com_evt_2_4,
            _ => &com_evt_1_3,
        };

        let param = serial_parameters
            .get(&(SerialHardware::Serial, x + 1))
            .ok_or(DeviceRegistrationError::MissingRequiredSerialDevice(x + 1))?;

        let mut preserved_descriptors = Vec::new();
        let com = param
            .create_serial_device::<Serial>(protected_vm, com_evt, &mut preserved_descriptors)
            .map_err(DeviceRegistrationError::CreateSerialDevice)?;

        match serial_jail.as_ref() {
            #[cfg(unix)]
            Some(jail) => {
                let com = Arc::new(Mutex::new(
                    ProxyDevice::new(com, jail, preserved_descriptors)
                        .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
                ));
                io_bus
                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8)
                    .unwrap();
            }
            #[cfg(windows)]
            Some(_) => (),
            None => {
                let com = Arc::new(Mutex::new(com));
                io_bus
                    .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8)
                    .unwrap();

                #[cfg(windows)]
                {
                    if !param.stdin {
                        if let SerialType::SystemSerialType = param.type_ {
                            let mut in_pipe_result =
                                com.lock().in_stream.as_ref().unwrap().try_clone();
                            thread::spawn(move || {
                                let serial_input = SerialInput::new_local(com);
                                let in_pipe = in_pipe_result.as_mut().unwrap();

                                let mut buffer: [u8; 255] = [0; 255];
                                loop {
                                    let bytes = in_pipe.read(&mut buffer).unwrap_or(0);
                                    if bytes > 0 {
                                        serial_input.queue_input_bytes(&buffer[0..bytes]).unwrap();
                                    }
                                    // We can't issue blocking reads here and overlapped I/O is
                                    // incompatible with the call site where writes to this pipe are being
                                    // made, so instead we issue a small wait to prevent us from hogging
                                    // the CPU. This 20ms delay while typing doesn't seem to be noticeable.
                                    thread::sleep(Duration::from_millis(20));
                                }
                            });
                        }
                    }
                }
            }
        }
    }

    Ok(())
}

#[sorted]
#[derive(ThisError, Debug)]
pub enum GetSerialCmdlineError {
    #[error("Error appending to cmdline: {0}")]
    KernelCmdline(kernel_cmdline::Error),
    #[error("Hardware {0} not supported as earlycon")]
    UnsupportedEarlyconHardware(SerialHardware),
}

pub type GetSerialCmdlineResult<T> = std::result::Result<T, GetSerialCmdlineError>;

/// Add serial options to the provided `cmdline` based on `serial_parameters`.
/// `serial_io_type` should be "io" if the platform uses x86-style I/O ports for serial devices
/// or "mmio" if the serial ports are memory mapped.
// TODO(b/227407433): Support cases where vhost-user console is specified.
pub fn get_serial_cmdline(
    cmdline: &mut kernel_cmdline::Cmdline,
    serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
    serial_io_type: &str,
) -> GetSerialCmdlineResult<()> {
    match serial_parameters
        .iter()
        .filter(|(_, p)| p.console)
        .map(|(k, _)| k)
        .next()
    {
        Some((SerialHardware::Serial, num)) => {
            cmdline
                .insert("console", &format!("ttyS{}", num - 1))
                .map_err(GetSerialCmdlineError::KernelCmdline)?;
        }
        Some((SerialHardware::VirtioConsole, num)) => {
            cmdline
                .insert("console", &format!("hvc{}", num - 1))
                .map_err(GetSerialCmdlineError::KernelCmdline)?;
        }
        Some((SerialHardware::Debugcon, _)) => {}
        None => {}
    }

    match serial_parameters
        .iter()
        .filter(|(_, p)| p.earlycon)
        .map(|(k, _)| k)
        .next()
    {
        Some((SerialHardware::Serial, num)) => {
            if let Some(addr) = SERIAL_ADDR.get(*num as usize - 1) {
                cmdline
                    .insert(
                        "earlycon",
                        &format!("uart8250,{},0x{:x}", serial_io_type, addr),
                    )
                    .map_err(GetSerialCmdlineError::KernelCmdline)?;
            }
        }
        Some((hw, _num)) => {
            return Err(GetSerialCmdlineError::UnsupportedEarlyconHardware(*hw));
        }
        None => {}
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use kernel_cmdline::Cmdline;

    #[test]
    fn get_serial_cmdline_default() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect("get_serial_cmdline failed");

        let cmdline_str = cmdline.as_str();
        assert!(cmdline_str.contains("console=ttyS0"));
    }

    #[test]
    fn get_serial_cmdline_virtio_console() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        // Add a virtio-console device with console=true.
        serial_parameters.insert(
            (SerialHardware::VirtioConsole, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::VirtioConsole,
                path: None,
                input: None,
                num: 1,
                console: true,
                earlycon: false,
                stdin: true,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect("get_serial_cmdline failed");

        let cmdline_str = cmdline.as_str();
        assert!(cmdline_str.contains("console=hvc0"));
    }

    #[test]
    fn get_serial_cmdline_virtio_console_serial_earlycon() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        // Add a virtio-console device with console=true.
        serial_parameters.insert(
            (SerialHardware::VirtioConsole, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::VirtioConsole,
                path: None,
                input: None,
                num: 1,
                console: true,
                earlycon: false,
                stdin: true,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        // Override the default COM1 with an earlycon device.
        serial_parameters.insert(
            (SerialHardware::Serial, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::Serial,
                path: None,
                input: None,
                num: 1,
                console: false,
                earlycon: true,
                stdin: false,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect("get_serial_cmdline failed");

        let cmdline_str = cmdline.as_str();
        assert!(cmdline_str.contains("console=hvc0"));
        assert!(cmdline_str.contains("earlycon=uart8250,io,0x3f8"));
    }

    #[test]
    fn get_serial_cmdline_virtio_console_invalid_earlycon() {
        let mut cmdline = Cmdline::new(4096);
        let mut serial_parameters = BTreeMap::new();

        // Try to add a virtio-console device with earlycon=true (unsupported).
        serial_parameters.insert(
            (SerialHardware::VirtioConsole, 1),
            SerialParameters {
                type_: SerialType::Stdout,
                hardware: SerialHardware::VirtioConsole,
                path: None,
                input: None,
                num: 1,
                console: false,
                earlycon: true,
                stdin: true,
                out_timestamp: false,
                debugcon_port: 0,
            },
        );

        set_default_serial_parameters(&mut serial_parameters, false);
        get_serial_cmdline(&mut cmdline, &serial_parameters, "io")
            .expect_err("get_serial_cmdline succeeded");
    }
}
<|endoftext|>


<commit_before>#[link(name = "simplify", vers = "0.0.5")];
extern mod extra;
use extra::json::*;
use std::hashmap::HashMap;
use std::vec;
pub struct Point {
	x: float,
	y: float
}
impl ToJson for Point {
    fn to_json(&self) -> Json { List(~[self.x.to_json(),self.y.to_json()]) }
}
impl Eq for Point {
    fn eq(&self, other: &Point) -> bool { other.x == self.x && other.y == self.y }
    fn ne(&self, other: &Point) -> bool { other.x != self.x || other.y != self.y }
}
impl Sub<Point,Point> for Point {
    #[inline]
    fn sub(&self, other: &Point) -> Point { Point {x:self.x-other.x,y:self.y-other.y} }
}
impl Add<Point,Point> for Point {
    #[inline]
    fn add(&self, other: &Point) -> Point { Point { x:self.x+other.x,y:self.y+other.y }}
}
impl Mul<Point,Point> for Point {
    #[inline]
    fn mul(&self, other: &Point) -> Point { Point { x:self.x*other.x,y:self.y*other.y }}
}

impl Point {
    fn sum(self) -> float { self.x+self.y }
    fn sqsum(self) -> float { self.x * self.x + self.y * self.y}
    fn sub(self, other: float) -> Point { Point { x:self.x - other , y:self.y - other }}
    fn mul(self, other: float) -> Point { Point { x:self.x * other, y:self.y * other }}
    fn add(self, other: float) -> Point {  Point {x:self.x + other, y:self.y + other }}
}

fn calcStuff(p:Point,p1:Point,d1:Point)->float {
	let top : float = ((p - p1) * d1).sum();
	let bottom : float =  d1.sqsum();
	match bottom{
		0.0=>0.0,
		_=>top/bottom
	}
}
fn getSquareSegmentDistance(p: Point, p1: Point, p2: Point) -> float {
	let d1 : Point = p2-p1;
	let d2 : Point = match d1{
		Point {x:0.0,_} | Point {y:0.0,_}=> {p1}
		_=>{
			let t : float = calcStuff(p,p1,d1);
			match t {
				tt if tt>1.0=>p2,
				tt if tt>0.0=> d1.mul(tt)+p1,
				_=>p1
			}
		}
	};
	let d4 : Point = p-d2;
	d4.sqsum()
}
fn simplifyRadialDistance(points:~[Point], sqTolerance:float) -> ~[Point]{
    let mut it = points.iter();
	let mut prevPoint : Point = it.next().get();
	let mut newPoints : ~[Point] = ~[prevPoint];
	let last : Point = points.last();
	for point in it.filter(|point|(point - prevPoint).sqsum() > sqTolerance) {
			newPoints.push(point);
			prevPoint = point;
	}
	if (prevPoint!= last) {
		newPoints.push(last);
	}
	newPoints
}
fn simplifyDouglasPeucker(points : ~[Point], tolerance : float) -> ~[Point]{
	let len : uint = points.len();
	let mut markers = HashMap::new();
	let mut first : uint = 0u;
	let mut last : uint = len - 1u;
	let mut firstStack : ~[uint] = vec:: with_capacity(len);
	let mut lastStack : ~[uint] = vec:: with_capacity(len);
	markers.insert(first,1u);
	markers.insert(last,1u);
	let mut index : uint = 0;
	loop {
		let mut maxSqDist : float = 0.0f;
		let mut i : uint = first + 1u;
		while (i < last) {

			let sqDist :float  = getSquareSegmentDistance(
				points[i],
				points[first],
				points[last]
			);
			if (sqDist > maxSqDist) {
				index = i;
				maxSqDist = sqDist;
			}
			i += 1;
		}
		if (maxSqDist > tolerance) {
			markers.insert(index,1u);
			firstStack.push(first);
			lastStack.push(index);
			firstStack.push(index);
			lastStack.push(last);
		}
		if(lastStack.len()>0u){
			first = firstStack.pop();
			last = lastStack.pop();
		}else{
			break;
		};
	};
    vec::from_fn(markers.len(),|k| points[k])
}

pub fn simplify(points : ~[Point], sqTolerance : float, hq:bool) -> ~[Point]{
	let tolerance : float = sqTolerance*sqTolerance;
	let pts:~[Point]=match hq {
		true=>points,
		_=>simplifyRadialDistance(points,tolerance)
	};
	simplifyDouglasPeucker(pts,tolerance)
}
<commit_msg>small int map<commit_after>#[link(name = "simplify", vers = "0.0.5")];
extern mod extra;
use extra::json::*;
use extra::smallintmap::SmallIntMap;
use std::vec;
pub struct Point {
	x: float,
	y: float
}
impl ToJson for Point {
    fn to_json(&self) -> Json { List(~[self.x.to_json(),self.y.to_json()]) }
}
impl Eq for Point {
    fn eq(&self, other: &Point) -> bool { other.x == self.x && other.y == self.y }
    fn ne(&self, other: &Point) -> bool { other.x != self.x || other.y != self.y }
}
impl Sub<Point,Point> for Point {
    #[inline]
    fn sub(&self, other: &Point) -> Point { Point {x:self.x-other.x,y:self.y-other.y} }
}
impl Add<Point,Point> for Point {
    #[inline]
    fn add(&self, other: &Point) -> Point { Point { x:self.x+other.x,y:self.y+other.y }}
}
impl Mul<Point,Point> for Point {
    #[inline]
    fn mul(&self, other: &Point) -> Point { Point { x:self.x*other.x,y:self.y*other.y }}
}

impl Point {
    fn sum(self) -> float { self.x+self.y }
    fn sqsum(self) -> float { self.x * self.x + self.y * self.y}
    fn sub(self, other: float) -> Point { Point { x:self.x - other , y:self.y - other }}
    fn mul(self, other: float) -> Point { Point { x:self.x * other, y:self.y * other }}
    fn add(self, other: float) -> Point {  Point {x:self.x + other, y:self.y + other }}
}

fn calcStuff(p:Point,p1:Point,d1:Point)->float {
	let top : float = ((p - p1) * d1).sum();
	let bottom : float =  d1.sqsum();
	match bottom{
		0.0=>0.0,
		_=>top/bottom
	}
}
fn getSquareSegmentDistance(p: Point, p1: Point, p2: Point) -> float {
	let d1 : Point = p2-p1;
	let d2 : Point = match d1{
		Point {x:0.0,_} | Point {y:0.0,_}=> {p1}
		_=>{
			let t : float = calcStuff(p,p1,d1);
			match t {
				tt if tt>1.0=>p2,
				tt if tt>0.0=> d1.mul(tt)+p1,
				_=>p1
			}
		}
	};
	let d4 : Point = p-d2;
	d4.sqsum()
}
fn simplifyRadialDistance(points:~[Point], sqTolerance:float) -> ~[Point]{
    let mut it = points.iter();
    it.next();
	let mut prevPoint : Point = points[0u];
	let mut newPoints : ~[Point] = ~[prevPoint];
	let last : Point = *points.last();
	for &point in it.filter(|&point|(point - prevPoint).sqsum() > sqTolerance) {
			newPoints.push(point);
			prevPoint = point;
	}
	if (prevPoint!= last) {
		newPoints.push(last);
	}
	newPoints
}
fn simplifyDouglasPeucker(points : ~[Point], tolerance : float) -> ~[Point]{
	let len : uint = points.len();
	let mut markers = SmallIntMap::new();
	let mut first : uint = 0u;
	let mut last : uint = len - 1u;
	let mut firstStack : ~[uint] = vec:: with_capacity(len);
	let mut lastStack : ~[uint] = vec:: with_capacity(len);
	markers.insert(first,1u);
	markers.insert(last,1u);
	let mut index : uint = 0;
	loop {
		let mut maxSqDist : float = 0.0f;
		let mut i : uint = first + 1u;
		while (i < last) {

			let sqDist :float  = getSquareSegmentDistance(
				points[i],
				points[first],
				points[last]
			);
			if (sqDist > maxSqDist) {
				index = i;
				maxSqDist = sqDist;
			}
			i += 1;
		}
		if (maxSqDist > tolerance) {
			markers.insert(index,1u);
			firstStack.push(first);
			lastStack.push(index);
			firstStack.push(index);
			lastStack.push(last);
		}
		if(lastStack.len()>0u){
			first = firstStack.pop();
			last = lastStack.pop();
		}else{
			break;
		};
	};
    vec::from_fn(markers.len(),|k| points[k])
}

pub fn simplify(points : ~[Point], sqTolerance : float, hq:bool) -> ~[Point]{
	let tolerance : float = sqTolerance*sqTolerance;
	let pts:~[Point]=match hq {
		true=>points,
		_=>simplifyRadialDistance(points,tolerance)
	};
	simplifyDouglasPeucker(pts,tolerance)
}
<|endoftext|>


<commit_before>//! Sequential IR for Weld programs

use std::fmt;
use std::collections::{BTreeMap, HashMap, HashSet};

use super::ast::*;
use super::ast::ExprKind::*;
use super::error::*;
use super::pretty_print::*;
use super::util::SymbolGenerator;

type BasicBlockId = usize;

/// A non-terminating statement inside a basic block.
pub enum Statement {
    /// output, op, type, left, right
    AssignBinOp(Symbol, BinOpKind, Type, Symbol, Symbol),
    /// output, value
    Assign(Symbol, Symbol),
    /// output, value
    AssignLiteral(Symbol, LiteralKind),
    /// output, builder, value
    DoMerge(Symbol, Symbol, Symbol),
    /// output, builder
    GetResult(Symbol, Symbol),
    /// output, builder type
    CreateBuilder(Symbol, Type),
}

/// A terminating statement inside a basic block.
pub enum Terminator {
    /// condition, on_true, on_false
    Branch(Symbol, BasicBlockId, BasicBlockId),
    Jump(BasicBlockId),
    Return(Symbol),
    ParallelFor {
        data: Symbol,
        builder: Symbol,
        body: BasicBlockId,
        data_arg: Symbol,
        closure: HashSet<Symbol>,
        builder_arg: Symbol,
        exit: BasicBlockId,
        result: Symbol,
    },
    Crash
}

/// A basic block inside a SIR program
pub struct BasicBlock {
    id: BasicBlockId,
    statements: Vec<Statement>,
    terminator: Terminator
}

pub struct SirFunction {
    params: Vec<TypedParameter>,
    locals: HashMap<Symbol, Type>,
    blocks: Vec<BasicBlock>,
    sym_gen: SymbolGenerator,
}

impl SirFunction {
    pub fn new() -> SirFunction {
        SirFunction {
            params: vec![],
            blocks: vec![],
            locals: HashMap::new(),
            sym_gen: SymbolGenerator::new(),
        }
    }

    /// Add a new basic block and return its block ID.
    pub fn add_block(&mut self) -> BasicBlockId {
        let block = BasicBlock {
            id: self.blocks.len(),
            statements: vec![],
            terminator: Terminator::Crash
        };
        self.blocks.push(block);
        self.blocks.len() - 1
    }

    /// Add a local variable of the given type and return a symbol for it.
    pub fn add_local(&mut self, ty: &Type) -> Symbol {
        let sym = self.sym_gen.new_symbol("tmp");
        self.locals.insert(sym.clone(), ty.clone());
        sym
    }

    /// Add a local variable of the given type and name
    pub fn add_local_named(&mut self, ty: &Type, sym: &Symbol) {
        self.locals.insert(sym.clone(), ty.clone());
    }
}

impl BasicBlock {
    pub fn add_statement(&mut self, statement: Statement) {
        self.statements.push(statement);
    }
}

impl fmt::Display for Statement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Statement::*;
        match *self {
            AssignBinOp(ref out, ref op, ref ty, ref left, ref right) => {
                write!(f, "{} = {} {} {} {}", out, op, print_type(ty), left, right)
            },
            Assign(ref out, ref value) => write!(f, "{} = {}", out, value),
            AssignLiteral(ref out, ref lit) => write!(f, "{} = {}", out, print_literal(lit)),
            DoMerge(ref out, ref bld, ref elem) => write!(f, "{} = merge {} {}", out, bld, elem),
            GetResult(ref out, ref value) => write!(f, "{} = result {}", out, value),
            CreateBuilder(ref out, ref ty) => write!(f, "{} = new {}", out, print_type(ty)),
        }
    }
}

impl fmt::Display for Terminator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Terminator::*;
        match *self {
            Branch(ref cond, ref on_true, ref on_false) => {
                write!(f, "branch {} B{} B{}", cond, on_true, on_false)
            },
            ParallelFor {
                ref data, ref builder, body, ref data_arg, ref closure, ref builder_arg, exit, ref result
            } => {
                write!(f, "for {} {} B{} {} {} B{} {} [",
                    data, builder, body, data_arg, builder_arg, exit, result)?;
                for x in closure.iter() {
                  write!(f, "{}, ", x)?;
                }
                write!(f, "]")?;
                Ok(())
            },
            Jump(block) => write!(f, "jump B{}", block),
            Return(ref sym) => write!(f, "return {}", sym),
            Crash => write!(f, "crash")
        }
    }
}

impl fmt::Display for BasicBlock {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "B{}:\n", self.id)?;
        for stmt in &self.statements {
            write!(f, "  {}\n", stmt)?;
        }
        write!(f, "  {}\n", self.terminator)?;
        Ok(())
    }
}

impl fmt::Display for SirFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Params:\n")?;
        for param in &self.params {
            write!(f, "  {}: {}\n", param.name, print_type(&param.ty))?;
        }
        write!(f, "Locals:\n")?;
        let locals_sorted: BTreeMap<&Symbol, &Type> = self.locals.iter().collect();
        for (name, ty) in locals_sorted {
            write!(f, "  {}: {}\n", name, print_type(ty))?;
        }
        for block in &self.blocks {
            write!(f, "{}", block)?;
        }
        Ok(())
    }
}

pub fn ast_to_sir(expr: &TypedExpr) -> WeldResult<SirFunction> {
    if let Lambda(ref params, ref body) = expr.kind {
        let mut func = SirFunction::new();
        func.sym_gen = SymbolGenerator::from_expression(expr);
        if func.sym_gen.next_id("tmp") == 0 {
            func.sym_gen.new_symbol("tmp");
        }
        func.params = params.clone();
        let first_block = func.add_block();
        let mut dummy_closure = HashSet::new();
        let (res_block, res_sym) = gen_expr(body, &mut func, &mut dummy_closure, first_block)?;
        func.blocks[res_block].terminator = Terminator::Return(res_sym);
        Ok((func))
    } else {
        weld_err!("Expression passed to ast_to_sir was not a Lambda")
    }
}

/// Generate code to compute the expression `expr` starting at the current tail of `cur_block`,
/// possibly creating new basic blocks in the process. Return the basic block that the expression
/// will be ready in, and its symbol therein.
fn gen_expr(
    expr: &TypedExpr,
    func: &mut SirFunction,
    loop_closure: &mut HashSet<Symbol>,
    cur_block: BasicBlockId
) -> WeldResult<(BasicBlockId, Symbol)> {
    use self::Statement::*;
    use self::Terminator::*;
    match expr.kind {
        Ident(ref sym) => {
            loop_closure.insert(sym.clone());
            Ok((cur_block, sym.clone()))
        },

        Literal(lit) => {
            let res_sym = func.add_local(&expr.ty);
            func.blocks[cur_block].add_statement(AssignLiteral(res_sym.clone(), lit));
            Ok((cur_block, res_sym))
        },

        Let(ref sym, ref value, ref body) => {
            let (cur_block, val_sym) = gen_expr(value, func, loop_closure, cur_block)?;
            func.add_local_named(&value.ty, sym);
            func.blocks[cur_block].add_statement(Assign(sym.clone(), val_sym));
            let (cur_block, res_sym) = gen_expr(body, func, loop_closure, cur_block)?;
            loop_closure.remove(sym);
            Ok((cur_block, res_sym))
        },

        BinOp(kind, ref left, ref right) => {
            let (cur_block, left_sym) = gen_expr(left, func, loop_closure, cur_block)?;
            let (cur_block, right_sym) = gen_expr(right, func, loop_closure, cur_block)?;
            let res_sym = func.add_local(&expr.ty);
            func.blocks[cur_block].add_statement(
                AssignBinOp(res_sym.clone(), kind, left.ty.clone(), left_sym, right_sym));
            Ok((cur_block, res_sym))
        },

        If(ref cond, ref on_true, ref on_false) => {
            let (cur_block, cond_sym) = gen_expr(cond, func, loop_closure, cur_block)?;
            let true_block = func.add_block();
            let false_block = func.add_block();
            func.blocks[cur_block].terminator = Branch(cond_sym, true_block, false_block);
            let (true_block, true_sym) = gen_expr(on_true, func, loop_closure, true_block)?;
            let (false_block, false_sym) = gen_expr(on_false, func, loop_closure, false_block)?;
            let res_sym = func.add_local(&expr.ty);
            let res_block = func.add_block();
            func.blocks[true_block].add_statement(Assign(res_sym.clone(), true_sym));
            func.blocks[true_block].terminator = Jump(res_block);
            func.blocks[false_block].add_statement(Assign(res_sym.clone(), false_sym));
            func.blocks[false_block].terminator = Jump(res_block);
            Ok((res_block, res_sym))
        },

        Merge(ref builder, ref elem) => {
            let (cur_block, builder_sym) = gen_expr(builder, func, loop_closure, cur_block)?;
            let (cur_block, elem_sym) = gen_expr(elem, func, loop_closure, cur_block)?;
            let res_sym = func.add_local(&expr.ty);
            func.blocks[cur_block].add_statement(DoMerge(res_sym.clone(), builder_sym, elem_sym));
            Ok((cur_block, res_sym))
        },

        Res(ref builder) => {
            let (cur_block, builder_sym) = gen_expr(builder, func, loop_closure, cur_block)?;
            let res_sym = func.add_local(&expr.ty);
            func.blocks[cur_block].add_statement(GetResult(res_sym.clone(), builder_sym));
            Ok((cur_block, res_sym))
        },

        NewBuilder => {
            let res_sym = func.add_local(&expr.ty);
            func.blocks[cur_block].add_statement(CreateBuilder(res_sym.clone(), expr.ty.clone()));
            Ok((cur_block, res_sym))
        },

        For(ref data, ref builder, ref update) => {
            if let Lambda(ref params, ref body) = update.kind {
                let mut inner_closure = HashSet::new();
                let (cur_block, data_sym) = gen_expr(data, func, loop_closure, cur_block)?;
                let (cur_block, builder_sym) = gen_expr(builder, func, loop_closure, cur_block)?;
                let body_block = func.add_block();
                let (body_end_block, body_res) = gen_expr(body, func, &mut inner_closure, body_block)?;
                inner_closure.remove(&params[0].name);
                inner_closure.remove(&params[1].name);
                func.blocks[body_end_block].terminator = Return(body_res);
                let exit_block = func.add_block();
                let res_sym = func.add_local(&expr.ty);
                func.blocks[cur_block].terminator = ParallelFor {
                    data: data_sym,
                    builder: builder_sym,
                    body: body_block,
                    data_arg: params[0].name.clone(),
                    closure: inner_closure.clone(),
                    builder_arg: params[1].name.clone(),
                    exit: exit_block,
                    result: res_sym.clone()
                };
                for x in &inner_closure {
                  loop_closure.insert(x.clone());
                }
                Ok((exit_block, res_sym))
            } else {
                weld_err!("Argument to For was not a Lambda: {}", print_expr(update))
            }
        },

        _ => weld_err!("Unsupported expression: {}", print_expr(expr))
    }
}
<commit_msg>separate function generation<commit_after>//! Sequential IR for Weld programs

use std::fmt;
use std::collections::{BTreeMap, HashMap, HashSet};

use super::ast::*;
use super::ast::ExprKind::*;
use super::error::*;
use super::pretty_print::*;
use super::util::SymbolGenerator;

type BasicBlockId = usize;
type SirFunctionId = usize;

/// A non-terminating statement inside a basic block.
#[derive(Clone)]
pub enum Statement {
    /// output, op, type, left, right
    AssignBinOp(Symbol, BinOpKind, Type, Symbol, Symbol),
    /// output, value
    Assign(Symbol, Symbol),
    /// output, value
    AssignLiteral(Symbol, LiteralKind),
    /// output, builder, value
    DoMerge(Symbol, Symbol, Symbol),
    /// output, builder
    GetResult(Symbol, Symbol),
    /// output, builder type
    CreateBuilder(Symbol, Type),
}

/// A terminating statement inside a basic block.
#[derive(Clone)]
pub enum Terminator {
    /// condition, on_true, on_false
    Branch(Symbol, BasicBlockId, BasicBlockId),
    JumpBlock(BasicBlockId),
    JumpFunction(SirFunctionId),
    Return(Symbol),
    ParallelFor {
        data: Symbol,
        builder: Symbol,
        data_arg: Symbol,
        builder_arg: Symbol,
        body: SirFunctionId,
        cont: SirFunctionId
    },
    Crash
}

/// A basic block inside a SIR program
#[derive(Clone)]
pub struct BasicBlock {
    id: BasicBlockId,
    statements: Vec<Statement>,
    terminator: Terminator
}

pub struct SirFunction {
    id: SirFunctionId,
    params: HashMap<Symbol, Type>,
    locals: HashMap<Symbol, Type>,
    blocks: Vec<BasicBlock>
}

pub struct SirProgram {
    /// funcs[0] is the main function
    funcs: Vec<SirFunction>,
    sym_gen: SymbolGenerator
}

impl SirProgram {
    pub fn new() -> SirProgram {
        let mut prog = SirProgram {
            funcs: vec![],
            sym_gen: SymbolGenerator::new()
        };
        /// add main
        prog.add_func();
        prog
    }

    pub fn add_func(&mut self) -> SirFunctionId {
        let func = SirFunction {
            id: self.funcs.len(),
            params: HashMap::new(),
            blocks: vec![],
            locals: HashMap::new()
        };
        self.funcs.push(func);
        self.funcs.len() - 1
    }

    /// Add a local variable of the given type and return a symbol for it.
    pub fn add_local(&mut self, ty: &Type, func: SirFunctionId) -> Symbol {
        let sym = self.sym_gen.new_symbol(format!("fn{}_tmp", func).as_str());
        self.funcs[func].locals.insert(sym.clone(), ty.clone());
        sym
    }

    /// Add a local variable of the given type and name
    pub fn add_local_named(&mut self, ty: &Type, sym: &Symbol, func: SirFunctionId) {
        self.funcs[func].locals.insert(sym.clone(), ty.clone());
    }
}

impl SirFunction {
    /// Add a new basic block and return its block ID.
    pub fn add_block(&mut self) -> BasicBlockId {
        let block = BasicBlock {
            id: self.blocks.len(),
            statements: vec![],
            terminator: Terminator::Crash
        };
        self.blocks.push(block);
        self.blocks.len() - 1
    }
}

impl BasicBlock {
    pub fn add_statement(&mut self, statement: Statement) {
        self.statements.push(statement);
    }
}

impl fmt::Display for Statement {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Statement::*;
        match *self {
            AssignBinOp(ref out, ref op, ref ty, ref left, ref right) => {
                write!(f, "{} = {} {} {} {}", out, op, print_type(ty), left, right)
            },
            Assign(ref out, ref value) => write!(f, "{} = {}", out, value),
            AssignLiteral(ref out, ref lit) => write!(f, "{} = {}", out, print_literal(lit)),
            DoMerge(ref out, ref bld, ref elem) => write!(f, "{} = merge {} {}", out, bld, elem),
            GetResult(ref out, ref value) => write!(f, "{} = result {}", out, value),
            CreateBuilder(ref out, ref ty) => write!(f, "{} = new {}", out, print_type(ty)),
        }
    }
}

impl fmt::Display for Terminator {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Terminator::*;
        match *self {
            Branch(ref cond, ref on_true, ref on_false) => {
                write!(f, "branch {} B{} B{}", cond, on_true, on_false)
            },
            ParallelFor {
                ref data, ref builder, ref data_arg, ref builder_arg, body, cont
            } => {
                write!(f, "for {} {} {} {} F{} F{}",
                    data, builder, data_arg, builder_arg, body, cont)?;
                Ok(())
            },
            JumpBlock(block) => write!(f, "jump B{}", block),
            JumpFunction(func) => write!(f, "jump F{}", func),
            Return(ref sym) => write!(f, "return {}", sym),
            Crash => write!(f, "crash")
        }
    }
}

impl fmt::Display for BasicBlock {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "B{}:\n", self.id)?;
        for stmt in &self.statements {
            write!(f, "  {}\n", stmt)?;
        }
        write!(f, "  {}\n", self.terminator)?;
        Ok(())
    }
}

impl fmt::Display for SirFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "F{}:\n", self.id)?;
        write!(f, "Params:\n")?;
        let params_sorted: BTreeMap<&Symbol, &Type> = self.params.iter().collect();
        for (name, ty) in params_sorted {
            write!(f, "  {}: {}\n", name, print_type(ty))?;
        }
        write!(f, "Locals:\n")?;
        let locals_sorted: BTreeMap<&Symbol, &Type> = self.locals.iter().collect();
        for (name, ty) in locals_sorted {
            write!(f, "  {}: {}\n", name, print_type(ty))?;
        }
        for block in &self.blocks {
            write!(f, "{}", block)?;
        }
        Ok(())
    }
}

impl fmt::Display for SirProgram {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for func in &self.funcs {
            write!(f, "{}\n", func)?;
        }
        Ok(())
    }
}

pub fn sir_param_correction_helper(prog: &mut SirProgram, func_id: SirFunctionId, env: &mut HashMap<Symbol, Type>,
closure: &mut HashSet<Symbol>) {
    for (name, ty) in &prog.funcs[func_id].params {
        env.insert(name.clone(), ty.clone());
    }
    for (name, ty) in &prog.funcs[func_id].locals {
        env.insert(name.clone(), ty.clone());
    }
    /// All symbols are unique, so there is no need to remove stuff from env at any point.
    for block in prog.funcs[func_id].blocks.clone() {
        let mut vars = vec![];
        for statement in &block.statements {
            use self::Statement::*;
            match *statement {
                AssignBinOp(_, _, _, ref left, ref right) => {
                    vars.push(left.clone());
                    vars.push(right.clone());
                },
                Assign(_, ref value) => vars.push(value.clone()),
                DoMerge(_, ref bld, ref elem) => {
                    vars.push(bld.clone());
                    vars.push(elem.clone());
                },
                GetResult(_, ref value) => vars.push(value.clone()),
                _ => {}
            }
        }
        for var in &vars {
            if prog.funcs[func_id].locals.get(&var) == None {
                prog.funcs[func_id].params.insert(var.clone(), env.get(&var).unwrap().clone());
                closure.insert(var.clone());
            }
        }
        let mut inner_closure = HashSet::new();
        use self::Terminator::*;
        match block.terminator {
            // TODO how do we get rid of unused variable warnings here?
            ParallelFor {data, builder, data_arg, builder_arg, body, cont} => {
                sir_param_correction_helper(prog, body, env, &mut inner_closure);
                sir_param_correction_helper(prog, cont, env, &mut inner_closure);
            },
            JumpFunction(jump_func) => {
                sir_param_correction_helper(prog, jump_func, env, &mut inner_closure);
            },
            _ => {}
        }
        for var in inner_closure {
            if prog.funcs[func_id].locals.get(&var) == None {
                prog.funcs[func_id].params.insert(var.clone(), env.get(&var).unwrap().clone());
                closure.insert(var.clone());
            }
        }
    }
}

pub fn sir_param_correction(prog: &mut SirProgram) -> WeldResult<()> {
    let mut env = HashMap::new();
    let mut closure = HashSet::new();
    sir_param_correction_helper(prog, 0, &mut env, &mut closure);
    let ref func = prog.funcs[0];
    for name in closure {
        if func.params.get(&name) == None {
            weld_err!("Unbound symbol {}#{}", name.name, name.id)?;
        }
    }
    Ok(())
}

/// symbols must be unique in expr
pub fn ast_to_sir(expr: &TypedExpr) -> WeldResult<SirProgram> {
    if let Lambda(ref params, ref body) = expr.kind {
        let mut prog = SirProgram::new();
        prog.sym_gen = SymbolGenerator::from_expression(expr);
        for tp in params {
            prog.funcs[0].params.insert(tp.name.clone(), tp.ty.clone());
        }
        let first_block = prog.funcs[0].add_block();
        let (res_func, res_block, res_sym) = gen_expr(body, &mut prog, 0, first_block)?;
        // TODO we probably want this to be a special kind of return for the final program result
        prog.funcs[res_func].blocks[res_block].terminator = Terminator::Return(res_sym);
        sir_param_correction(&mut prog)?;
        Ok((prog))
    } else {
        weld_err!("Expression passed to ast_to_sir was not a Lambda")
    }
}

/// Generate code to compute the expression `expr` starting at the current tail of `cur_block`,
/// possibly creating new basic blocks and functions in the process. Return the basic block that
/// the expression will be ready in, and its symbol therein.
fn gen_expr(
    expr: &TypedExpr,
    prog: &mut SirProgram,
    cur_func: SirFunctionId,
    cur_block: BasicBlockId
) -> WeldResult<(SirFunctionId, BasicBlockId, Symbol)> {
    use self::Statement::*;
    use self::Terminator::*;
    match expr.kind {
        Ident(ref sym) => {
            Ok((cur_func, cur_block, sym.clone()))
        },

        Literal(lit) => {
            let res_sym = prog.add_local(&expr.ty, cur_func);
            prog.funcs[cur_func].blocks[cur_block].add_statement(AssignLiteral(res_sym.clone(), lit));
            Ok((cur_func, cur_block, res_sym))
        },

        Let(ref sym, ref value, ref body) => {
            let (cur_func, cur_block, val_sym) = gen_expr(value, prog, cur_func, cur_block)?;
            prog.add_local_named(&value.ty, sym, cur_func);
            prog.funcs[cur_func].blocks[cur_block].add_statement(Assign(sym.clone(), val_sym));
            let (cur_func, cur_block, res_sym) = gen_expr(body, prog, cur_func, cur_block)?;
            Ok((cur_func, cur_block, res_sym))
        },

        BinOp(kind, ref left, ref right) => {
            let (cur_func, cur_block, left_sym) = gen_expr(left, prog, cur_func, cur_block)?;
            let (cur_func, cur_block, right_sym) = gen_expr(right, prog, cur_func, cur_block)?;
            let res_sym = prog.add_local(&expr.ty, cur_func);
            prog.funcs[cur_func].blocks[cur_block].add_statement(
                AssignBinOp(res_sym.clone(), kind, left.ty.clone(), left_sym, right_sym));
            Ok((cur_func, cur_block, res_sym))
        },

        If(ref cond, ref on_true, ref on_false) => {
            let (cur_func, cur_block, cond_sym) = gen_expr(cond, prog, cur_func, cur_block)?;
            let true_block = prog.funcs[cur_func].add_block();
            let false_block = prog.funcs[cur_func].add_block();
            prog.funcs[cur_func].blocks[cur_block].terminator = Branch(cond_sym, true_block, false_block);
            let (true_func, true_block, true_sym) = gen_expr(on_true, prog, cur_func, true_block)?;
            let (false_func, false_block, false_sym) = gen_expr(on_false, prog, cur_func, false_block)?;
            let res_sym = prog.add_local(&expr.ty, true_func);
            prog.funcs[true_func].blocks[true_block].add_statement(Assign(res_sym.clone(), true_sym));
            prog.funcs[false_func].blocks[false_block].add_statement(Assign(res_sym.clone(), false_sym));
            if true_func != cur_func || false_func != cur_func {
                // TODO we probably want a better for name for this symbol than whatever res_sym is
                prog.add_local_named(&expr.ty, &res_sym, false_func);
                let cont_func = prog.add_func();
                let cont_block = prog.funcs[cont_func].add_block();
                prog.funcs[true_func].blocks[true_block].terminator = JumpFunction(cont_func);
                prog.funcs[false_func].blocks[false_block].terminator = JumpFunction(cont_func);
                Ok((cont_func, cont_block, res_sym))
            } else {
                let cont_block = prog.funcs[cur_func].add_block();
                prog.funcs[true_func].blocks[true_block].terminator = JumpBlock(cont_block);
                prog.funcs[false_func].blocks[false_block].terminator = JumpBlock(cont_block);
                Ok((cur_func, cont_block, res_sym))
            }
        },

        Merge(ref builder, ref elem) => {
            let (cur_func, cur_block, builder_sym) = gen_expr(builder, prog, cur_func, cur_block)?;
            let (cur_func, cur_block, elem_sym) = gen_expr(elem, prog, cur_func, cur_block)?;
            let res_sym = prog.add_local(&expr.ty, cur_func);
            prog.funcs[cur_func].blocks[cur_block].add_statement(DoMerge(res_sym.clone(), builder_sym, elem_sym));
            Ok((cur_func, cur_block, res_sym))
        },

        Res(ref builder) => {
            let (cur_func, cur_block, builder_sym) = gen_expr(builder, prog, cur_func, cur_block)?;
            let res_sym = prog.add_local(&expr.ty, cur_func);
            prog.funcs[cur_func].blocks[cur_block].add_statement(GetResult(res_sym.clone(), builder_sym));
            Ok((cur_func, cur_block, res_sym))
        },

        NewBuilder => {
            let res_sym = prog.add_local(&expr.ty, cur_func);
            prog.funcs[cur_func].blocks[cur_block].add_statement(CreateBuilder(res_sym.clone(), expr.ty.clone()));
            Ok((cur_func, cur_block, res_sym))
        },

        For(ref data, ref builder, ref update) => {
            if let Lambda(ref params, ref body) = update.kind {
                let (cur_func, cur_block, data_sym) = gen_expr(data, prog, cur_func, cur_block)?;
                let (cur_func, cur_block, builder_sym) = gen_expr(builder, prog, cur_func, cur_block)?;
                let body_func = prog.add_func();
                let body_block = prog.funcs[body_func].add_block();
                prog.add_local_named(&params[0].ty, &params[0].name, body_func);
                prog.add_local_named(&params[1].ty, &params[1].name, body_func);
                prog.funcs[body_func].params.insert(data_sym.clone(), data.ty.clone());
                prog.funcs[body_func].params.insert(builder_sym.clone(), builder.ty.clone());
                let (body_end_func, body_end_block, body_res) = gen_expr(body, prog, body_func, body_block)?;
                // TODO this is a useless line
                prog.funcs[body_end_func].blocks[body_end_block].terminator = Return(body_res);
                let cont_func = prog.add_func();
                let cont_block = prog.funcs[cont_func].add_block();
                prog.funcs[cur_func].blocks[cur_block].terminator = ParallelFor {
                    data: data_sym,
                    builder: builder_sym.clone(),
                    data_arg: params[0].name.clone(),
                    builder_arg: params[1].name.clone(),
                    body: body_func,
                    cont: cont_func
                };
                Ok((cont_func, cont_block, builder_sym))
            } else {
                weld_err!("Argument to For was not a Lambda: {}", print_expr(update))
            }
        },

        _ => weld_err!("Unsupported expression: {}", print_expr(expr))
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/main.rs
// - Kernel main
#![crate_name="kernel"]
#![crate_type="lib"]
#![feature(no_std)]
#![feature(asm)]	// Enables the asm! syntax extension
#![feature(box_syntax)]	// Enables 'box' syntax
#![feature(thread_local)]	// Allows use of thread_local
#![feature(lang_items)]	// Allow definition of lang_items
#![feature(core)]	// silences warnings about write!
#![feature(optin_builtin_traits)]	// Negative impls
#![feature(unique)]	// Unique
#![feature(slice_patterns)]	// Slice (array) destructuring patterns, used by multiboot code
#![feature(step_by)]	// Range::step_by
#![feature(linkage)]	// allows using #[linkage="external"]
#![feature(const_fn)]	// Allows defining `const fn`
#![no_std]

#![feature(plugin)]
#![feature(custom_attribute)]
#![plugin(tag_safe)]
use prelude::*;

#[macro_use]
extern crate core;

pub use arch::memory::PAGE_SIZE;

#[doc(hidden)]
#[macro_use] pub mod logmacros;
#[doc(hidden)]
#[macro_use] pub mod macros;
#[doc(hidden)]
#[macro_use] #[cfg(arch__amd64)] #[path="arch/amd64/mod-macros.rs"] pub mod arch_macros;

// Evil Hack: For some reason, write! (and friends) will expand pointing to std instead of core
#[doc(hidden)]
mod std {
	pub use core::option;
	pub use core::{default,fmt,cmp};
	pub use core::marker;	// needed for derive(Copy)
	pub use core::iter;	// needed for 'for'
}

/// Kernel's version of 'std::prelude'
pub mod prelude;

/// Library datatypes (Vec, Queue, ...)
#[macro_use]
pub mod lib;	// Clone of libstd

/// Heavy synchronisation primitives (Mutex, Semaphore, RWLock, ...)
#[macro_use]
pub mod sync;

/// Asynchrnous wait support
pub mod async;

/// Logging framework
pub mod logging;
/// Memory management (physical, virtual, heap)
pub mod memory;
/// Thread management
#[macro_use]
pub mod threads;
/// Timekeeping (timers and wall time)
pub mod time;

// Module/Executable loading (and symbol lookup)
pub mod loading;
/// Module management (loading and initialisation of kernel modules)
pub mod modules;

/// Meta devices (the Hardware Abstraction Layer)
pub mod metadevs;
/// Device to driver mapping manager
///
/// Starts driver instances for the devices it sees
pub mod device_manager;

/// User output, via a kernel-provided compositing "WM"
pub mod gui;

// Public for driver modules
pub mod vfs;

mod config;

/// Stack unwinding (panic) handling
pub mod unwind;

pub mod irqs;

pub mod syscalls;

/// Built-in device drivers
mod hw;

/// Achitecture-specific code - AMD64 (aka x86-64)
#[macro_use]
#[cfg(arch__amd64)] #[path="arch/amd64/mod.rs"] pub mod arch;	// Needs to be pub for exports to be avaliable

/// Kernel entrypoint
#[no_mangle]
pub extern "C" fn kmain()
{
	log_notice!("Tifflin Kernel v{} build {} starting", env!("TK_VERSION"), env!("TK_BUILD"));
	log_notice!("> Git state : {}", env!("TK_GITSPEC"));
	log_notice!("> Built with {}", env!("RUST_VERSION"));

	// Initialise core services before attempting modules
	::memory::phys::init();
	::memory::virt::init();
	::memory::heap::init();
	::threads::init();

	log_log!("Command line = '{}'", ::arch::boot::get_boot_string());
	::config::init( ::arch::boot::get_boot_string() );

	// Dump active video mode
	let vidmode = ::arch::boot::get_video_mode();
	match vidmode {
	Some(m) => {
		log_debug!("Video mode : {}x{} @ {:#x}", m.width, m.height, m.base);
		::metadevs::video::set_boot_mode(m);
		},
	None => log_debug!("No video mode present")
	}

	// Modules (dependency tree included)
	// - Requests that the GUI be started as soon as possible
	::modules::init(&["GUI"]);

	// Yield to allow init threads to run
	::threads::yield_time();

	// Run system init
	sysinit();

	// Thread 0 idle loop
	log_info!("Entering idle");
	loop
	{
		log_trace!("TID0 napping");
		::threads::yield_time();
	}
}

// Initialise the system once drivers are up
fn sysinit()
{
	use metadevs::storage::VolumeHandle;
	use vfs::{mount,handle};
	use vfs::Path;

	// 1. Mount /system to the specified volume
	let sysdisk = ::config::get_string(::config::Value::SysDisk);
	match VolumeHandle::open_named(sysdisk)
	{
	Err(e) => {
		log_error!("Unable to open /system volume {}: {}", sysdisk, e);
		return ;
		},
	Ok(vh) => match mount::mount("/system".as_ref(), vh, "", &[])
		{
		Ok(_) => {},
		Err(e) => {
			log_error!("Unable to mount /system from {}: {:?}", sysdisk, e);
			return ;
			},
		},
	}

	// 2. Symbolic link /sysroot to the specified folder
	let sysroot = ::config::get_string(::config::Value::SysRoot);
	handle::Dir::open(Path::new("/")).unwrap()
		.symlink("sysroot", Path::new(sysroot)).unwrap();

	// 3. Start 'init' (parent process)
	// XXX: hard-code the sysroot path here to avoid having to handle symlinks yet
	spawn_init("/system/Tifflin/bin/loader", "/sysroot/Tifflin/bin/init");

	fn ls(p: &Path) {
		// - Iterate root dir
		match handle::Dir::open(p)
		{
		Err(e) => log_warning!("'{:?}' cannot be opened: {:?}", p, e),
		Ok(h) =>
			for name in h.iter() {
				log_log!("{:?}", name);
			},
		}
	}

	// *. Testing: open a file known to exist on the testing disk
	{
		match handle::File::open( Path::new("/system/1.TXT"), handle::FileOpenMode::SharedRO )
		{
		Err(e) => log_warning!("VFS test file can't be opened: {:?}", e),
		Ok(h) => {
			log_debug!("VFS open test = {:?}", h);
			let mut buf = [0; 16];
			let sz = h.read(0, &mut buf).unwrap();
			log_debug!("- Contents: {:?}", ::lib::RawString(&buf[..sz]));
			},
		}

		ls(Path::new("/"));
		ls(Path::new("/system"));
	}

	// *. TEST Automount
	// - Probably shouldn't be included in the final version, but works for testing filesystem and storage drivers
	let mountdir = handle::Dir::open( Path::new("/") ).and_then(|h| h.mkdir("mount")).unwrap();
	for (_,v) in ::metadevs::storage::enum_lvs()
	{
		let vh = match VolumeHandle::open_named(&v)
			{
			Err(e) => {
				log_log!("Unable to open '{}': {}", v, e);
				continue;
				},
			Ok(v) => v,
			};
		mountdir.mkdir(&v).unwrap();
		let mountpt = format!("/mount/{}",v);
		match mount::mount( mountpt.as_ref(), vh, "", &[] )
		{
		Ok(_) => log_log!("Auto-mounted to {}", mountpt),
		Err(e) => log_notice!("Unable to automount '{}': {:?}", v, e),
		}
	}
	ls(Path::new("/mount/ATA-2w"));
}

fn spawn_init(loader_path: &str, init_cmdline: &str)
{
	use vfs::handle;
	use vfs::Path;

	#[repr(C)]
	struct LoaderHeader
	{
		magic: u32,
		info: u32,
		codesize: u32,
		memsize: u32,
		entrypoint: usize,
		init_path: usize,
	}
	const MAGIC: u32 = 0x71FF1013;
	#[cfg(arch__amd64)]
	const INFO: u32 = (3*4+2*8) | (2 << 8);
	#[cfg(arch__amd64)]
	const LOAD_MAX: usize = 1 << 47;

	// - 1. Memory-map the loader binary to a per-architecture location
	//  > E.g. for x86 it'd be 0xBFFF0000 - Limiting it to 64KiB
	//  > For amd64: 1<<48-64KB
	//  > PANIC if the binary (or its memory size) is too large
	let loader = match handle::File::open(Path::new(loader_path), handle::FileOpenMode::Execute)
		{
		Ok(v) => v,
		Err(e) => {
			log_error!("Unable to open initial userland loader '{}': {:?}", loader_path, e);
			return ;
			},
		};
	let max_size: usize = 64*1024;
	let load_base: usize = LOAD_MAX - max_size;
	let ondisk_size = loader.size();
	{
		if ondisk_size > max_size as u64 {
			log_error!("Loader is too large to fit in reserved region ({}, max {})",
				ondisk_size, max_size);
			return ;
		}
		let maphandle = loader.memory_map(load_base,  0, ::PAGE_SIZE,  handle::MemoryMapMode::Execute);
		::core::mem::forget(maphandle);
	}
	// - 2. Parse the header
	let header_ptr = unsafe { &*(load_base as *const LoaderHeader) };
	if header_ptr.magic != 0x71FF1013 || header_ptr.info != INFO {
		log_error!("Loader header is invalid: magic {:#x} != {:#x} or info {:#x} != {:#x}",
			header_ptr.magic, MAGIC, header_ptr.info, INFO);
		return ;
	}
	// - 3. Map the remainder of the image into memory (with correct permissions)
	let codesize = header_ptr.codesize as usize;
	let datasize = ondisk_size as usize - codesize;
	let bss_size = header_ptr.memsize as usize - ondisk_size as usize;
	log_debug!("Executable size: {}, rw data size: {}", codesize, datasize);
	::core::mem::forget( loader.memory_map(load_base + ::PAGE_SIZE, ::PAGE_SIZE as u64, codesize - ::PAGE_SIZE,  handle::MemoryMapMode::Execute) );
	assert!(codesize % ::PAGE_SIZE == 0, "Loader code doesn't end on a page boundary - {:#x}", codesize);
	::core::mem::forget( loader.memory_map(load_base + codesize, codesize as u64, datasize,  handle::MemoryMapMode::COW) );
	// - 4. Allocate the loaders's BSS
	assert!(ondisk_size as usize % ::PAGE_SIZE == 0, "Loader file size is not aligned to a page - {:#x}", ondisk_size);
	let pages = (bss_size + ::PAGE_SIZE) / ::PAGE_SIZE;
	let bss_start = (load_base + ondisk_size as usize) as *mut ();
	::core::mem::forget( ::memory::virt::allocate(bss_start, pages/*, ::memory::virt::ProtectionMode::UserRW*/) );
	// - 5. Write loader arguments
	if header_ptr.init_path < load_base+codesize || header_ptr.init_path + init_cmdline.len() >= load_base + LOAD_MAX {
		log_error!("Userland init string location out of range: {:#x}", header_ptr.init_path);
		return ;
	}
	// - 6. Enter userland
	if header_ptr.entrypoint < load_base || header_ptr.entrypoint >= load_base + LOAD_MAX {
		log_error!("Userland entrypoint out of range: {:#x}", header_ptr.entrypoint);
		return ;
	}
	// TODO: Instead hand this handle over to the syscall layer, as the first user file
	::core::mem::forget(loader);
	// SAFE: This pointer is as validated as it can be...
	unsafe {
		::arch::drop_to_user(header_ptr.entrypoint);
	}
}

// vim: ft=rust

<commit_msg>Kernel/main - Minor cleanup to loader loading<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/main.rs
// - Kernel main
#![crate_name="kernel"]
#![crate_type="lib"]
#![feature(no_std)]
#![feature(asm)]	// Enables the asm! syntax extension
#![feature(box_syntax)]	// Enables 'box' syntax
#![feature(thread_local)]	// Allows use of thread_local
#![feature(lang_items)]	// Allow definition of lang_items
#![feature(core)]	// silences warnings about write!
#![feature(optin_builtin_traits)]	// Negative impls
#![feature(unique)]	// Unique
#![feature(slice_patterns)]	// Slice (array) destructuring patterns, used by multiboot code
#![feature(step_by)]	// Range::step_by
#![feature(linkage)]	// allows using #[linkage="external"]
#![feature(const_fn)]	// Allows defining `const fn`
#![no_std]

#![feature(plugin)]
#![feature(custom_attribute)]
#![plugin(tag_safe)]
use prelude::*;

#[macro_use]
extern crate core;

pub use arch::memory::PAGE_SIZE;

#[doc(hidden)]
#[macro_use] pub mod logmacros;
#[doc(hidden)]
#[macro_use] pub mod macros;
#[doc(hidden)]
#[macro_use] #[cfg(arch__amd64)] #[path="arch/amd64/mod-macros.rs"] pub mod arch_macros;

// Evil Hack: For some reason, write! (and friends) will expand pointing to std instead of core
#[doc(hidden)]
mod std {
	pub use core::option;
	pub use core::{default,fmt,cmp};
	pub use core::marker;	// needed for derive(Copy)
	pub use core::iter;	// needed for 'for'
}

/// Kernel's version of 'std::prelude'
pub mod prelude;

/// Library datatypes (Vec, Queue, ...)
#[macro_use]
pub mod lib;	// Clone of libstd

/// Heavy synchronisation primitives (Mutex, Semaphore, RWLock, ...)
#[macro_use]
pub mod sync;

/// Asynchrnous wait support
pub mod async;

/// Logging framework
pub mod logging;
/// Memory management (physical, virtual, heap)
pub mod memory;
/// Thread management
#[macro_use]
pub mod threads;
/// Timekeeping (timers and wall time)
pub mod time;

// Module/Executable loading (and symbol lookup)
pub mod loading;
/// Module management (loading and initialisation of kernel modules)
pub mod modules;

/// Meta devices (the Hardware Abstraction Layer)
pub mod metadevs;
/// Device to driver mapping manager
///
/// Starts driver instances for the devices it sees
pub mod device_manager;

/// User output, via a kernel-provided compositing "WM"
pub mod gui;

// Public for driver modules
pub mod vfs;

mod config;

/// Stack unwinding (panic) handling
pub mod unwind;

pub mod irqs;

pub mod syscalls;

/// Built-in device drivers
mod hw;

/// Achitecture-specific code - AMD64 (aka x86-64)
#[macro_use]
#[cfg(arch__amd64)] #[path="arch/amd64/mod.rs"] pub mod arch;	// Needs to be pub for exports to be avaliable

/// Kernel entrypoint
#[no_mangle]
pub extern "C" fn kmain()
{
	log_notice!("Tifflin Kernel v{} build {} starting", env!("TK_VERSION"), env!("TK_BUILD"));
	log_notice!("> Git state : {}", env!("TK_GITSPEC"));
	log_notice!("> Built with {}", env!("RUST_VERSION"));

	// Initialise core services before attempting modules
	::memory::phys::init();
	::memory::virt::init();
	::memory::heap::init();
	::threads::init();

	log_log!("Command line = '{}'", ::arch::boot::get_boot_string());
	::config::init( ::arch::boot::get_boot_string() );

	// Dump active video mode
	let vidmode = ::arch::boot::get_video_mode();
	match vidmode {
	Some(m) => {
		log_debug!("Video mode : {}x{} @ {:#x}", m.width, m.height, m.base);
		::metadevs::video::set_boot_mode(m);
		},
	None => log_debug!("No video mode present")
	}

	// Modules (dependency tree included)
	// - Requests that the GUI be started as soon as possible
	::modules::init(&["GUI"]);

	// Yield to allow init threads to run
	::threads::yield_time();

	// Run system init
	sysinit();

	// Thread 0 idle loop
	log_info!("Entering idle");
	loop
	{
		log_trace!("TID0 napping");
		::threads::yield_time();
	}
}

// Initialise the system once drivers are up
fn sysinit()
{
	use metadevs::storage::VolumeHandle;
	use vfs::{mount,handle};
	use vfs::Path;

	// 1. Mount /system to the specified volume
	let sysdisk = ::config::get_string(::config::Value::SysDisk);
	match VolumeHandle::open_named(sysdisk)
	{
	Err(e) => {
		log_error!("Unable to open /system volume {}: {}", sysdisk, e);
		return ;
		},
	Ok(vh) => match mount::mount("/system".as_ref(), vh, "", &[])
		{
		Ok(_) => {},
		Err(e) => {
			log_error!("Unable to mount /system from {}: {:?}", sysdisk, e);
			return ;
			},
		},
	}

	// 2. Symbolic link /sysroot to the specified folder
	let sysroot = ::config::get_string(::config::Value::SysRoot);
	handle::Dir::open(Path::new("/")).unwrap()
		.symlink("sysroot", Path::new(sysroot)).unwrap();

	// 3. Start 'init' (parent process)
	// XXX: hard-code the sysroot path here to avoid having to handle symlinks yet
	spawn_init("/system/Tifflin/bin/loader", "/sysroot/Tifflin/bin/init");

	fn ls(p: &Path) {
		// - Iterate root dir
		match handle::Dir::open(p)
		{
		Err(e) => log_warning!("'{:?}' cannot be opened: {:?}", p, e),
		Ok(h) =>
			for name in h.iter() {
				log_log!("{:?}", name);
			},
		}
	}

	// *. Testing: open a file known to exist on the testing disk
	{
		match handle::File::open( Path::new("/system/1.TXT"), handle::FileOpenMode::SharedRO )
		{
		Err(e) => log_warning!("VFS test file can't be opened: {:?}", e),
		Ok(h) => {
			log_debug!("VFS open test = {:?}", h);
			let mut buf = [0; 16];
			let sz = h.read(0, &mut buf).unwrap();
			log_debug!("- Contents: {:?}", ::lib::RawString(&buf[..sz]));
			},
		}

		ls(Path::new("/"));
		ls(Path::new("/system"));
	}

	// *. TEST Automount
	// - Probably shouldn't be included in the final version, but works for testing filesystem and storage drivers
	let mountdir = handle::Dir::open( Path::new("/") ).and_then(|h| h.mkdir("mount")).unwrap();
	for (_,v) in ::metadevs::storage::enum_lvs()
	{
		let vh = match VolumeHandle::open_named(&v)
			{
			Err(e) => {
				log_log!("Unable to open '{}': {}", v, e);
				continue;
				},
			Ok(v) => v,
			};
		mountdir.mkdir(&v).unwrap();
		let mountpt = format!("/mount/{}",v);
		match mount::mount( mountpt.as_ref(), vh, "", &[] )
		{
		Ok(_) => log_log!("Auto-mounted to {}", mountpt),
		Err(e) => log_notice!("Unable to automount '{}': {:?}", v, e),
		}
	}
	ls(Path::new("/mount/ATA-2w"));
}

fn spawn_init(loader_path: &str, init_cmdline: &str)
{
	use vfs::handle;
	use vfs::Path;
	use core::mem::forget;

	#[repr(C)]
	struct LoaderHeader
	{
		magic: u32,
		info: u32,
		codesize: u32,
		memsize: u32,
		entrypoint: usize,
		init_path: usize,
	}
	const MAGIC: u32 = 0x71FF1013;
	#[cfg(arch__amd64)]
	const INFO: u32 = (3*4+2*8) | (2 << 8);
	#[cfg(arch__amd64)]
	const LOAD_MAX: usize = 1 << 47;

	// - 1. Memory-map the loader binary to a per-architecture location
	//  > E.g. for x86 it'd be 0xBFFF0000 - Limiting it to 64KiB
	//  > For amd64: 1<<48-64KB
	//  > PANIC if the binary (or its memory size) is too large
	let loader = match handle::File::open(Path::new(loader_path), handle::FileOpenMode::Execute)
		{
		Ok(v) => v,
		Err(e) => {
			log_error!("Unable to open initial userland loader '{}': {:?}", loader_path, e);
			return ;
			},
		};
	let max_size: usize = 64*1024;
	let load_base: usize = LOAD_MAX - max_size;
	let ondisk_size = loader.size();
	let mh_firstpage = {
		if ondisk_size > max_size as u64 {
			log_error!("Loader is too large to fit in reserved region ({}, max {})",
				ondisk_size, max_size);
			return ;
		}
		loader.memory_map(load_base,  0, ::PAGE_SIZE,  handle::MemoryMapMode::Execute)
		};
	// - 2. Parse the header
	let header_ptr = unsafe { &*(load_base as *const LoaderHeader) };
	if header_ptr.magic != 0x71FF1013 || header_ptr.info != INFO {
		log_error!("Loader header is invalid: magic {:#x} != {:#x} or info {:#x} != {:#x}",
			header_ptr.magic, MAGIC, header_ptr.info, INFO);
		return ;
	}
	// - 3. Map the remainder of the image into memory (with correct permissions)
	let codesize = header_ptr.codesize as usize;
	let datasize = ondisk_size as usize - codesize;
	let bss_size = header_ptr.memsize as usize - ondisk_size as usize;
	log_debug!("Executable size: {}, rw data size: {}", codesize, datasize);
	let mh_code = loader.memory_map(load_base + ::PAGE_SIZE, ::PAGE_SIZE as u64, codesize - ::PAGE_SIZE,  handle::MemoryMapMode::Execute);
	assert!(codesize % ::PAGE_SIZE == 0, "Loader code doesn't end on a page boundary - {:#x}", codesize);
	let mh_data = loader.memory_map(load_base + codesize, codesize as u64, datasize,  handle::MemoryMapMode::COW);

	// - 4. Allocate the loaders's BSS
	assert!(ondisk_size as usize % ::PAGE_SIZE == 0, "Loader file size is not aligned to a page - {:#x}", ondisk_size);
	let pages = (bss_size + ::PAGE_SIZE) / ::PAGE_SIZE;
	let bss_start = (load_base + ondisk_size as usize) as *mut ();
	let ah_bss = ::memory::virt::allocate(bss_start, pages/*, ::memory::virt::ProtectionMode::UserRW*/);

	// - 5. Write loader arguments
	if header_ptr.init_path < load_base+codesize || header_ptr.init_path + init_cmdline.len() >= load_base + LOAD_MAX {
		log_error!("Userland init string location out of range: {:#x}", header_ptr.init_path);
		return ;
	}
	// TODO: Write loader arguments into the provided location
	// TODO: Should the argument string length be passed down to the user? In memory, or via a register?

	// - 6. Enter userland
	if header_ptr.entrypoint < load_base || header_ptr.entrypoint >= load_base + LOAD_MAX {
		log_error!("Userland entrypoint out of range: {:#x}", header_ptr.entrypoint);
		return ;
	}

	// > Forget about all maps and allocations
	//  ... Is this strictly nessesary? This function never resumes after drop_to_user.
	//  May be needed if the loader gets moved
	forget(mh_firstpage);
	forget(mh_code);
	forget(mh_data);
	forget(ah_bss);
	// > Forget the loader handle too
	// TODO: Instead hand this handle over to the syscall layer, as the first user file
	//forget(loader);
	// SAFE: This pointer is as validated as it can be...
	unsafe {
		::arch::drop_to_user(header_ptr.entrypoint);
	}
}

// vim: ft=rust

<|endoftext|>


<commit_before><commit_msg>Add removing comments from preprocessed output for clang<commit_after><|endoftext|>


<commit_before>use geom::point::Point;
use renderer::Renderer;
use frame::Frame;

use super::Scene;

pub struct DevelRenderer {
   scene: Scene,
   width: u32,
   height: u32,
}

impl DevelRenderer {
   #[inline]
   pub fn new(scene: Scene) -> Self {
      DevelRenderer {
         scene: scene,
         width: 0,
         height: 0,
      }
   }
}

impl Renderer for DevelRenderer {
   fn init(&mut self, width: u32, height: u32) {
      self.width = width;
      self.height = height;
   }

   fn render(&mut self, _: &mut Frame) {
      let points = &self.scene.polys[0].points;

      for i in 0..points.len() {
         println!("{:?}", points[i]);
      }

      let (left, right) = left_right_edges(points);

      for edge in &left {
         println!("{:?}", edge);
      }

      for edge in &right {
         println!("{:?}", edge);
      }

      panic!("END");
   }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct Edge {
   p1: Point,
   p2: Point,
}

impl Edge {
   #[inline]
   fn new(p1: Point, p2: Point) -> Self {
      Edge {
         p1: p1,
         p2: p2,
      }
   }
}

fn left_right_edges(points: &Vec<Point>) -> (Vec<Edge>, Vec<Edge>){
   let (_, _, min_i, max_i) = min_max_y_index(points);

   let left = left_edges(points, min_i, max_i);
   let right = right_edges(points, min_i, max_i);

   (left, right)
}

fn left_edges(points: &Vec<Point>, min_i: usize, max_i: usize) -> Vec<Edge> {
   let mut edges = Vec::new();

   let mut curr_i = min_i;
   let mut prev_i = curr_i;

   loop {
      curr_i += 1;

      if curr_i == points.len() {
         curr_i = 0;
      }

      edges.push(Edge::new(points[prev_i], points[curr_i]));

      prev_i = curr_i;

      if curr_i == max_i {
         break;
      }
   }

   edges
}

fn right_edges(points: &Vec<Point>, min_i: usize, max_i: usize) -> Vec<Edge> {
   let mut edges = Vec::new();

   let mut curr_i = min_i;
   let mut prev_i = curr_i;

   loop {
      if curr_i == 0 {
         curr_i = points.len() - 1;
      } else {
         curr_i -= 1;
      }

      edges.push(Edge::new(points[prev_i], points[curr_i]));

      prev_i = curr_i;

      if curr_i == max_i {
         break;
      }
   }

   edges
}

fn min_max_y_index(points: &Vec<Point>) -> (i64, i64, usize, usize) {
   let (first, rest) = points.split_first().unwrap();

   let mut min_y = first.y;
   let mut max_y = min_y;
   let mut min_i = 0;
   let mut max_i = 0;

   for (i, point) in rest.iter().enumerate() {
      if point.y < min_y {
         min_i = i + 1;
         min_y = point.y;
      } else if point.y > max_y {
         max_i = i + 1;
         max_y = point.y;
      }
   }

   (min_y, max_y, min_i, max_i)
}
<commit_msg>Finish the transfer of the initial development rasterization code<commit_after>use geom::point::Point;
use renderer::Renderer;
use frame::Frame;
use draw::RGB;

use super::Scene;

pub struct DevelRenderer {
   scene: Scene,
   aliased: Vec<RGB>,
   rendered: Vec<RGB>,
}

const SUBDIVISIONS: i64 = 3;

impl DevelRenderer {
   #[inline]
   pub fn new(scene: Scene) -> Self {
      DevelRenderer {
         scene: scene,

         aliased: vec!(),
         rendered: vec!(),
      }
   }

   fn resize(&mut self, width: u32, height: u32) {
      self.aliased.resize((width * height) as usize * (SUBDIVISIONS * SUBDIVISIONS) as usize, RGB::new(0, 0, 0));
      self.rendered.resize((width * height) as usize, RGB::new(0, 0, 0));
   }

   #[inline]
   fn clear(&mut self) {
      let mut aliased: &mut Vec<RGB> = self.aliased.as_mut();

      for i in 0..aliased.len() {
         aliased[i] = RGB::default();
      }
   }

   #[inline]
   fn render_aliased(&mut self, frame: &mut Frame) {
      let mut aliased: &mut Vec<RGB> = self.aliased.as_mut();

      for poly in &self.scene.polys {
         let points = &poly.points;

         let (left, right) = get_left_right_edges(points);

         let mut left_i = 0;
         let mut right_i = 0;

         let mut left_edge = left[left_i];
         let mut right_edge = right[right_i];

         let mut left_x = left_edge.p1.x;
         let mut right_x = right_edge.p1.x;

         let left_last_i = left.len() - 1;
         let right_last_i = right.len() - 1;

         let mut left_advancer = YAxisAdvancer::new(&left_edge);
         let mut right_advancer = YAxisAdvancer::new(&right_edge);

         let min_y = left_edge.p1.y;
         let max_y = left[left_last_i].p2.y;

         for y in min_y..max_y + 1 {
            if left_edge.p2.y == y && left_i != left_last_i {
               left_i += 1;
               left_edge = left[left_i];
               left_advancer = YAxisAdvancer::new(&left_edge);
            }

            if right_edge.p2.y == y && right_i != right_last_i  {
               right_i += 1;
               right_edge = right[right_i];
               right_advancer = YAxisAdvancer::new(&right_edge);
            }

            for x in left_x..right_x {
               aliased[y as usize * frame.width as usize * SUBDIVISIONS as usize + x as usize] = poly.color;
            }

            left_x = left_advancer.advance();
            right_x = right_advancer.advance();
         }
      }
   }

   #[inline]
   fn downsample(&mut self, frame: &mut Frame) {
      let aliased: &mut Vec<RGB> = self.aliased.as_mut();

      let rendered: &mut Vec<RGB> = self.rendered.as_mut();

      let divisor = (SUBDIVISIONS * SUBDIVISIONS) as u16;

      for y in 0..frame.height as usize {
         for x in 0..frame.width as usize {
            let mut r: u16 = 0;
            let mut g: u16 = 0;
            let mut b: u16 = 0;
            for box_y in 0..SUBDIVISIONS as usize {
               for box_x in 0..SUBDIVISIONS as usize {
                  let pos = (box_y + y * SUBDIVISIONS as usize * frame.width as usize * SUBDIVISIONS as usize) + box_x + x * SUBDIVISIONS as usize;
                  let color = &aliased[pos];
                  r += color.r as u16;
                  g += color.g as u16;
                  b += color.b as u16;
               }
            }

            r /= divisor;
            g /= divisor;
            b /= divisor;

            let color = RGB::new(r as u8, g as u8, b as u8);

            frame.put_pixel(x as i32, y as i32, &color);

            rendered[y * frame.width as usize + x] = color;
         }
      }
   }
}

impl Renderer for DevelRenderer {
   #[inline]
   fn init(&mut self, width: u32, height: u32) {
      self.resize(width, height);
   }

   fn render(&mut self, frame: &mut Frame) {
      self.clear();

      self.render_aliased(frame);

      self.downsample(frame);
   }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
struct Edge {
   p1: Point,
   p2: Point,
}

impl Edge {
   #[inline]
   fn new(p1: Point, p2: Point) -> Self {
      Edge {
         p1: p1,
         p2: p2,
      }
   }
}

struct YAxisAdvancer {
   delta: f64,
   f64x: f64,
}

impl YAxisAdvancer {
   fn new(edge: &Edge) -> Self {
      let dx = edge.p2.x - edge.p1.x;
      let dy = edge.p2.y - edge.p1.y;

      let delta = dx as f64 / dy as f64;
      let f64x = edge.p1.x as f64;

      YAxisAdvancer {
         delta: delta,
         f64x: f64x,
      }
   }

   fn advance(&mut self) -> i64 {
      self.f64x += self.delta;
      self.f64x.round() as i64
   }
}

fn get_left_right_edges(points: &Vec<Point>) -> (Vec<Edge>, Vec<Edge>){
   let (min_i, max_i) = find_min_max_y_index(points);

   let left = get_left_edges(points, min_i, max_i);
   let right = get_right_edges(points, min_i, max_i);

   (left, right)
}

fn get_left_edges(points: &Vec<Point>, min_i: usize, max_i: usize) -> Vec<Edge> {
   let mut edges = Vec::new();

   let mut curr_i = min_i;
   let mut prev_i = curr_i;

   loop {
      curr_i += 1;

      if curr_i == points.len() {
         curr_i = 0;
      }

      edges.push(Edge::new(points[prev_i], points[curr_i]));

      prev_i = curr_i;

      if curr_i == max_i {
         break;
      }
   }

   edges
}

fn get_right_edges(points: &Vec<Point>, min_i: usize, max_i: usize) -> Vec<Edge> {
   let mut edges = Vec::new();

   let mut curr_i = min_i;
   let mut prev_i = curr_i;

   loop {
      if curr_i == 0 {
         curr_i = points.len() - 1;
      } else {
         curr_i -= 1;
      }

      edges.push(Edge::new(points[prev_i], points[curr_i]));

      prev_i = curr_i;

      if curr_i == max_i {
         break;
      }
   }

   edges
}

fn find_min_max_y_index(points: &Vec<Point>) -> (usize, usize) {
   let (first, rest) = points.split_first().unwrap();

   let mut min_y = first.y;
   let mut max_y = min_y;
   let mut min_i = 0;
   let mut max_i = 0;

   for (i, point) in rest.iter().enumerate() {
      if point.y < min_y {
         min_i = i + 1;
         min_y = point.y;
      } else if point.y > max_y {
         max_i = i + 1;
         max_y = point.y;
      }
   }

   (min_i, max_i)
}

<|endoftext|>


<commit_before><commit_msg>Upping the escape magnitude from 2.0 to 3.0.<commit_after><|endoftext|>