Add support for emitting code with a single return at the end. (#153)
This also enables testing of the wasmtests tests. This also updates for wabt updating to the official "wat" filename extension, as opposed to "wast".
This commit is contained in:
@@ -30,7 +30,7 @@ Usage:
|
|||||||
cton-util cat <file>...
|
cton-util cat <file>...
|
||||||
cton-util filecheck [-v] <file>
|
cton-util filecheck [-v] <file>
|
||||||
cton-util print-cfg <file>...
|
cton-util print-cfg <file>...
|
||||||
cton-util wasm [-cvo] <file>...
|
cton-util wasm [-cvo] [--enable=<flag>]... <file>...
|
||||||
cton-util --help | --version
|
cton-util --help | --version
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@@ -53,6 +53,7 @@ struct Args {
|
|||||||
flag_check: bool,
|
flag_check: bool,
|
||||||
flag_optimize: bool,
|
flag_optimize: bool,
|
||||||
flag_verbose: bool,
|
flag_verbose: bool,
|
||||||
|
flag_enable: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A command either succeeds or fails with an error message.
|
/// A command either succeeds or fails with an error message.
|
||||||
@@ -84,6 +85,7 @@ fn cton_util() -> CommandResult {
|
|||||||
args.flag_verbose,
|
args.flag_verbose,
|
||||||
args.flag_optimize,
|
args.flag_optimize,
|
||||||
args.flag_check,
|
args.flag_check,
|
||||||
|
args.flag_enable,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Debugging / shouldn't happen with proper command line handling above.
|
// Debugging / shouldn't happen with proper command line handling above.
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//! CLI tool to use the functions provided by crates [wasm2cretonne](../wasm2cretonne/index.html)
|
//! CLI tool to use the functions provided by the [cretonne-wasm](../cton_wasm/index.html) crate.
|
||||||
//! and [wasmstandalone](../wasmstandalone/index.html).
|
|
||||||
//!
|
//!
|
||||||
//! Reads Wasm binary files (one Wasm module per file), translates the functions' code to Cretonne
|
//! Reads Wasm binary files (one Wasm module per file), translates the functions' code to Cretonne
|
||||||
//! IL. Can also executes the `start` function of the module by laying out the memories, globals
|
//! IL. Can also executes the `start` function of the module by laying out the memories, globals
|
||||||
@@ -13,6 +12,7 @@ use cretonne::dominator_tree::DominatorTree;
|
|||||||
use cretonne::Context;
|
use cretonne::Context;
|
||||||
use cretonne::result::CtonError;
|
use cretonne::result::CtonError;
|
||||||
use cretonne::verifier;
|
use cretonne::verifier;
|
||||||
|
use cretonne::settings::{self, Configurable};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -54,7 +54,16 @@ pub fn run(
|
|||||||
flag_verbose: bool,
|
flag_verbose: bool,
|
||||||
flag_optimize: bool,
|
flag_optimize: bool,
|
||||||
flag_check: bool,
|
flag_check: bool,
|
||||||
|
flag_enable: Vec<String>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
let mut flag_builder = settings::builder();
|
||||||
|
for enable in flag_enable {
|
||||||
|
flag_builder.enable(&enable).map_err(|_| {
|
||||||
|
format!("unrecognized flag: {}", enable)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
let flags = settings::Flags::new(&flag_builder);
|
||||||
|
|
||||||
for filename in files {
|
for filename in files {
|
||||||
let path = Path::new(&filename);
|
let path = Path::new(&filename);
|
||||||
let name = String::from(path.as_os_str().to_string_lossy());
|
let name = String::from(path.as_os_str().to_string_lossy());
|
||||||
@@ -64,6 +73,7 @@ pub fn run(
|
|||||||
flag_check,
|
flag_check,
|
||||||
path.to_path_buf(),
|
path.to_path_buf(),
|
||||||
name,
|
name,
|
||||||
|
&flags,
|
||||||
) {
|
) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(message) => return Err(message),
|
Err(message) => return Err(message),
|
||||||
@@ -78,6 +88,7 @@ fn handle_module(
|
|||||||
flag_check: bool,
|
flag_check: bool,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
name: String,
|
name: String,
|
||||||
|
flags: &settings::Flags,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let mut terminal = term::stdout().unwrap();
|
let mut terminal = term::stdout().unwrap();
|
||||||
terminal.fg(term::color::YELLOW).unwrap();
|
terminal.fg(term::color::YELLOW).unwrap();
|
||||||
@@ -89,7 +100,7 @@ fn handle_module(
|
|||||||
terminal.reset().unwrap();
|
terminal.reset().unwrap();
|
||||||
let data = match path.extension() {
|
let data = match path.extension() {
|
||||||
None => {
|
None => {
|
||||||
return Err(String::from("the file extension is not wasm or wast"));
|
return Err(String::from("the file extension is not wasm or wat"));
|
||||||
}
|
}
|
||||||
Some(ext) => {
|
Some(ext) => {
|
||||||
match ext.to_str() {
|
match ext.to_str() {
|
||||||
@@ -101,17 +112,17 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some("wast") => {
|
Some("wat") => {
|
||||||
let tmp_dir = TempDir::new("wasm2cretonne").unwrap();
|
let tmp_dir = TempDir::new("cretonne-wasm").unwrap();
|
||||||
let file_path = tmp_dir.path().join("module.wasm");
|
let file_path = tmp_dir.path().join("module.wasm");
|
||||||
File::create(file_path.clone()).unwrap();
|
File::create(file_path.clone()).unwrap();
|
||||||
Command::new("wast2wasm")
|
Command::new("wat2wasm")
|
||||||
.arg(path.clone())
|
.arg(path.clone())
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(file_path.to_str().unwrap())
|
.arg(file_path.to_str().unwrap())
|
||||||
.output()
|
.output()
|
||||||
.or_else(|e| if let io::ErrorKind::NotFound = e.kind() {
|
.or_else(|e| if let io::ErrorKind::NotFound = e.kind() {
|
||||||
return Err(String::from("wast2wasm not found"));
|
return Err(String::from("wat2wasm not found"));
|
||||||
} else {
|
} else {
|
||||||
return Err(String::from(e.description()));
|
return Err(String::from(e.description()));
|
||||||
})
|
})
|
||||||
@@ -124,12 +135,12 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None | Some(&_) => {
|
None | Some(&_) => {
|
||||||
return Err(String::from("the file extension is not wasm or wast"));
|
return Err(String::from("the file extension is not wasm or wat"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut dummy_runtime = DummyRuntime::new();
|
let mut dummy_runtime = DummyRuntime::with_flags(flags.clone());
|
||||||
let translation = {
|
let translation = {
|
||||||
let runtime: &mut WasmRuntime = &mut dummy_runtime;
|
let runtime: &mut WasmRuntime = &mut dummy_runtime;
|
||||||
match translate_module(&data, runtime) {
|
match translate_module(&data, runtime) {
|
||||||
|
|||||||
10
cranelift/wasmtests/return_at_end.wat
Normal file
10
cranelift/wasmtests/return_at_end.wat
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
(module
|
||||||
|
(memory 1)
|
||||||
|
(func $main (param i32)
|
||||||
|
(if
|
||||||
|
(get_local 0)
|
||||||
|
(then (return))
|
||||||
|
(else (unreachable))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -14,3 +14,6 @@ name = "cton_wasm"
|
|||||||
wasmparser = "0.10.0"
|
wasmparser = "0.10.0"
|
||||||
cretonne = { path = "../cretonne" }
|
cretonne = { path = "../cretonne" }
|
||||||
cretonne-frontend = { path = "../frontend" }
|
cretonne-frontend = { path = "../frontend" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempdir = "0.3.5"
|
||||||
|
|||||||
@@ -329,8 +329,20 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operator::Return => {
|
Operator::Return => {
|
||||||
let return_count = state.control_stack[0].return_values().len();
|
let (return_count, br_destination) = {
|
||||||
builder.ins().return_(state.peekn(return_count));
|
let frame = &mut state.control_stack[0];
|
||||||
|
frame.set_reachable();
|
||||||
|
let return_count = frame.return_values().len();
|
||||||
|
(return_count, frame.br_destination())
|
||||||
|
};
|
||||||
|
{
|
||||||
|
let args = state.peekn(return_count);
|
||||||
|
if environ.flags().return_at_end() {
|
||||||
|
builder.ins().jump(br_destination, args);
|
||||||
|
} else {
|
||||||
|
builder.ins().return_(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
state.popn(return_count);
|
state.popn(return_count);
|
||||||
state.real_unreachable_stack_depth = 1;
|
state.real_unreachable_stack_depth = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let mut trans = FuncTranslator::new();
|
let mut trans = FuncTranslator::new();
|
||||||
let mut runtime = DummyRuntime::new();
|
let mut runtime = DummyRuntime::default();
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::FunctionName::new("small1");
|
ctx.func.name = ir::FunctionName::new("small1");
|
||||||
@@ -271,7 +271,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let mut trans = FuncTranslator::new();
|
let mut trans = FuncTranslator::new();
|
||||||
let mut runtime = DummyRuntime::new();
|
let mut runtime = DummyRuntime::default();
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::FunctionName::new("small2");
|
ctx.func.name = ir::FunctionName::new("small2");
|
||||||
@@ -314,7 +314,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let mut trans = FuncTranslator::new();
|
let mut trans = FuncTranslator::new();
|
||||||
let mut runtime = DummyRuntime::new();
|
let mut runtime = DummyRuntime::default();
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::FunctionName::new("infloop");
|
ctx.func.name = ir::FunctionName::new("infloop");
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use translation_utils::{Global, Memory, Table, GlobalIndex, TableIndex, Signatur
|
|||||||
use cretonne::ir::{self, InstBuilder};
|
use cretonne::ir::{self, InstBuilder};
|
||||||
use cretonne::ir::types::*;
|
use cretonne::ir::types::*;
|
||||||
use cretonne::cursor::FuncCursor;
|
use cretonne::cursor::FuncCursor;
|
||||||
|
use cretonne::settings;
|
||||||
|
|
||||||
/// This runtime implementation is a "naïve" one, doing essentially nothing and emitting
|
/// This runtime implementation is a "naïve" one, doing essentially nothing and emitting
|
||||||
/// placeholders when forced to. Don't try to execute code translated with this runtime, it is
|
/// placeholders when forced to. Don't try to execute code translated with this runtime, it is
|
||||||
@@ -18,23 +19,32 @@ pub struct DummyRuntime {
|
|||||||
|
|
||||||
// Names of imported functions.
|
// Names of imported functions.
|
||||||
imported_funcs: Vec<ir::FunctionName>,
|
imported_funcs: Vec<ir::FunctionName>,
|
||||||
|
|
||||||
|
// Compilation setting flags.
|
||||||
|
flags: settings::Flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DummyRuntime {
|
impl DummyRuntime {
|
||||||
/// Allocates the runtime data structures.
|
/// Allocates the runtime data structures with default flags.
|
||||||
pub fn new() -> Self {
|
pub fn default() -> Self {
|
||||||
|
Self::with_flags(settings::Flags::new(&settings::builder()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocates the runtime data structures with the given flags.
|
||||||
|
pub fn with_flags(flags: settings::Flags) -> Self {
|
||||||
Self {
|
Self {
|
||||||
signatures: Vec::new(),
|
signatures: Vec::new(),
|
||||||
globals: Vec::new(),
|
globals: Vec::new(),
|
||||||
func_types: Vec::new(),
|
func_types: Vec::new(),
|
||||||
imported_funcs: Vec::new(),
|
imported_funcs: Vec::new(),
|
||||||
|
flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncEnvironment for DummyRuntime {
|
impl FuncEnvironment for DummyRuntime {
|
||||||
fn native_pointer(&self) -> ir::Type {
|
fn flags(&self) -> &settings::Flags {
|
||||||
ir::types::I64
|
&self.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_global(&self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
|
fn make_global(&self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
//! trait `WasmRuntime`.
|
//! trait `WasmRuntime`.
|
||||||
use cretonne::ir::{self, InstBuilder};
|
use cretonne::ir::{self, InstBuilder};
|
||||||
use cretonne::cursor::FuncCursor;
|
use cretonne::cursor::FuncCursor;
|
||||||
|
use cretonne::settings::Flags;
|
||||||
use translation_utils::{SignatureIndex, FunctionIndex, TableIndex, GlobalIndex, MemoryIndex,
|
use translation_utils::{SignatureIndex, FunctionIndex, TableIndex, GlobalIndex, MemoryIndex,
|
||||||
Global, Table, Memory};
|
Global, Table, Memory};
|
||||||
|
|
||||||
@@ -26,10 +27,19 @@ pub enum GlobalValue {
|
|||||||
/// IL. The function environment provides information about the WebAssembly module as well as the
|
/// IL. The function environment provides information about the WebAssembly module as well as the
|
||||||
/// runtime environment.
|
/// runtime environment.
|
||||||
pub trait FuncEnvironment {
|
pub trait FuncEnvironment {
|
||||||
|
/// Get the flags for the current compilation.
|
||||||
|
fn flags(&self) -> &Flags;
|
||||||
|
|
||||||
/// Get the Cretonne integer type to use for native pointers.
|
/// Get the Cretonne integer type to use for native pointers.
|
||||||
///
|
///
|
||||||
/// This should be `I64` for 64-bit architectures and `I32` for 32-bit architectures.
|
/// This returns `I64` for 64-bit architectures and `I32` for 32-bit architectures.
|
||||||
fn native_pointer(&self) -> ir::Type;
|
fn native_pointer(&self) -> ir::Type {
|
||||||
|
if self.flags().is_64bit() {
|
||||||
|
ir::types::I64
|
||||||
|
} else {
|
||||||
|
ir::types::I32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Set up the necessary preamble definitions in `func` to access the global variable
|
/// Set up the necessary preamble definitions in `func` to access the global variable
|
||||||
/// identified by `index`.
|
/// identified by `index`.
|
||||||
@@ -138,7 +148,7 @@ pub trait FuncEnvironment {
|
|||||||
|
|
||||||
/// An object satisfyng the `WasmRuntime` trait can be passed as argument to the
|
/// An object satisfyng the `WasmRuntime` trait can be passed as argument to the
|
||||||
/// [`translate_module`](fn.translate_module.html) function. These methods should not be called
|
/// [`translate_module`](fn.translate_module.html) function. These methods should not be called
|
||||||
/// by the user, they are only for the `wasm2cretonne` internal use.
|
/// by the user, they are only for `cretonne-wasm` internal use.
|
||||||
pub trait WasmRuntime: FuncEnvironment {
|
pub trait WasmRuntime: FuncEnvironment {
|
||||||
/// Declares a function signature to the runtime.
|
/// Declares a function signature to the runtime.
|
||||||
fn declare_signature(&mut self, sig: &ir::Signature);
|
fn declare_signature(&mut self, sig: &ir::Signature);
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
extern crate cton_wasm;
|
extern crate cton_wasm;
|
||||||
extern crate cretonne;
|
extern crate cretonne;
|
||||||
|
extern crate tempdir;
|
||||||
|
|
||||||
use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
|
use cton_wasm::{translate_module, DummyRuntime, WasmRuntime};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::str;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
use std::process::Command;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use cretonne::ir;
|
use cretonne::ir;
|
||||||
use cretonne::ir::entities::AnyEntity;
|
use cretonne::ir::entities::AnyEntity;
|
||||||
use cretonne::isa::TargetIsa;
|
use cretonne::isa::{self, TargetIsa};
|
||||||
|
use cretonne::settings::{self, Configurable};
|
||||||
use cretonne::verifier;
|
use cretonne::verifier;
|
||||||
|
use tempdir::TempDir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn testsuite() {
|
fn testsuite() {
|
||||||
@@ -23,13 +29,29 @@ fn testsuite() {
|
|||||||
paths.sort_by_key(|dir| dir.path());
|
paths.sort_by_key(|dir| dir.path());
|
||||||
for path in paths {
|
for path in paths {
|
||||||
let path = path.path();
|
let path = path.path();
|
||||||
match handle_module(path) {
|
handle_module(path, None);
|
||||||
Ok(()) => (),
|
|
||||||
Err(message) => println!("{}", message),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_at_end() {
|
||||||
|
let mut flag_builder = settings::builder();
|
||||||
|
flag_builder.enable("return_at_end").unwrap();
|
||||||
|
let flags = settings::Flags::new(&flag_builder);
|
||||||
|
// We don't care about the target itself here, so just pick one arbitrarily.
|
||||||
|
let isa = match isa::lookup("riscv") {
|
||||||
|
Err(_) => {
|
||||||
|
println!("riscv target not found; disabled test return_at_end.wat");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ok(isa_builder) => isa_builder.finish(flags),
|
||||||
|
};
|
||||||
|
handle_module(
|
||||||
|
PathBuf::from("../../wasmtests/return_at_end.wat"),
|
||||||
|
Some(isa.borrow()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn read_wasm_file(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
fn read_wasm_file(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
@@ -38,44 +60,80 @@ fn read_wasm_file(path: PathBuf) -> Result<Vec<u8>, io::Error> {
|
|||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(path: PathBuf) -> Result<(), String> {
|
fn handle_module(path: PathBuf, isa: Option<&TargetIsa>) {
|
||||||
let data = match path.extension() {
|
let data = match path.extension() {
|
||||||
None => {
|
None => {
|
||||||
return Err(String::from("the file extension is not wasm or wast"));
|
panic!("the file extension is not wasm or wat");
|
||||||
}
|
}
|
||||||
Some(ext) => {
|
Some(ext) => {
|
||||||
match ext.to_str() {
|
match ext.to_str() {
|
||||||
Some("wasm") => {
|
Some("wasm") => {
|
||||||
match read_wasm_file(path.clone()) {
|
match read_wasm_file(path.clone()) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => panic!("error reading wasm file: {}", err.description()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some("wat") => {
|
||||||
|
let tmp_dir = TempDir::new("cretonne-wasm").unwrap();
|
||||||
|
let file_path = tmp_dir.path().join("module.wasm");
|
||||||
|
File::create(file_path.clone()).unwrap();
|
||||||
|
let result_output = Command::new("wat2wasm")
|
||||||
|
.arg(path.clone())
|
||||||
|
.arg("-o")
|
||||||
|
.arg(file_path.to_str().unwrap())
|
||||||
|
.output();
|
||||||
|
match result_output {
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() == io::ErrorKind::NotFound {
|
||||||
|
println!(
|
||||||
|
"wat2wasm not found; disabled test {}",
|
||||||
|
path.to_str().unwrap()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
panic!("error convering wat file: {}", e.description());
|
||||||
|
}
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
panic!(
|
||||||
|
"error running wat2wasm: {}",
|
||||||
|
str::from_utf8(&output.stderr).expect(
|
||||||
|
"wat2wasm's error message should be valid UTF-8",
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match read_wasm_file(file_path) {
|
||||||
Ok(data) => data,
|
Ok(data) => data,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(String::from(err.description()));
|
panic!("error reading converted wasm file: {}", err.description());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None | Some(&_) => {
|
None | Some(&_) => panic!("the file extension is not wasm or wat"),
|
||||||
return Err(String::from("the file extension is not wasm or wast"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut dummy_runtime = DummyRuntime::new();
|
let mut dummy_runtime = match isa {
|
||||||
|
Some(isa) => DummyRuntime::with_flags(isa.flags().clone()),
|
||||||
|
None => DummyRuntime::default(),
|
||||||
|
};
|
||||||
let translation = {
|
let translation = {
|
||||||
let runtime: &mut WasmRuntime = &mut dummy_runtime;
|
let runtime: &mut WasmRuntime = &mut dummy_runtime;
|
||||||
match translate_module(&data, runtime) {
|
match translate_module(&data, runtime) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(string) => {
|
Err(string) => {
|
||||||
return Err(string);
|
panic!(string);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for func in &translation.functions {
|
for func in &translation.functions {
|
||||||
match verifier::verify_function(func, None) {
|
match verifier::verify_function(func, isa) {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
Err(err) => return Err(pretty_verifier_error(func, None, err)),
|
Err(err) => panic!(pretty_verifier_error(func, isa, err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user