Formatted files

This commit is contained in:
Syrus Akbary
2018-10-14 23:48:59 +02:00
parent 48fbc850ea
commit a9a580acee
8 changed files with 182 additions and 140 deletions

View File

@ -1,5 +1,5 @@
use core::ptr::NonNull;
use core::ops::{Index, IndexMut}; use core::ops::{Index, IndexMut};
use core::ptr::NonNull;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(transparent)] #[repr(transparent)]
@ -17,7 +17,7 @@ impl<T> UncheckedSlice<T> {
#[inline] #[inline]
unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T { unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
let ptr = self.ptr.as_ptr(); let ptr = self.ptr.as_ptr();
&mut*(ptr.add(index) as *mut _) &mut *(ptr.add(index) as *mut _)
} }
pub unsafe fn dangling() -> UncheckedSlice<T> { pub unsafe fn dangling() -> UncheckedSlice<T> {
@ -38,9 +38,7 @@ impl<T> UncheckedSlice<T> {
impl<'a, T> From<&'a [T]> for UncheckedSlice<T> { impl<'a, T> From<&'a [T]> for UncheckedSlice<T> {
fn from(slice: &[T]) -> UncheckedSlice<T> { fn from(slice: &[T]) -> UncheckedSlice<T> {
let ptr: NonNull<[T]> = slice.into(); let ptr: NonNull<[T]> = slice.into();
UncheckedSlice { UncheckedSlice { ptr: ptr.cast() }
ptr: ptr.cast(),
}
} }
} }
@ -52,9 +50,7 @@ pub struct BoundedSlice<T> {
impl<T> BoundedSlice<T> { impl<T> BoundedSlice<T> {
pub fn get(&self, index: usize) -> Option<&T> { pub fn get(&self, index: usize) -> Option<&T> {
if index < self.len { if index < self.len {
unsafe { unsafe { Some(self.data.get_unchecked(index)) }
Some(self.data.get_unchecked(index))
}
} else { } else {
None None
} }
@ -62,9 +58,7 @@ impl<T> BoundedSlice<T> {
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
if index < self.len { if index < self.len {
unsafe { unsafe { Some(self.data.get_unchecked_mut(index)) }
Some(self.data.get_unchecked_mut(index))
}
} else { } else {
None None
} }

View File

@ -2,29 +2,28 @@
extern crate error_chain; extern crate error_chain;
#[macro_use] #[macro_use]
extern crate structopt; extern crate structopt;
extern crate wabt;
extern crate cranelift_codegen; extern crate cranelift_codegen;
extern crate cranelift_entity;
extern crate cranelift_native; extern crate cranelift_native;
extern crate cranelift_wasm; extern crate cranelift_wasm;
extern crate cranelift_entity; extern crate wabt;
#[macro_use] #[macro_use]
extern crate target_lexicon; extern crate target_lexicon;
extern crate spin; extern crate spin;
use std::path::PathBuf; use std::error::Error;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::io::Read; use std::io::Read;
use std::path::PathBuf;
use std::process::exit; use std::process::exit;
use std::error::Error;
use structopt::StructOpt; use structopt::StructOpt;
use wabt::wat2wasm; use wabt::wat2wasm;
pub mod webassembly;
pub mod spec;
pub mod common; pub mod common;
pub mod spec;
pub mod webassembly;
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt(name = "wasmer", about = "WASM execution runtime.")] #[structopt(name = "wasmer", about = "WASM execution runtime.")]
@ -32,7 +31,7 @@ pub mod common;
enum CLIOptions { enum CLIOptions {
/// Run a WebAssembly file. Formats accepted: wasm, wast /// Run a WebAssembly file. Formats accepted: wasm, wast
#[structopt(name = "run")] #[structopt(name = "run")]
Run(Run) Run(Run),
} }
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
@ -44,7 +43,7 @@ struct Run {
path: PathBuf, path: PathBuf,
} }
/// Read the contents of a file /// Read the contents of a file
fn read_file_contents(path: PathBuf) -> Result<Vec<u8>, io::Error> { fn read_file_contents(path: PathBuf) -> Result<Vec<u8>, io::Error> {
let mut buffer: Vec<u8> = Vec::new(); let mut buffer: Vec<u8> = Vec::new();
let mut file = File::open(path)?; let mut file = File::open(path)?;
@ -53,12 +52,11 @@ fn read_file_contents(path: PathBuf) -> Result<Vec<u8>, io::Error> {
} }
/// Execute a WASM/WAT file /// Execute a WASM/WAT file
fn execute_wasm(wasm_path: PathBuf) -> Result<(), String>{ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String> {
let mut wasm_binary: Vec<u8> = read_file_contents(wasm_path).map_err(|err| String::from(err.description()))?; let mut wasm_binary: Vec<u8> =
read_file_contents(wasm_path).map_err(|err| String::from(err.description()))?;
if !webassembly::utils::is_wasm_binary(&wasm_binary) { if !webassembly::utils::is_wasm_binary(&wasm_binary) {
wasm_binary = wat2wasm( wasm_binary = wat2wasm(wasm_binary).map_err(|err| String::from(err.description()))?;
wasm_binary
).map_err(|err| String::from(err.description()))?;
} }
webassembly::instantiate(wasm_binary, None).map_err(|err| String::from(err.description()))?; webassembly::instantiate(wasm_binary, None).map_err(|err| String::from(err.description()))?;

View File

@ -70,9 +70,9 @@ wast total: 0 passed; 17955 failed
//! ``` //! ```
pub extern crate wabt; pub extern crate wabt;
pub use wabt::script::Value;
pub use wabt::script::Action; pub use wabt::script::Action;
pub use wabt::script::CommandKind; pub use wabt::script::CommandKind;
pub use wabt::script::Value;
use std::path::Path; use std::path::Path;
use wabt::script::*; use wabt::script::*;
@ -93,7 +93,12 @@ pub trait ScriptHandler {
/// ///
/// Targets either the last loaded module if `module` is None, or /// Targets either the last loaded module if `module` is None, or
/// the module registered with the given name otherwise. /// the module registered with the given name otherwise.
fn action_invoke(&mut self, module: Option<String>, field: String, args: Vec<Value>) -> InvokationResult; fn action_invoke(
&mut self,
module: Option<String>,
field: String,
args: Vec<Value>,
) -> InvokationResult;
/// Handles an `get` action. /// Handles an `get` action.
/// ///
@ -110,16 +115,18 @@ pub trait ScriptHandler {
/// if a function call trapped or exhausted the stack. /// if a function call trapped or exhausted the stack.
fn action(&mut self, action: Action) -> Vec<Value> { fn action(&mut self, action: Action) -> Vec<Value> {
match action { match action {
Action::Invoke { module, field, args } => { Action::Invoke {
module,
field,
args,
} => {
if let InvokationResult::Vals(v) = self.action_invoke(module, field, args) { if let InvokationResult::Vals(v) = self.action_invoke(module, field, args) {
v v
} else { } else {
panic!("invokation returned Trap or exhausted the stack"); panic!("invokation returned Trap or exhausted the stack");
} }
} }
Action::Get { module, field } => { Action::Get { module, field } => vec![self.action_get(module, field)],
vec![self.action_get(module, field)]
}
} }
} }
@ -151,14 +158,16 @@ pub trait ScriptHandler {
/// does not trap, or refers to an global. /// does not trap, or refers to an global.
fn assert_trap(&mut self, action: Action) { fn assert_trap(&mut self, action: Action) {
match action { match action {
Action::Invoke { module, field, args } => { Action::Invoke {
module,
field,
args,
} => {
if let InvokationResult::Vals(results) = self.action_invoke(module, field, args) { if let InvokationResult::Vals(results) = self.action_invoke(module, field, args) {
panic!("invokation did not trap, but returned {:?}", results); panic!("invokation did not trap, but returned {:?}", results);
} }
} }
Action::Get { .. } => { Action::Get { .. } => panic!("a global access can not trap!"),
panic!("a global access can not trap!")
}
} }
} }
@ -267,27 +276,26 @@ impl<'a> ::std::cmp::PartialEq for NanCompare<'a> {
if self.0.len() != other.0.len() { if self.0.len() != other.0.len() {
return false; return false;
} }
self.0.iter().zip(other.0.iter()).all(|pair| { self.0.iter().zip(other.0.iter()).all(|pair| match pair {
match pair { (Value::I32(l), Value::I32(r)) => l == r,
(Value::I32(l), Value::I32(r)) => l == r, (Value::I64(l), Value::I64(r)) => l == r,
(Value::I64(l), Value::I64(r)) => l == r, (Value::F32(l), Value::F32(r)) if l.is_nan() && r.is_nan() => {
(Value::F32(l), Value::F32(r)) if l.is_nan() && r.is_nan() => { l.payload() == r.payload()
l.payload() == r.payload()
},
(Value::F64(l), Value::F64(r)) if l.is_nan() && r.is_nan() => {
l.payload() == r.payload()
},
(Value::F32(l), Value::F32(r)) => l == r,
(Value::F64(l), Value::F64(r)) => l == r,
_ => false,
} }
(Value::F64(l), Value::F64(r)) if l.is_nan() && r.is_nan() => {
l.payload() == r.payload()
}
(Value::F32(l), Value::F32(r)) => l == r,
(Value::F64(l), Value::F64(r)) => l == r,
_ => false,
}) })
} }
} }
impl<'a> ::std::fmt::Debug for NanCompare<'a> { impl<'a> ::std::fmt::Debug for NanCompare<'a> {
fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
formatter.debug_list().entries(self.0.iter().map(|e| { formatter
match e { .debug_list()
.entries(self.0.iter().map(|e| match e {
Value::F32(v) if v.is_nan() => { Value::F32(v) if v.is_nan() => {
let p = v.payload(); let p = v.payload();
format!("F32(NaN:0x{:x})", p) format!("F32(NaN:0x{:x})", p)
@ -296,9 +304,9 @@ impl<'a> ::std::fmt::Debug for NanCompare<'a> {
let p = v.payload(); let p = v.payload();
format!("F64(NaN:0x{:x})", p) format!("F64(NaN:0x{:x})", p)
} }
_ => format!("{:?}", e) _ => format!("{:?}", e),
} }))
})).finish() .finish()
} }
} }
@ -344,8 +352,12 @@ impl NanPayload for f32 {
let p = bits & mask; let p = bits & mask;
p as u64 p as u64
} }
fn signif() -> u32 { 23 } fn signif() -> u32 {
fn infinite() -> Self { 1.0 / 0.0 } 23
}
fn infinite() -> Self {
1.0 / 0.0
}
fn canonical_payload() -> u64 { fn canonical_payload() -> u64 {
1u64 << (Self::signif() - 1) 1u64 << (Self::signif() - 1)
} }
@ -374,8 +386,12 @@ impl NanPayload for f64 {
let p = bits & mask; let p = bits & mask;
p p
} }
fn signif() -> u32 { 52 } fn signif() -> u32 {
fn infinite() -> Self { 1.0 / 0.0 } 52
}
fn infinite() -> Self {
1.0 / 0.0
}
fn canonical_payload() -> u64 { fn canonical_payload() -> u64 {
1u64 << (Self::signif() - 1) 1u64 << (Self::signif() - 1)
} }
@ -423,24 +439,38 @@ impl SpectestResult {
break; break;
} }
} }
println!("wast total: {} passed; {} failed", self.successes, self.failures.len()); println!(
"wast total: {} passed; {} failed",
self.successes,
self.failures.len()
);
panic!("some wast commands failed"); panic!("some wast commands failed");
} else { } else {
println!("wast total: {} passed; {} failed", self.successes, self.failures.len()); println!(
"wast total: {} passed; {} failed",
self.successes,
self.failures.len()
);
} }
} }
} }
/// Run all scripts of the bundled webassembly testsuite on `handler`. /// Run all scripts of the bundled webassembly testsuite on `handler`.
pub fn run_mvp_spectest<T: ScriptHandler>(handler: &mut T) -> SpectestResult { pub fn run_mvp_spectest<T: ScriptHandler>(handler: &mut T) -> SpectestResult {
run_all_in_directory(format!("{}/testsuite", env!("CARGO_MANIFEST_DIR")).as_ref(), handler) run_all_in_directory(
format!("{}/testsuite", env!("CARGO_MANIFEST_DIR")).as_ref(),
handler,
)
} }
/// Module that is expected under the name "spectest" by all spectest testcases. /// Module that is expected under the name "spectest" by all spectest testcases.
/// ///
/// This is automatically registered by all `run_` functions in this modules /// This is automatically registered by all `run_` functions in this modules
/// that work at file granularity or higher. /// that work at file granularity or higher.
pub const SPECTEST_MODULE: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/spec/spectest.wasm")); pub const SPECTEST_MODULE: &[u8] = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/spec/spectest.wasm"
));
/// Run all scripts in a given directory on `handler`. /// Run all scripts in a given directory on `handler`.
pub fn run_all_in_directory<T: ScriptHandler>(path: &Path, handler: &mut T) -> SpectestResult { pub fn run_all_in_directory<T: ScriptHandler>(path: &Path, handler: &mut T) -> SpectestResult {
@ -480,7 +510,7 @@ pub fn run_single_file<T: ScriptHandler>(path: &Path, handler: &mut T) -> Specte
let filename = path.file_name().unwrap().to_str().unwrap(); let filename = path.file_name().unwrap().to_str().unwrap();
let source = fs::read(&path).unwrap(); let source = fs::read(&path).unwrap();
let mut script = ScriptParser::<>::from_source_and_name(&source, filename).unwrap(); let mut script = ScriptParser::from_source_and_name(&source, filename).unwrap();
let mut fatal = false; let mut fatal = false;
handler.reset(); handler.reset();
@ -507,7 +537,8 @@ pub fn run_single_file<T: ScriptHandler>(path: &Path, handler: &mut T) -> Specte
match r { match r {
Err(msg) => { Err(msg) => {
res.failures.push(("<internal spectest module>".to_owned(), 0, msg)); res.failures
.push(("<internal spectest module>".to_owned(), 0, msg));
fatal = true; fatal = true;
} }
Ok(()) => { Ok(()) => {
@ -518,7 +549,8 @@ pub fn run_single_file<T: ScriptHandler>(path: &Path, handler: &mut T) -> Specte
while let Some(Command { line, kind }) = script.next().unwrap() { while let Some(Command { line, kind }) = script.next().unwrap() {
if fatal { if fatal {
res.failures.push((filename.to_owned(), line, "<not attempted>".to_string())); res.failures
.push((filename.to_owned(), line, "<not attempted>".to_string()));
continue; continue;
} }
match run_single_command(kind, handler) { match run_single_command(kind, handler) {
@ -541,7 +573,10 @@ pub fn run_single_file<T: ScriptHandler>(path: &Path, handler: &mut T) -> Specte
/// Note that `T` needs to be exception safe, in the sense that any /// Note that `T` needs to be exception safe, in the sense that any
/// panic that happened during a method call should not affect it beyond /// panic that happened during a method call should not affect it beyond
/// a subsequent `reset()` call. /// a subsequent `reset()` call.
pub fn run_single_command<T: ScriptHandler>(kind: CommandKind, handler: &mut T) -> Result<(), String> { pub fn run_single_command<T: ScriptHandler>(
kind: CommandKind,
handler: &mut T,
) -> Result<(), String> {
use std::panic::*; use std::panic::*;
if let Err(msg) = catch_unwind(AssertUnwindSafe(|| { if let Err(msg) = catch_unwind(AssertUnwindSafe(|| {

View File

@ -1,15 +1,15 @@
use std::path::Path;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use wabt::script::{Value, Action}; use super::{run_single_file, InvokationResult, ScriptHandler};
use super::{InvokationResult, ScriptHandler, run_single_file};
use crate::webassembly::{compile, instantiate, Error, ErrorKind, Module}; use crate::webassembly::{compile, instantiate, Error, ErrorKind, Module};
use wabt::script::{Action, Value};
// use crate::webassembly::instance::InvokeResult; // use crate::webassembly::instance::InvokeResult;
struct StoreCtrl<'module> { struct StoreCtrl<'module> {
last_module: Option<Module>, last_module: Option<Module>,
modules: HashMap<String, Rc<&'module Module>> modules: HashMap<String, Rc<&'module Module>>,
} }
impl<'module> StoreCtrl<'module> { impl<'module> StoreCtrl<'module> {
@ -112,8 +112,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
// println!("action invoke {}", module.unwrap_or("as".to_string())); // println!("action invoke {}", module.unwrap_or("as".to_string()));
// let modul = &self.last_module; // let modul = &self.last_module;
// modul.expect("a"); // modul.expect("a");
// //
} }
fn action_get(&mut self, module: Option<String>, field: String) -> Value { fn action_get(&mut self, module: Option<String>, field: String) -> Value {
// println!("action get"); // println!("action get");
@ -131,7 +130,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
let module_wrapped = instantiate(bytes, None); let module_wrapped = instantiate(bytes, None);
match module_wrapped { match module_wrapped {
Err(ErrorKind::CompileError(v)) => {} Err(ErrorKind::CompileError(v)) => {}
_ => panic!("Module compilation should have failed") _ => panic!("Module compilation should have failed"),
} }
} }
fn assert_invalid(&mut self, bytes: Vec<u8>) { fn assert_invalid(&mut self, bytes: Vec<u8>) {
@ -140,7 +139,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
// print!("IS INVALID?? {:?}", module_wrapped); // print!("IS INVALID?? {:?}", module_wrapped);
match module_wrapped { match module_wrapped {
Err(ErrorKind::CompileError(v)) => {} Err(ErrorKind::CompileError(v)) => {}
_ => assert!(false, "Module compilation should have failed") _ => assert!(false, "Module compilation should have failed"),
} }
} }
fn assert_uninstantiable(&mut self, bytes: Vec<u8>) { fn assert_uninstantiable(&mut self, bytes: Vec<u8>) {
@ -157,7 +156,11 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
fn do_test(test_name: String) { fn do_test(test_name: String) {
let mut handler = &mut StoreCtrl::new(); let mut handler = &mut StoreCtrl::new();
let test_path_str = format!("{}/src/spec/tests/{}.wast", env!("CARGO_MANIFEST_DIR"), test_name); let test_path_str = format!(
"{}/src/spec/tests/{}.wast",
env!("CARGO_MANIFEST_DIR"),
test_name
);
let test_path = Path::new(&test_path_str); let test_path = Path::new(&test_path_str);
let res = run_single_file(&test_path, handler); let res = run_single_file(&test_path, handler);
res.present() res.present()

View File

@ -6,20 +6,24 @@
//! synchronously instantiate a given webassembly::Module object. However, the //! synchronously instantiate a given webassembly::Module object. However, the
//! primary way to get an Instance is through the asynchronous //! primary way to get an Instance is through the asynchronous
//! webassembly::instantiateStreaming() function. //! webassembly::instantiateStreaming() function.
use cranelift_wasm::{GlobalInit, FuncIndex};
use super::module::Module; use super::module::Module;
use super::module::{DataInitializer, Exportable}; use super::module::{DataInitializer, Exportable};
use cranelift_entity::EntityRef; use cranelift_entity::EntityRef;
use cranelift_wasm::{FuncIndex, GlobalInit};
use super::memory::LinearMemory; use super::memory::LinearMemory;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::{slice, mem};
use std::sync::Arc; use std::sync::Arc;
use std::{mem, slice};
use spin::RwLock;
use super::super::common::slice::{BoundedSlice, UncheckedSlice}; use super::super::common::slice::{BoundedSlice, UncheckedSlice};
use spin::RwLock;
pub fn get_function_addr(base: *const (), functions: &[usize], func_index: &FuncIndex) -> *const () { pub fn get_function_addr(
base: *const (),
functions: &[usize],
func_index: &FuncIndex,
) -> *const () {
let offset = functions[func_index.index()]; let offset = functions[func_index.index()];
(base as usize + offset) as _ (base as usize + offset) as _
} }
@ -30,18 +34,14 @@ pub enum VmCtx {}
impl VmCtx { impl VmCtx {
pub fn data(&self) -> &VmCtxData { pub fn data(&self) -> &VmCtxData {
let heap_ptr = self as *const _ as *const VmCtxData; let heap_ptr = self as *const _ as *const VmCtxData;
unsafe { unsafe { &*heap_ptr.sub(1) }
&*heap_ptr.sub(1)
}
} }
/// This is safe because the offset is 32 bits and thus /// This is safe because the offset is 32 bits and thus
/// cannot extend out of the guarded wasm memory. /// cannot extend out of the guarded wasm memory.
pub fn fastpath_offset_ptr<T>(&self, offset: u32) -> *const T { pub fn fastpath_offset_ptr<T>(&self, offset: u32) -> *const T {
let heap_ptr = self as *const _ as *const u8; let heap_ptr = self as *const _ as *const u8;
unsafe { unsafe { heap_ptr.add(offset as usize) as *const T }
heap_ptr.add(offset as usize) as *const T
}
} }
} }
@ -60,7 +60,6 @@ pub struct UserData {
pub instance: Instance, pub instance: Instance,
} }
/// An Instance of a WebAssembly module /// An Instance of a WebAssembly module
#[derive(Debug)] #[derive(Debug)]
pub struct Instance { pub struct Instance {
@ -93,7 +92,10 @@ impl Instance {
} }
// instantiate tables // instantiate tables
for table_element in &module.info.table_elements { for table_element in &module.info.table_elements {
assert!(table_element.base.is_none(), "globalvalue base not supported yet."); assert!(
table_element.base.is_none(),
"globalvalue base not supported yet."
);
let base = 0; let base = 0;
let table = &mut tables[table_element.table_index]; let table = &mut tables[table_element.table_index];
@ -116,7 +118,8 @@ impl Instance {
memories.reserve_exact(module.info.memories.len()); memories.reserve_exact(module.info.memories.len());
for memory in &module.info.memories { for memory in &module.info.memories {
let memory = memory.entity; let memory = memory.entity;
let v = LinearMemory::new(memory.pages_count as u32, memory.maximum.map(|m| m as u32)); let v =
LinearMemory::new(memory.pages_count as u32, memory.maximum.map(|m| m as u32));
memories.push(v); memories.push(v);
} }
for init in &module.info.data_initializers { for init in &module.info.data_initializers {
@ -135,7 +138,9 @@ impl Instance {
globals.resize(globals_data_size, 0); globals.resize(globals_data_size, 0);
// cast the globals slice to a slice of i64. // cast the globals slice to a slice of i64.
let globals_data = unsafe { slice::from_raw_parts_mut(globals.as_mut_ptr() as *mut i64, globals_count) }; let globals_data = unsafe {
slice::from_raw_parts_mut(globals.as_mut_ptr() as *mut i64, globals_count)
};
for (i, global) in module.info.globals.iter().enumerate() { for (i, global) in module.info.globals.iter().enumerate() {
let value: i64 = match global.entity.initializer { let value: i64 = match global.entity.initializer {
GlobalInit::I32Const(n) => n as _, GlobalInit::I32Const(n) => n as _,
@ -144,7 +149,7 @@ impl Instance {
GlobalInit::F64Const(f) => unsafe { mem::transmute(f) }, GlobalInit::F64Const(f) => unsafe { mem::transmute(f) },
_ => unimplemented!(), _ => unimplemented!(),
}; };
globals_data[i] = value; globals_data[i] = value;
} }
}; };
@ -167,7 +172,6 @@ impl Instance {
// pub fn start_func(&self) -> extern fn(&VmCtx) { // pub fn start_func(&self) -> extern fn(&VmCtx) {
// self.start_func // self.start_func
// } // }
} }
impl Clone for Instance { impl Clone for Instance {

View File

@ -1,24 +1,24 @@
pub mod errors; pub mod errors;
pub mod utils;
pub mod module;
pub mod memory;
pub mod instance; pub mod instance;
pub mod memory;
pub mod module;
pub mod utils;
use std::str::FromStr; use cranelift_codegen::isa;
use std::time::{Duration, Instant}; use cranelift_native;
use std::panic; use std::panic;
use std::ptr; use std::ptr;
use cranelift_native; use std::str::FromStr;
use std::time::{Duration, Instant};
use target_lexicon::{self, Triple}; use target_lexicon::{self, Triple};
use wasmparser; use wasmparser;
use cranelift_codegen::isa;
// use cranelift_codegen::print_errors::pretty_verifier_error; // use cranelift_codegen::print_errors::pretty_verifier_error;
// use cranelift_codegen::verifier; // use cranelift_codegen::verifier;
pub use self::module::Module;
pub use self::instance::Instance;
pub use self::errors::{Error, ErrorKind}; pub use self::errors::{Error, ErrorKind};
pub use self::instance::Instance;
pub use self::memory::LinearMemory; pub use self::memory::LinearMemory;
pub use self::module::Module;
pub struct ResultObject { pub struct ResultObject {
/// A webassembly::Module object representing the compiled WebAssembly module. /// A webassembly::Module object representing the compiled WebAssembly module.
@ -29,13 +29,12 @@ pub struct ResultObject {
pub instance: Instance, pub instance: Instance,
} }
pub struct ImportObject { pub struct ImportObject {}
}
/// The webassembly::instantiate() function allows you to compile and /// The webassembly::instantiate() function allows you to compile and
/// instantiate WebAssembly code /// instantiate WebAssembly code
/// Params: /// Params:
/// * `buffer_source`: A `Vec<u8>` containing the /// * `buffer_source`: A `Vec<u8>` containing the
/// binary code of the .wasm module you want to compile. /// binary code of the .wasm module you want to compile.
@ -46,16 +45,16 @@ pub struct ImportObject {
/// webassembly::LinkError is thrown. /// webassembly::LinkError is thrown.
/// Errors: /// Errors:
/// If the operation fails, the Result rejects with a /// If the operation fails, the Result rejects with a
/// webassembly::CompileError, webassembly::LinkError, or /// webassembly::CompileError, webassembly::LinkError, or
/// webassembly::RuntimeError, depending on the cause of the failure. /// webassembly::RuntimeError, depending on the cause of the failure.
pub fn instantiate(buffer_source: Vec<u8>, import_object: Option<ImportObject>) -> Result<ResultObject, ErrorKind> { pub fn instantiate(
buffer_source: Vec<u8>,
import_object: Option<ImportObject>,
) -> Result<ResultObject, ErrorKind> {
let module = compile(buffer_source)?; let module = compile(buffer_source)?;
let instance = Instance::new(&module, ptr::null(), &vec![]); let instance = Instance::new(&module, ptr::null(), &vec![]);
Ok(ResultObject{ Ok(ResultObject { module, instance })
module,
instance
})
} }
/// The webassembly::compile() function compiles a webassembly::Module /// The webassembly::compile() function compiles a webassembly::Module
@ -63,19 +62,19 @@ pub fn instantiate(buffer_source: Vec<u8>, import_object: Option<ImportObject>)
/// is necessary to a compile a module before it can be instantiated /// is necessary to a compile a module before it can be instantiated
/// (otherwise, the webassembly::instantiate() function should be used). /// (otherwise, the webassembly::instantiate() function should be used).
/// Params: /// Params:
/// * `buffer_source`: A `Vec<u8>` containing the /// * `buffer_source`: A `Vec<u8>` containing the
/// binary code of the .wasm module you want to compile. /// binary code of the .wasm module you want to compile.
/// Errors: /// Errors:
/// If the operation fails, the Result rejects with a /// If the operation fails, the Result rejects with a
/// webassembly::CompileError. /// webassembly::CompileError.
pub fn compile(buffer_source: Vec<u8>) -> Result<Module, ErrorKind> { pub fn compile(buffer_source: Vec<u8>) -> Result<Module, ErrorKind> {
// TODO: This should be automatically validated when creating the Module // TODO: This should be automatically validated when creating the Module
if !validate(&buffer_source) { if !validate(&buffer_source) {
return Err(ErrorKind::CompileError("Module not valid".to_string())); return Err(ErrorKind::CompileError("Module not valid".to_string()));
} }
let module = Module::from_bytes(buffer_source, triple!("riscv64"), None)?; let module = Module::from_bytes(buffer_source, triple!("riscv64"), None)?;
// let isa = isa::lookup(module.info.triple) // let isa = isa::lookup(module.info.triple)
@ -87,7 +86,7 @@ pub fn compile(buffer_source: Vec<u8>) -> Result<Module, ErrorKind> {
// .map_err(|errors| panic!(pretty_verifier_error(func, Some(&*isa), None, errors))) // .map_err(|errors| panic!(pretty_verifier_error(func, Some(&*isa), None, errors)))
// .unwrap(); // .unwrap();
// }; // };
Ok(module) Ok(module)
} }
@ -95,7 +94,7 @@ pub fn compile(buffer_source: Vec<u8>) -> Result<Module, ErrorKind> {
/// array of WebAssembly binary code, returning whether the bytes /// array of WebAssembly binary code, returning whether the bytes
/// form a valid wasm module (true) or not (false). /// form a valid wasm module (true) or not (false).
/// Params: /// Params:
/// * `buffer_source`: A `Vec<u8>` containing the /// * `buffer_source`: A `Vec<u8>` containing the
/// binary code of the .wasm module you want to compile. /// binary code of the .wasm module you want to compile.
pub fn validate(buffer_source: &Vec<u8>) -> bool { pub fn validate(buffer_source: &Vec<u8>) -> bool {

View File

@ -4,27 +4,39 @@
use cranelift_codegen::cursor::FuncCursor; use cranelift_codegen::cursor::FuncCursor;
use cranelift_codegen::ir::immediates::{Imm64, Offset32}; use cranelift_codegen::ir::immediates::{Imm64, Offset32};
use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{self, InstBuilder, FuncRef, ExtFuncData, ExternalName, Signature, AbiParam, use cranelift_codegen::ir::{
ArgumentPurpose, ArgumentLoc, ArgumentExtension, Function}; self, AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, ExtFuncData, ExternalName,
FuncRef, Function, InstBuilder, Signature,
};
use cranelift_codegen::settings; use cranelift_codegen::settings;
use cranelift_entity::{EntityRef, PrimaryMap}; use cranelift_entity::{EntityRef, PrimaryMap};
use super::errors::ErrorKind; use super::errors::ErrorKind;
use super::memory::LinearMemory;
use cranelift_wasm::{
translate_module, // ReturnMode,
DefinedFuncIndex,
FuncEnvironment as FuncEnvironmentTrait,
FuncIndex,
FuncTranslator,
Global,
GlobalIndex,
GlobalVariable,
Memory,
MemoryIndex,
ModuleEnvironment,
SignatureIndex,
Table,
TableIndex,
WasmResult,
};
use std::string::String; use std::string::String;
use std::vec::Vec; use std::vec::Vec;
use target_lexicon::{Triple, PointerWidth}; use target_lexicon::{PointerWidth, Triple};
use cranelift_wasm::{
FuncTranslator,
FuncEnvironment as FuncEnvironmentTrait, GlobalVariable, ModuleEnvironment, WasmResult,
DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
TableIndex, translate_module, // ReturnMode,
};
use super::memory::LinearMemory;
// use alloc::vec::Vec; // use alloc::vec::Vec;
// use alloc::string::String; // use alloc::string::String;
/// Compute a `ir::ExternalName` for a given wasm function index. /// Compute a `ir::ExternalName` for a given wasm function index.
fn get_func_name(func_index: FuncIndex) -> ir::ExternalName { fn get_func_name(func_index: FuncIndex) -> ir::ExternalName {
ir::ExternalName::user(0, func_index.index() as u32) ir::ExternalName::user(0, func_index.index() as u32)
@ -124,7 +136,6 @@ impl ModuleInfo {
} }
} }
/// A data initializer for linear memory. /// A data initializer for linear memory.
#[derive(Debug)] #[derive(Debug)]
pub struct DataInitializer { pub struct DataInitializer {
@ -138,7 +149,6 @@ pub struct DataInitializer {
pub data: Vec<u8>, pub data: Vec<u8>,
} }
/// Possible values for a WebAssembly table element. /// Possible values for a WebAssembly table element.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum TableElement { pub enum TableElement {
@ -161,7 +171,6 @@ pub struct TableElements {
pub elements: Vec<FuncIndex>, pub elements: Vec<FuncIndex>,
} }
/// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and /// This `ModuleEnvironment` implementation is a "naïve" one, doing essentially nothing and
/// emitting placeholders when forced to. Don't try to execute code translated for this /// emitting placeholders when forced to. Don't try to execute code translated for this
/// environment, essentially here for translation debug purposes. /// environment, essentially here for translation debug purposes.
@ -174,7 +183,6 @@ pub struct Module {
/// Vector of wasm bytecode size for each function. /// Vector of wasm bytecode size for each function.
pub func_bytecode_sizes: Vec<usize>, pub func_bytecode_sizes: Vec<usize>,
// How to return from functions. // How to return from functions.
// return_mode: ReturnMode, // return_mode: ReturnMode,
} }
@ -204,11 +212,13 @@ impl Module {
// } // }
// } // }
pub fn from_bytes(buffer_source: Vec<u8>, triple: Triple, flags: Option<settings::Flags>) -> Result<Self, ErrorKind> { pub fn from_bytes(
buffer_source: Vec<u8>,
triple: Triple,
flags: Option<settings::Flags>,
) -> Result<Self, ErrorKind> {
// let return_mode = ReturnMode::NormalReturns; // let return_mode = ReturnMode::NormalReturns;
let flags = flags.unwrap_or_else(|| { let flags = flags.unwrap_or_else(|| settings::Flags::new(settings::builder()));
settings::Flags::new(settings::builder())
});
let mut module = Self { let mut module = Self {
info: ModuleInfo::with_triple_flags(triple, flags), info: ModuleInfo::with_triple_flags(triple, flags),
trans: FuncTranslator::new(), trans: FuncTranslator::new(),
@ -216,7 +226,8 @@ impl Module {
// return_mode, // return_mode,
}; };
// We iterate through the source bytes, generating the compiled module // We iterate through the source bytes, generating the compiled module
translate_module(&buffer_source, &mut module).map_err(|e| ErrorKind::CompileError(e.to_string()))?; translate_module(&buffer_source, &mut module)
.map_err(|e| ErrorKind::CompileError(e.to_string()))?;
Ok(module) Ok(module)
} }
@ -247,18 +258,17 @@ impl Module {
)) ))
} }
} }
} }
/// The `FuncEnvironment` implementation for use by the `Module`. /// The `FuncEnvironment` implementation for use by the `Module`.
pub struct FuncEnvironment<'environment> { pub struct FuncEnvironment<'environment> {
pub mod_info: &'environment ModuleInfo, pub mod_info: &'environment ModuleInfo,
// return_mode: ReturnMode, // return_mode: ReturnMode,
} }
impl<'environment> FuncEnvironment<'environment> { impl<'environment> FuncEnvironment<'environment> {
pub fn new(mod_info: &'environment ModuleInfo) -> Self { // , return_mode: ReturnMode pub fn new(mod_info: &'environment ModuleInfo) -> Self {
// , return_mode: ReturnMode
Self { Self {
mod_info, mod_info,
// return_mode, // return_mode,
@ -406,7 +416,7 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
let base = self.mod_info.tables_base.unwrap_or_else(|| { let base = self.mod_info.tables_base.unwrap_or_else(|| {
let tables_offset = self.ptr_size() as i32 * -1; let tables_offset = self.ptr_size() as i32 * -1;
let new_base = func.create_global_value(ir::GlobalValueData::VMContext { }); let new_base = func.create_global_value(ir::GlobalValueData::VMContext {});
// { // {
// offset: tables_offset.into(), // offset: tables_offset.into(),
// }); // });
@ -435,7 +445,7 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
let new_table_bounds = func.create_global_value(ir::GlobalValueData::Load { let new_table_bounds = func.create_global_value(ir::GlobalValueData::Load {
base: new_table_bounds_addr, base: new_table_bounds_addr,
offset: 0.into(), offset: 0.into(),
global_type: I32, // Might be self.pointer_type() global_type: I32, // Might be self.pointer_type()
}); });
let table = func.create_table(ir::TableData { let table = func.create_table(ir::TableData {
@ -444,7 +454,7 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
// min_size: (self.mod_info.tables[table_index].size as i64).into(), // min_size: (self.mod_info.tables[table_index].size as i64).into(),
bound_gv: new_table_bounds, bound_gv: new_table_bounds,
element_size: (ptr_size as i64).into(), element_size: (ptr_size as i64).into(),
index_type: I32 index_type: I32,
}); });
table table

View File

@ -1,4 +1,3 @@
/// Detect if a provided binary is a WASM file /// Detect if a provided binary is a WASM file
pub fn is_wasm_binary(binary: &Vec<u8>) -> bool { pub fn is_wasm_binary(binary: &Vec<u8>) -> bool {
binary.starts_with(&[b'\0', b'a', b's', b'm']) binary.starts_with(&[b'\0', b'a', b's', b'm'])