Make use of Lightbeam configurable.
This adds a `--always-lightbeam` option as well as an `--always-cranelift` option, to allow the compilation strategy to be selected via the command-line. This also enables regular testing for Lightbeam.
This commit is contained in:
101
build.rs
101
build.rs
@@ -14,12 +14,24 @@ fn main() {
|
|||||||
let mut out = File::create(out_dir.join("wast_testsuite_tests.rs"))
|
let mut out = File::create(out_dir.join("wast_testsuite_tests.rs"))
|
||||||
.expect("error generating test source file");
|
.expect("error generating test source file");
|
||||||
|
|
||||||
test_directory(&mut out, "misc_testsuite").expect("generating tests");
|
for strategy in &["AlwaysCranelift", "AlwaysLightbeam"] {
|
||||||
test_directory(&mut out, "spec_testsuite").expect("generating tests");
|
writeln!(out, "#[allow(non_snake_case)]").expect("generating tests");
|
||||||
test_file(&mut out, "spec_testsuite/proposals/simd/simd_const.wast").expect("generating tests");
|
writeln!(out, "mod {} {{", strategy).expect("generating tests");
|
||||||
|
|
||||||
|
test_directory(&mut out, "misc_testsuite", strategy).expect("generating tests");
|
||||||
|
test_directory(&mut out, "spec_testsuite", strategy).expect("generating tests");
|
||||||
|
test_file(
|
||||||
|
&mut out,
|
||||||
|
"spec_testsuite/proposals/simd/simd_const.wast",
|
||||||
|
strategy,
|
||||||
|
)
|
||||||
|
.expect("generating tests");
|
||||||
|
|
||||||
|
writeln!(out, "}}").expect("generating tests");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_directory(out: &mut File, testsuite: &str) -> io::Result<()> {
|
fn test_directory(out: &mut File, testsuite: &str, strategy: &str) -> io::Result<()> {
|
||||||
let mut dir_entries: Vec<_> = read_dir(testsuite)
|
let mut dir_entries: Vec<_> = read_dir(testsuite)
|
||||||
.expect("reading testsuite directory")
|
.expect("reading testsuite directory")
|
||||||
.map(|r| r.expect("reading testsuite directory entry"))
|
.map(|r| r.expect("reading testsuite directory entry"))
|
||||||
@@ -44,6 +56,22 @@ fn test_directory(out: &mut File, testsuite: &str) -> io::Result<()> {
|
|||||||
|
|
||||||
dir_entries.sort_by_key(|dir| dir.path());
|
dir_entries.sort_by_key(|dir| dir.path());
|
||||||
|
|
||||||
|
start_test_module(out, testsuite)?;
|
||||||
|
for dir_entry in dir_entries {
|
||||||
|
write_testsuite_tests(out, &dir_entry.path(), testsuite, strategy)?;
|
||||||
|
}
|
||||||
|
finish_test_module(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_file(out: &mut File, testfile: &str, strategy: &str) -> io::Result<()> {
|
||||||
|
let testsuite = "single_file_spec_test";
|
||||||
|
let path = Path::new(testfile);
|
||||||
|
start_test_module(out, testsuite)?;
|
||||||
|
write_testsuite_tests(out, path, testsuite, strategy)?;
|
||||||
|
finish_test_module(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_test_module(out: &mut File, testsuite: &str) -> io::Result<()> {
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
" mod {} {{",
|
" mod {} {{",
|
||||||
@@ -52,25 +80,24 @@ fn test_directory(out: &mut File, testsuite: &str) -> io::Result<()> {
|
|||||||
.expect("testsuite filename should have a stem")
|
.expect("testsuite filename should have a stem")
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("testsuite filename should be representable as a string")
|
.expect("testsuite filename should be representable as a string")
|
||||||
.replace("-", "_")
|
.replace("-", "_"),
|
||||||
)?;
|
)?;
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
" use super::{{native_isa, Path, WastContext, Compiler, Features}};"
|
" use super::super::{{native_isa, Path, WastContext, Compiler, Features, CompilationStrategy}};"
|
||||||
)?;
|
)
|
||||||
for dir_entry in dir_entries {
|
|
||||||
write_testsuite_tests(out, &dir_entry.path(), testsuite)?;
|
|
||||||
}
|
|
||||||
writeln!(out, "}}")?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_file(out: &mut File, testfile: &str) -> io::Result<()> {
|
fn finish_test_module(out: &mut File) -> io::Result<()> {
|
||||||
let path = Path::new(testfile);
|
writeln!(out, " }}")
|
||||||
write_testsuite_tests(out, path, "single_file_spec_test")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_testsuite_tests(out: &mut File, path: &Path, testsuite: &str) -> io::Result<()> {
|
fn write_testsuite_tests(
|
||||||
|
out: &mut File,
|
||||||
|
path: &Path,
|
||||||
|
testsuite: &str,
|
||||||
|
strategy: &str,
|
||||||
|
) -> io::Result<()> {
|
||||||
let stemstr = path
|
let stemstr = path
|
||||||
.file_stem()
|
.file_stem()
|
||||||
.expect("file_stem")
|
.expect("file_stem")
|
||||||
@@ -78,12 +105,16 @@ fn write_testsuite_tests(out: &mut File, path: &Path, testsuite: &str) -> io::Re
|
|||||||
.expect("to_str");
|
.expect("to_str");
|
||||||
|
|
||||||
writeln!(out, " #[test]")?;
|
writeln!(out, " #[test]")?;
|
||||||
if ignore(testsuite, stemstr) {
|
if ignore(testsuite, stemstr, strategy) {
|
||||||
writeln!(out, " #[ignore]")?;
|
writeln!(out, " #[ignore]")?;
|
||||||
}
|
}
|
||||||
writeln!(out, " fn r#{}() {{", &stemstr.replace("-", "_"))?;
|
writeln!(out, " fn r#{}() {{", &stemstr.replace("-", "_"))?;
|
||||||
writeln!(out, " let isa = native_isa();")?;
|
writeln!(out, " let isa = native_isa();")?;
|
||||||
writeln!(out, " let compiler = Compiler::new(isa);")?;
|
writeln!(
|
||||||
|
out,
|
||||||
|
" let compiler = Compiler::new(isa, CompilationStrategy::{});",
|
||||||
|
strategy
|
||||||
|
)?;
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
" let features = Features {{ simd: true, ..Default::default() }};"
|
" let features = Features {{ simd: true, ..Default::default() }};"
|
||||||
@@ -113,7 +144,39 @@ fn write_testsuite_tests(out: &mut File, path: &Path, testsuite: &str) -> io::Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Ignore tests that aren't supported yet.
|
/// Ignore tests that aren't supported yet.
|
||||||
fn ignore(testsuite: &str, name: &str) -> bool {
|
fn ignore(testsuite: &str, name: &str, strategy: &str) -> bool {
|
||||||
|
match strategy {
|
||||||
|
#[cfg(feature = "lightbeam")]
|
||||||
|
"AlwaysLightbeam" => match (testsuite, name) {
|
||||||
|
("misc_testsuite", "memory_grow")
|
||||||
|
| ("misc_testsuite", "misc_traps")
|
||||||
|
| ("single_file_spec_test", "simd_const")
|
||||||
|
| ("spec_testsuite", "address")
|
||||||
|
| ("spec_testsuite", "align")
|
||||||
|
| ("spec_testsuite", "call")
|
||||||
|
| ("spec_testsuite", "call_indirect")
|
||||||
|
| ("spec_testsuite", "conversions")
|
||||||
|
| ("spec_testsuite", "elem")
|
||||||
|
| ("spec_testsuite", "func_ptrs")
|
||||||
|
| ("spec_testsuite", "globals")
|
||||||
|
| ("spec_testsuite", "i32")
|
||||||
|
| ("spec_testsuite", "i64")
|
||||||
|
| ("spec_testsuite", "if")
|
||||||
|
| ("spec_testsuite", "imports")
|
||||||
|
| ("spec_testsuite", "int_exprs")
|
||||||
|
| ("spec_testsuite", "linking")
|
||||||
|
| ("spec_testsuite", "memory_grow")
|
||||||
|
| ("spec_testsuite", "memory_trap")
|
||||||
|
| ("spec_testsuite", "select")
|
||||||
|
| ("spec_testsuite", "traps")
|
||||||
|
| ("spec_testsuite", "unreachable")
|
||||||
|
| ("spec_testsuite", "unwind") => return true,
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
"AlwaysCranelift" => {}
|
||||||
|
_ => panic!("unrecognized strategy"),
|
||||||
|
}
|
||||||
|
|
||||||
if cfg!(windows) {
|
if cfg!(windows) {
|
||||||
return match (testsuite, name) {
|
return match (testsuite, name) {
|
||||||
("spec_testsuite", "address") => true,
|
("spec_testsuite", "address") => true,
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ pub fn instantiate(
|
|||||||
isa_builder.finish(cranelift_codegen::settings::Flags::new(flag_builder))
|
isa_builder.finish(cranelift_codegen::settings::Flags::new(flag_builder))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut context = wasmtime_jit::Context::with_isa(isa);
|
let mut context = wasmtime_jit::Context::with_isa(isa, wasmtime_jit::CompilationStrategy::Auto);
|
||||||
context.set_debug_info(generate_debug_info);
|
context.set_debug_info(generate_debug_info);
|
||||||
let global_exports = context.get_global_exports();
|
let global_exports = context.get_global_exports();
|
||||||
|
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ use serde::Deserialize;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process;
|
use std::process;
|
||||||
use wasmtime_environ::{cache_create_new_config, cache_init};
|
use wasmtime_environ::{cache_create_new_config, cache_init};
|
||||||
use wasmtime_jit::{Compiler, Features};
|
use wasmtime_jit::{CompilationStrategy, Compiler, Features};
|
||||||
use wasmtime_wast::WastContext;
|
use wasmtime_wast::WastContext;
|
||||||
|
|
||||||
const USAGE: &str = "
|
const USAGE: &str = "
|
||||||
Wast test runner.
|
Wast test runner.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
wast [-do] [--enable-simd] [--disable-cache | --cache-config=<cache_config_file>] <file>...
|
wast [-do] [--enable-simd] [--disable-cache | --cache-config=<cache_config_file>] [--always-lightmean | --always-cranelift] <file>...
|
||||||
wast --create-cache-config [--cache-config=<cache_config_file>]
|
wast --create-cache-config [--cache-config=<cache_config_file>]
|
||||||
wast --help | --version
|
wast --help | --version
|
||||||
|
|
||||||
@@ -57,6 +57,8 @@ Options:
|
|||||||
creates default configuration and writes it to the disk,
|
creates default configuration and writes it to the disk,
|
||||||
use with --cache-config to specify custom config file
|
use with --cache-config to specify custom config file
|
||||||
instead of default one
|
instead of default one
|
||||||
|
--always-lightbeam use Lightbeam for all compilation
|
||||||
|
--always-cranelift use Cranelift for all compilation
|
||||||
-d, --debug enable debug output on stderr/stdout
|
-d, --debug enable debug output on stderr/stdout
|
||||||
--enable-simd enable proposed SIMD instructions
|
--enable-simd enable proposed SIMD instructions
|
||||||
";
|
";
|
||||||
@@ -71,6 +73,8 @@ struct Args {
|
|||||||
flag_cache_config: Option<String>,
|
flag_cache_config: Option<String>,
|
||||||
flag_create_cache_config: bool,
|
flag_create_cache_config: bool,
|
||||||
flag_enable_simd: bool,
|
flag_enable_simd: bool,
|
||||||
|
flag_always_lightbeam: bool,
|
||||||
|
flag_always_cranelift: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -148,8 +152,18 @@ fn main() {
|
|||||||
features.simd = true;
|
features.simd = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decide how to compile.
|
||||||
|
let strategy = match (args.flag_always_lightbeam, args.flag_always_cranelift) {
|
||||||
|
(true, false) => CompilationStrategy::AlwaysLightbeam,
|
||||||
|
(false, true) => CompilationStrategy::AlwaysCranelift,
|
||||||
|
(false, false) => CompilationStrategy::Auto,
|
||||||
|
(true, true) => {
|
||||||
|
panic!("Can't enable --always-cranelift and --always-lightbeam at the same time")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
let engine = Compiler::new(isa);
|
let engine = Compiler::new(isa, strategy);
|
||||||
let mut wast_context = WastContext::new(Box::new(engine)).with_features(features);
|
let mut wast_context = WastContext::new(Box::new(engine)).with_features(features);
|
||||||
|
|
||||||
wast_context
|
wast_context
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::io::Read;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wabt;
|
use wabt;
|
||||||
use wasmtime_jit::{instantiate, Compiler, NullResolver};
|
use wasmtime_jit::{instantiate, CompilationStrategy, Compiler, NullResolver};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
const PATH_MODULE_RS2WASM_ADD_FUNC: &str = r"filetests/rs2wasm-add-func.wat";
|
const PATH_MODULE_RS2WASM_ADD_FUNC: &str = r"filetests/rs2wasm-add-func.wat";
|
||||||
@@ -40,7 +40,7 @@ fn test_environ_translate() {
|
|||||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
|
|
||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let mut compiler = Compiler::new(isa);
|
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
||||||
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
||||||
let instance = instantiate(&mut compiler, &data, &mut resolver, global_exports, false);
|
let instance = instantiate(&mut compiler, &data, &mut resolver, global_exports, false);
|
||||||
assert!(instance.is_ok());
|
assert!(instance.is_ok());
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use cranelift_codegen::isa;
|
|||||||
use cranelift_codegen::settings;
|
use cranelift_codegen::settings;
|
||||||
use cranelift_codegen::settings::Configurable;
|
use cranelift_codegen::settings::Configurable;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use wasmtime_jit::{Compiler, Features};
|
use wasmtime_jit::{CompilationStrategy, Compiler, Features};
|
||||||
use wasmtime_wast::WastContext;
|
use wasmtime_wast::WastContext;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/wast_testsuite_tests.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wast_testsuite_tests.rs"));
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::cell::{RefCell, RefMut};
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use wasmtime_jit::{Compiler, Features};
|
use wasmtime_jit::{CompilationStrategy, Compiler, Features};
|
||||||
|
|
||||||
use cranelift_codegen::settings;
|
use cranelift_codegen::settings;
|
||||||
|
|
||||||
@@ -59,5 +59,5 @@ pub(crate) fn create_compiler(flags: settings::Flags) -> Compiler {
|
|||||||
isa_builder.finish(flags)
|
isa_builder.finish(flags)
|
||||||
};
|
};
|
||||||
|
|
||||||
Compiler::new(isa)
|
Compiler::new(isa, CompilationStrategy::Auto)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,20 @@ use wasmtime_runtime::{
|
|||||||
VMFunctionBody,
|
VMFunctionBody,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Select which kind of compilation to use.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum CompilationStrategy {
|
||||||
|
/// Let Wasmtime pick the strategy.
|
||||||
|
Auto,
|
||||||
|
|
||||||
|
/// Compile all functions with Cranelift.
|
||||||
|
AlwaysCranelift,
|
||||||
|
|
||||||
|
/// Compile all functions with Lightbeam.
|
||||||
|
#[cfg(feature = "lightbeam")]
|
||||||
|
AlwaysLightbeam,
|
||||||
|
}
|
||||||
|
|
||||||
/// A WebAssembly code JIT compiler.
|
/// A WebAssembly code JIT compiler.
|
||||||
///
|
///
|
||||||
/// A `Compiler` instance owns the executable memory that it allocates.
|
/// A `Compiler` instance owns the executable memory that it allocates.
|
||||||
@@ -40,6 +54,7 @@ pub struct Compiler {
|
|||||||
trap_registration_guards: Vec<TrapRegistrationGuard>,
|
trap_registration_guards: Vec<TrapRegistrationGuard>,
|
||||||
trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>,
|
trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>,
|
||||||
signatures: SignatureRegistry,
|
signatures: SignatureRegistry,
|
||||||
|
strategy: CompilationStrategy,
|
||||||
|
|
||||||
/// The `FunctionBuilderContext`, shared between trampline function compilations.
|
/// The `FunctionBuilderContext`, shared between trampline function compilations.
|
||||||
fn_builder_ctx: FunctionBuilderContext,
|
fn_builder_ctx: FunctionBuilderContext,
|
||||||
@@ -47,7 +62,7 @@ pub struct Compiler {
|
|||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
/// Construct a new `Compiler`.
|
/// Construct a new `Compiler`.
|
||||||
pub fn new(isa: Box<dyn TargetIsa>) -> Self {
|
pub fn new(isa: Box<dyn TargetIsa>, strategy: CompilationStrategy) -> Self {
|
||||||
Self {
|
Self {
|
||||||
isa,
|
isa,
|
||||||
code_memory: CodeMemory::new(),
|
code_memory: CodeMemory::new(),
|
||||||
@@ -55,6 +70,7 @@ impl Compiler {
|
|||||||
trampoline_park: HashMap::new(),
|
trampoline_park: HashMap::new(),
|
||||||
signatures: SignatureRegistry::new(),
|
signatures: SignatureRegistry::new(),
|
||||||
fn_builder_ctx: FunctionBuilderContext::new(),
|
fn_builder_ctx: FunctionBuilderContext::new(),
|
||||||
|
strategy,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,11 +89,6 @@ impl Drop for Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lightbeam")]
|
|
||||||
type DefaultCompiler = wasmtime_environ::lightbeam::Lightbeam;
|
|
||||||
#[cfg(not(feature = "lightbeam"))]
|
|
||||||
type DefaultCompiler = wasmtime_environ::cranelift::Cranelift;
|
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
/// Return the target's frontend configuration settings.
|
/// Return the target's frontend configuration settings.
|
||||||
pub fn frontend_config(&self) -> TargetFrontendConfig {
|
pub fn frontend_config(&self) -> TargetFrontendConfig {
|
||||||
@@ -105,12 +116,27 @@ impl Compiler {
|
|||||||
SetupError,
|
SetupError,
|
||||||
> {
|
> {
|
||||||
let (compilation, relocations, address_transform, value_ranges, stack_slots, traps) =
|
let (compilation, relocations, address_transform, value_ranges, stack_slots, traps) =
|
||||||
DefaultCompiler::compile_module(
|
match self.strategy {
|
||||||
|
// For now, interpret `Auto` as `AlwaysCranelift` since that's the most stable
|
||||||
|
// implementation.
|
||||||
|
CompilationStrategy::Auto | CompilationStrategy::AlwaysCranelift => {
|
||||||
|
wasmtime_environ::cranelift::Cranelift::compile_module(
|
||||||
module,
|
module,
|
||||||
function_body_inputs,
|
function_body_inputs,
|
||||||
&*self.isa,
|
&*self.isa,
|
||||||
debug_data.is_some(),
|
debug_data.is_some(),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "lightbeam")]
|
||||||
|
CompilationStrategy::AlwaysLightbeam => {
|
||||||
|
wasmtime_environ::lightbeam::Lightbeam::compile_module(
|
||||||
|
module,
|
||||||
|
function_body_inputs,
|
||||||
|
&*self.isa,
|
||||||
|
debug_data.is_some(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
.map_err(SetupError::Compile)?;
|
.map_err(SetupError::Compile)?;
|
||||||
|
|
||||||
let allocated_functions =
|
let allocated_functions =
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::action::{get, inspect_memory, invoke};
|
use crate::action::{get, inspect_memory, invoke};
|
||||||
use crate::{
|
use crate::{
|
||||||
instantiate, ActionError, ActionOutcome, Compiler, InstanceHandle, Namespace, RuntimeValue,
|
instantiate, ActionError, ActionOutcome, CompilationStrategy, Compiler, InstanceHandle,
|
||||||
SetupError,
|
Namespace, RuntimeValue, SetupError,
|
||||||
};
|
};
|
||||||
use cranelift_codegen::isa::TargetIsa;
|
use cranelift_codegen::isa::TargetIsa;
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
@@ -103,8 +103,8 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a new instance of `Context` with the given target.
|
/// Construct a new instance of `Context` with the given target.
|
||||||
pub fn with_isa(isa: Box<dyn TargetIsa>) -> Self {
|
pub fn with_isa(isa: Box<dyn TargetIsa>, strategy: CompilationStrategy) -> Self {
|
||||||
Self::new(Box::new(Compiler::new(isa)))
|
Self::new(Box::new(Compiler::new(isa, strategy)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the context features
|
/// Retrieve the context features
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ mod resolver;
|
|||||||
mod target_tunables;
|
mod target_tunables;
|
||||||
|
|
||||||
pub use crate::action::{ActionError, ActionOutcome, RuntimeValue};
|
pub use crate::action::{ActionError, ActionOutcome, RuntimeValue};
|
||||||
pub use crate::compiler::Compiler;
|
pub use crate::compiler::{CompilationStrategy, Compiler};
|
||||||
pub use crate::context::{Context, ContextError, Features, UnknownInstance};
|
pub use crate::context::{Context, ContextError, Features, UnknownInstance};
|
||||||
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
|
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
|
||||||
pub use crate::link::link_module;
|
pub use crate::link::link_module;
|
||||||
|
|||||||
Reference in New Issue
Block a user