8 个版本
0.3.1 | 2023年11月18日 |
---|---|
0.3.0 | 2020年6月11日 |
0.2.2 | 2020年5月24日 |
0.2.1 | 2020年4月14日 |
0.1.0 | 2020年3月29日 |
#318 在 WebAssembly
每月 52 次下载
用于 wain
150KB
3K SLoC
wain-exec
wain-exec
是一个用于执行 WebAssembly 抽象语法树的 crate。执行逻辑在 规范 中定义
此 crate 是更大 wain 项目的组成部分。
安装
[dependencies]
wain-exec = "0"
使用
此 crate 假设给定的 Wasm 语法树已被 验证。
它接受 wain_ast::Module
值并验证它。该树可以通过 wain-syntax-binary
和 wain-syntax-text
解析器进行解析,并通过 wain-validate
验证器进行验证
使用 wain_exec::execute()
是最简单的方法。如果存在,它会调用给定模块中的启动函数。否则,它将调用作为 _start
导出的函数。
extern crate wain_syntax_binary;
extern crate wain_validate;
extern crate wain_exec;
use std::fs;
use std::process::exit;
use wain_syntax_binary::parse;
use wain_validate::validate;
use wain_exec::execute;
// Read wasm binary
let source = fs::read("foo.wasm").unwrap();
// Parse binary into syntax tree
let tree = match parse(&source) {
Ok(tree) => tree,
Err(err) => {
eprintln!("Could not parse: {}", err);
exit(1);
}
};
// Validate module
if let Err(err) = validate(&tree) {
eprintln!("This .wasm file is invalid!: {}", err);
exit(1);
}
// Execute module
if let Err(trap) = execute(&tree.module) {
eprintln!("Execution was trapped: {}", trap);
exit(1);
}
或者调用具有参数的特定导出函数
// ...(snip)
use wain_exec::{Runtime, DefaultImporter, Value};
use std::io;
// Create default importer to call external function supported by default
let stdin = io::stdin();
let stdout = io::stdout();
let importer = DefaultImporter::with_stdio(stdin.lock(), stdout.lock());
// Make abstract machine runtime. It instantiates a module instance
let mut runtime = match Runtime::instantiate(&tree.module, importer) {
Ok(m) => m,
Err(err) => {
eprintln!("could not instantiate module: {}", err);
exit(1);
}
};
// Let's say `int add(int, int)` is exported
match runtime.invoke("add", &[Value::I32(10), Value::I32(32)]) {
Ok(ret) => {
// `ret` is type of `Option<Value>` where it contains `Some` value when the invoked
// function returned a value. Otherwise it's `None` value.
if let Some(Value::I32(i)) = ret {
println!("10 + 32 = {}", i);
} else {
unreachable!();
}
}
Err(trap) => eprintln!("Execution was trapped: {}", trap),
}
陷阱 作为 Err
部分返回。
wain_exec::execute()
默认情况下缓冲 stdin 和 stdout(此行为可能在未来发生变化)。如果不接受这种行为,请在 wain_exec::Runtime::new()
中指定您的 stdout/stdin 的 io::Write
/io::Read
值。然后通过 wain_exec::Runtime::invoke()
运行模块。
默认情况下,以下 C 函数在 env
模块中作为外部函数受支持
int putchar(int)
(在wasm中(func (param i32) (result i32))
)int getchar(void)
(在wasm中(func (param) (result i32))
)void *memcpy(void *, void *, size_t)
(在wasm中(func (param i32 i32 i32) (result i32))
)void abort(void)
(在wasm中(func (param) (result))
)
但您可以自己实现一个结构体,该结构体实现了从Rust侧定义外部函数的wain_exec::Importer
。
extern crate wain_exec;
extern crate wain_ast;
use wain_exec::{Runtime, Stack, Memory, Importer, ImportInvokeError, ImportInvalidError}
use wain_ast::ValType;
struct YourOwnImporter {
// ...
}
impl Importer for YourOwnImporter {
fn validate(&self, name: &str, params: &[ValType], ret: Option<ValType>) -> Option<ImportInvalidError> {
// `name` is a name of function to validate. `params` and `ret` are the function's signature.
// Return ImportInvalidError::NotFound when the name is unknown.
// Return ImportInvalidError::SignatureMismatch when signature does not match.
// wain_exec::check_func_signature() utility is would be useful for the check.
}
fn call(&mut self, name: &str, stack: &mut Stack, memory: &mut Memory) -> Result<(), ImportInvokeError> {
// Implement your own function call. `name` is a name of function and you have full access
// to stack and linear memory. Pop values from stack for getting arguments and push value to
// set return value.
// Note: Consistency between imported function signature and implementation of this method
// is your responsibility.
// On invocation failure, return ImportInvokeError::Fatal. It is trapped by interpreter and it
// stops execution immediately.
};
}
let ast = ...; // Parse abstract syntax tree and validate it
let mut runtime = Runtime::instantiate(&ast.module, YourOwnImporter{ /* ... */ }).unwrap();
let result = runtime.invoke("do_something", &[]);
工作示例可以在examples/api/目录中查看。
请阅读文档(尚未)以获取详细信息。
实现
由于验证,运行时检查是最小的(例如,间接调用上的函数签名)。
- 分配内存、表、全局变量。初始化栈
- 解释语法树节点,将值从栈中推入或弹出
目前wain直接解释Wasm语法树。我计划定义一个中间表示形式,它可以更快地解释。
入口点是“启动函数”,它可以是以下之一
start
部分中的函数集- 导出部分中名为
_start
的导出函数
第1项是标准入口点,但Clang不生成start
部分。相反,它将_start
函数作为入口点处理。wain实现了这两个入口点(1.优先)。