Commit 209130e6 authored by Guy Watson's avatar Guy Watson
Browse files

Compile example rust project for wasmer static lib bug

parent 623fddc8
......@@ -19,3 +19,5 @@ Cargo.lock
**/*.rs.bk
package-lock.json
*.zip
......@@ -48,10 +48,6 @@ fn get_crc() -> String {
#[derive(StructOpt)]
#[structopt(name = "load-wasmer", about = "Uses Wasmer to load and execute a WebAssembly program.")]
struct Cli {
/// The path to the wasm program (.wasm).
#[structopt(required(true))]
path: std::path::PathBuf,
/// Compiler. Options are "singlepass", "cranelift", or "llvm".
#[structopt(long, required(true))]
compiler: String,
......@@ -63,13 +59,17 @@ struct Cli {
/// Select if the compiler should apply optimizations.
#[structopt(long = "optimize")]
should_optimize: bool,
/// The path to the wasm program (.wasm).
#[structopt(required(true))]
program: std::path::PathBuf,
}
fn main() -> anyhow::Result<()> {
// Get command line arguments
let args = Cli::from_args();
if !(args.compiler == "singlepass"
if !(args.compiler == "singlepass"
|| args.compiler == "cranelift"
|| args.compiler == "llvm") {
panic!("Provided compiler option must be [\"singlepass\"|\"cranelift\"|\"llvm\"]");
......@@ -139,7 +139,7 @@ fn main() -> anyhow::Result<()> {
(_, _) => panic!("compiler did not match any known option"),
};
let wasm_bytes = fs::read(args.path)?;
let wasm_bytes = fs::read(args.program)?;
//println!("Compiling module...");
......
(module
(type (;0;) (func (param i32)))
(type (;1;) (func (result i32)))
(type (;2;) (func (param f64) (result f64)))
(type (;3;) (func))
(import "env" "addToCrc" (func (;0;) (type 0)))
(func (;1;) (type 1) (result i32)
(local i32 i64 f32 f64 i32 f64 i32)
i32.const 698
f32.load offset=87 align=1
f32.nearest
f32.const -0x1.d5859cp+9 (;=-939.044;)
i32.const 1455
f32.load offset=37 align=1
f32.mul
f32.ne
i32.const 691
i32.load offset=53 align=1
i32.ctz
i32.const 1847
i32.const 211
i32.load offset=32 align=1
i32.store offset=91 align=1
i32.const -34
i32.rotl
i32.or
local.get 6
f64.convert_i32_u
i32.const -82
if (result f64) ;; label = @1
local.get 5
else
f64.const 0x1.1cd643b75817p+7 (;=142.418;)
end
f64.min
i32.const 113
local.set 4
local.get 5
i32.const 1130
f64.load offset=78 align=1
f64.copysign
loop (param f64) (result f64) ;; label = @1
f64.const 0x1.c09d4be945cdbp+8 (;=448.614;)
f64.add
local.get 4
i32.const -1
i32.add
local.tee 4
br_if 0 (;@1;)
end
f64.ne
i32.shr_u)
(func (;2;) (type 3)
(local i64))
(memory (;0;) 1)
(export "_memory" (memory 0))
(export "_main" (func 1))
(export "_crc_globals" (func 2)))
[package]
name = "wasmer_bug"
version = "0.1.0"
authors = ["Guy Watson <guy.watson@utah.edu>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
wasmer = "1.0.2"
structopt = "0.3.21"
wasmer-compiler-cranelift = "1.0.2"
wasmer-compiler-llvm = "1.0.2"
wasmer-engine-native = "1.0.2"
anyhow = "1.0.38"
(module
(func $main (result i32)
i32.const 235
i32.const 0
i32.rotl
)
(export "_main" (func $main)))
(module
(func (;0;) (result i64)
i64.const 4
i64.const 0
i64.rotr)
(export "_main" (func 0)))
//!
//! This is a pared down version of the main load-wasmer program without
//! all of the bells and whistles. Good for tracking down bugs and minimizing examples.
use std::fs;
use structopt::StructOpt;
use wasmer::{imports, Instance, Module, NativeFunc, Store, Function};
use wasmer_compiler_cranelift::{Cranelift, CraneliftOptLevel};
use wasmer_compiler_llvm::{LLVM, LLVMOptLevel};
use wasmer_engine_native::Native;
/// Run a wasm program using Wasmer
#[derive(StructOpt)]
struct Cli {
/// The path to the wasm program (.wasm).
#[structopt(required(true))]
path: std::path::PathBuf,
}
fn print_val_i32(val: i32) -> i32 {
println!("[i32] {}", val);
return val;
}
fn print_val_i64(val: i64) -> i64 {
println!("[i64] {}", val);
return val;
}
fn main() -> anyhow::Result<()> {
let args = Cli::from_args();
// Insantiate the compiler and engine into a store
let mut cranelift_compiler = Cranelift::new();
cranelift_compiler.opt_level(CraneliftOptLevel::None);
let cranelift_store = Store::new(&Native::new(cranelift_compiler).engine());
//let mut llvm_compiler = LLVM::new();
//llvm_compiler.opt_level(LLVMOptLevel::None);
//let llvm_store = Store::new(&Native::new(llvm_compiler).engine());
let cranelift_wasm_bytes = fs::read(args.path.clone())?;
//let llvm_wasm_bytes = fs::read(args.path.clone())?;
let cranelift_module = Module::new(&cranelift_store, cranelift_wasm_bytes)?;
//let llvm_module = Module::new(&llvm_store, llvm_wasm_bytes)?;
let cranelift_print_val_i32_func = Function::new_native(&cranelift_store, print_val_i32);
let cranelift_print_val_i64_func = Function::new_native(&cranelift_store, print_val_i64);
//let llvm_print_val_i32_func = Function::new_native(&llvm_store, print_val_i32);
// Create an import object. Has no effect if wasm doesn't import it
let cranelift_import_object = imports! {
"env" => {
"print_i32" => cranelift_print_val_i32_func,
"print_i64" => cranelift_print_val_i64_func,
},
};
//let llvm_import_object = imports! {
//"env" => {
//"print_i32" => llvm_print_val_i32_func,
//},
//};
// Let's instantiate the Wasm module.
let cranelift_instance = Instance::new(&cranelift_module, &cranelift_import_object)?;
//let llvm_instance = Instance::new(&llvm_module, &llvm_import_object)?;
// Get handles for the exports
let cranelift_main_func: NativeFunc<(), i32> = cranelift_instance.exports.get_native_function("_main")?;
//let llvm_main_func: NativeFunc<(), i32> = llvm_instance.exports.get_native_function("_main")?;
// Call main and display the result
let cranelift_result = cranelift_main_func.call()?;
//let llvm_result = llvm_main_func.call()?;
println!("Result from cranelift: {}", cranelift_result);
//println!("Result from llvm: {}", llvm_result);
Ok(())
}
(module
(func $main (result i32)
i32.const 235
i32.const -123
f32.const -1
f32.const 0
f32.lt
i32.rem_u
i32.rotl)
(export "_main" (func $main)))
(module
(import "env" "print_i32" (func $print_i32 (param i32) (result i32)))
(func $main (result i32)
i32.const 235
i32.const -123
f32.const -1
f32.const 0
f32.lt
;; If either one of these next 2 calls to $print_i32 are uncommented, the
;; result from llvm will be -1 instead of 235.
;;call $print_i32
i32.rem_u
;;call $print_i32
i32.rotl)
(export "_main" (func $main)))
[package]
name = "load-wasmer"
version = "0.2.0"
authors = ["Guy Watson <guy.watson@utah.edu>"]
edition = "2018"
[dependencies]
# Uses the path to the repo when used locally, and uses
# version 1.0.2 from crates.io when published.
anyhow = "1.0.38"
crc = "1.8.1"
lazy_static = "1.4.0"
structopt = "0.3.21"
### Enable these for use on the testing machines (for fresh-built from source)
# wasmer = { path = "/local/work/wasmer/lib/api" }
# wasmer-compiler-singlepass = { path = "/local/work/wasmer/lib/compiler-singlepass" }
# wasmer-compiler-cranelift = { path = "/local/work/wasmer/lib/compiler-cranelift" }
# wasmer-compiler-llvm = { path = "/local/work/wasmer/lib/compiler-llvm" }
# wasmer-engine-universal = { path = "/local/work/wasmer/lib/engine-universal", features = ["compiler"] }
# wasmer-engine-dylib = { path = "/local/work/wasmer/lib/engine-dylib", features = ["compiler"] }
# wasmer-engine-staticlib = { path = "/local/work/wasmer/lib/engine-staticlib", features = ["compiler"] }
### Enable these for local development with an already set up rust environment
wasmer = { version = "2.0.0" }
wasmer-compiler-singlepass = { version = "2.0.0" }
wasmer-compiler-cranelift = { version = "2.0.0" }
wasmer-compiler-llvm = { version = "2.0.0" }
wasmer-engine-universal = { version = "2.0.0", features = ["compiler"] }
wasmer-engine-dylib = { version = "2.0.0", features = ["compiler"] }
wasmer-engine-staticlib = { version = "2.0.0", features = ["compiler"] }
//use std::env;
use std::fs;
use structopt::StructOpt;
use wasmer::{imports, Instance, Module, NativeFunc, Store, Function};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_universal::Universal;
use wasmer_engine_dylib::Dylib;
use wasmer_engine_staticlib::Staticlib;
use crc::{crc32, Hasher32};
use std::sync::Mutex;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref CRC_VAL: Mutex<crc32::Digest> = Mutex::new(crc32::Digest::new(crc32::IEEE));
}
// Add a value to the crc. This function is imported by the wasm code
fn add_to_crc(new_val : i32) {
CRC_VAL.lock().unwrap().write(&new_val.to_le_bytes());
}
fn get_crc() -> String {
format!("{:x}",CRC_VAL.lock().unwrap().sum32())
}
/// Run a wasm program using Wasmer
#[derive(StructOpt)]
#[structopt(name = "load-wasmer", about = "Uses Wasmer to load and execute a WebAssembly program.")]
struct Cli {
/// Engine. Options are "universal", "dylib" or "staticlib".
#[structopt(long, required(true))]
engine: String,
/// The path to the wasm program (.wasm).
#[structopt(required(true))]
program: std::path::PathBuf,
}
fn main() -> anyhow::Result<()> {
let args = Cli::from_args();
// Get command line arguments
if !(args.engine == "universal"
|| args.engine == "dylib"
|| args.engine == "staticlib") {
panic!("Provided engine option must be [\"universal\"|\"dylib\"|\"staticlib\"]");
}
// Insantiate the compiler and engine into a store
let engine = &args.engine[..];
let compiler = Cranelift::new();
let store = match engine {
"universal" => Store::new(&Universal::new(compiler).engine()),
"dylib" => Store::new(&Dylib::new(compiler).engine()),
"staticlib" => Store::new(&Staticlib::new(compiler).engine()),
_ => panic!("engine did not match any known option"),
};
let wasm_bytes = fs::read(args.program)?;
//println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create a function to pass to wasm
let add_to_crc_func = Function::new_native(
&store,
add_to_crc
);
// Create an import object with the crc function.
let import_object = imports! {
"env" => {
"addToCrc" => add_to_crc_func
},
};
//println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;
// Get handles for the exports
let main_func: NativeFunc<(), i32> = instance.exports.get_native_function("_main")?;
let crc_globals_func: NativeFunc<(), ()> = instance.exports.get_native_function("_crc_globals")?;
let memory = instance.exports.get_memory("_memory")?;
// Call main and add the result to the crc
add_to_crc(main_func.call()?);
// Call the crc globals function to have wasm add all of it's globals to the crc
crc_globals_func.call()?;
// Add the contents of memory to the crc
// Get the pointer and size in bytes
let mem_ptr: *mut i32 = memory.data_ptr() as *mut i32;
let mem_size = (memory.data_size() / 4) as isize; // bytes to i32s
for address in 0..mem_size {
let mem_value;
unsafe {
mem_value = *mem_ptr.offset(address);
}
add_to_crc(mem_value);
}
// Print the crc
println!("{}", get_crc());
Ok(())
}
(module
(type (;0;) (func (param i32)))
(type (;1;) (func (result i32)))
(type (;2;) (func (param f64) (result f64)))
(type (;3;) (func))
(import "env" "addToCrc" (func (;0;) (type 0)))
(func (;1;) (type 1) (result i32)
(local i32 i64 f32 f64 i32 f64 i32)
i32.const 698)
(func (;2;) (type 3)
(local i64))
(memory (;0;) 1)
(export "_memory" (memory 0))
(export "_main" (func 1))
(export "_crc_globals" (func 2)))
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment