Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve WasmerEnv, fix emscripten imports #2005

Merged
merged 5 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
## **[Unreleased]**

### Added
- [#2005](https://github.com/wasmerio/wasmer/pull/2005) Added the arguments `alias` and `optional` to `WasmerEnv` derive's `export` attribute.

### Changed
- [#1985](https://github.com/wasmerio/wasmer/pull/1985) Bump minimum supported Rust version to 1.48

### Fixed
- [#2005](https://github.com/wasmerio/wasmer/pull/2005) Emscripten is now working again.

## 1.0.0 - 2021-01-05

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ test-packages:
cargo test -p wasmer-cli --release
cargo test -p wasmer-cache --release
cargo test -p wasmer-engine --release
cargo test -p wasmer-derive --release


# The test-capi rules depend on the build-capi rules to build the .a files to
Expand Down
13 changes: 12 additions & 1 deletion lib/api/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ impl From<ExportError> for HostEnvInitError {
/// memory: LazyInit<Memory>,
/// #[wasmer(export(name = "real_name"))]
/// func: LazyInit<NativeFunc<(i32, i32), i32>>,
/// #[wasmer(export(optional = true, alias = "memory2", alias = "_memory2"))]
/// optional_memory: LazyInit<Memory>,
/// }
///
/// ```
Expand All @@ -51,7 +53,16 @@ impl From<ExportError> for HostEnvInitError {
/// `<field_name>_ref` and `<field_name>_ref_unchecked` for easy access to the
/// data.
///
/// This trait can also be implemented manually:
/// The valid arguments to `export` are:
/// - `name = "string"`: specify the name of this item in the Wasm module. If this is not specified, it will default to the name of the field.
/// - `optional = true`: specify whether this export is optional. Defaults to
/// `false`. Being optional means that if the export can't be found, the
/// [`LazyInit`] will be left uninitialized.
/// - `alias = "string"`: specify additional names to look for in the Wasm module.
/// `alias` may be specified multiple times to search for multiple aliases.
/// -------
///
/// This trait may also be implemented manually:
/// ```
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
/// #[derive(Clone)]
Expand Down
8 changes: 4 additions & 4 deletions lib/cli/src/commands/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ impl Compile {
pub(crate) fn get_recommend_extension(
engine_type: &EngineType,
target_triple: &Triple,
) -> &'static str {
match engine_type {
) -> Result<&'static str> {
Ok(match engine_type {
#[cfg(feature = "native")]
EngineType::Native => {
wasmer_engine_native::NativeArtifact::get_default_extension(target_triple)
Expand All @@ -55,7 +55,7 @@ impl Compile {
}
#[cfg(not(all(feature = "native", feature = "jit", feature = "object-file")))]
_ => bail!("selected engine type is not compiled in"),
}
})
}

fn inner_execute(&self) -> Result<()> {
Expand All @@ -81,7 +81,7 @@ impl Compile {
.file_stem()
.map(|osstr| osstr.to_string_lossy().to_string())
.unwrap_or_default();
let recommended_extension = Self::get_recommend_extension(&engine_type, target.triple());
let recommended_extension = Self::get_recommend_extension(&engine_type, target.triple())?;
match self.output.extension() {
Some(ext) => {
if ext != recommended_extension {
Expand Down
15 changes: 13 additions & 2 deletions lib/cli/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,19 @@ impl Run {
let mut em_env = EmEnv::new(&emscripten_globals.data, Default::default());
let import_object =
generate_emscripten_env(module.store(), &mut emscripten_globals, &mut em_env);
let mut instance = Instance::new(&module, &import_object)
.with_context(|| "Can't instantiate emscripten module")?;
let mut instance = match Instance::new(&module, &import_object) {
Ok(instance) => instance,
Err(e) => {
let err: Result<(), _> = Err(e);
#[cfg(feature = "wasi")]
{
if Wasi::has_wasi_imports(&module) {
return err.with_context(|| "This module has both Emscripten and WASI imports. Wasmer does not currently support Emscripten modules using WASI imports.");
}
}
return err.with_context(|| "Can't instantiate emscripten module");
}
};

run_emscripten_instance(
&mut instance,
Expand Down
10 changes: 9 additions & 1 deletion lib/cli/src/commands/run/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,22 @@ pub struct Wasi {
enable_experimental_io_devices: bool,
}

#[allow(dead_code)]
impl Wasi {
/// Gets the WASI version (if any) for the provided module
pub fn get_version(module: &Module) -> Option<WasiVersion> {
// Get the wasi version on strict mode, so no other imports are
// Get the wasi version in strict mode, so no other imports are
// allowed.
get_wasi_version(&module, true)
}

/// Checks if a given module has any WASI imports at all.
pub fn has_wasi_imports(module: &Module) -> bool {
// Get the wasi version in non-strict mode, so no other imports
// are allowed
get_wasi_version(&module, false).is_some()
}

/// Helper function for executing Wasi from the `Run` command.
pub fn execute(&self, module: Module, program_name: String, args: Vec<String>) -> Result<()> {
let args = args.iter().cloned().map(|arg| arg.into_bytes());
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-cranelift/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ rayon = "1.5"
serde = { version = "1.0", features = ["derive"] }
more-asserts = "0.2"
gimli = { version = "0.22", optional = true }
smallvec = "1.5"
smallvec = "1.6"

[dev-dependencies]
target-lexicon = { version = "0.11", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-llvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ wasmer-compiler = { path = "../compiler", version = "1.0.0", features = ["transl
wasmer-vm = { path = "../vm", version = "1.0.0" }
wasmer-types = { path = "../wasmer-types", version = "1.0.0" }
target-lexicon = { version = "0.11", default-features = false }
smallvec = "1.5"
smallvec = "1.6"
goblin = "0.2"
libc = { version = "^0.2", default-features = false }
byteorder = "1"
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler-singlepass/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dynasm = "1.0"
dynasmrt = "1.0"
lazy_static = "1.4"
byteorder = "1.3"
smallvec = "1.5"
smallvec = "1.6"

[dev-dependencies]
target-lexicon = { version = "0.11", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion lib/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ hashbrown = { version = "0.9", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "1.0"
serde_bytes = { version = "0.11", optional = true }
smallvec = "1.5"
smallvec = "1.6"

[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
raw-cpuid = "7.0"
Expand Down
61 changes: 55 additions & 6 deletions lib/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,71 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) {
helpers.push(helper_tokens);
}
match wasmer_attr {
WasmerAttr::Export { identifier, span } => {
WasmerAttr::Export {
identifier,
optional,
aliases,
span,
} => {
let finish_tokens = if let Some(name) = name {
let name_str = name.to_string();
let item_name =
identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span()));
quote_spanned! {f.span()=>
let #name: #inner_type = instance.exports.get_with_generics(#item_name)?;
self.#name.initialize(#name);
let mut access_expr = quote_spanned! {
f.span() =>
instance.exports.get_with_generics::<#inner_type, _, _>(#item_name)
};
for alias in aliases {
access_expr = quote_spanned! {
f.span()=>
#access_expr .or_else(|_| instance.exports.get_with_generics::<#inner_type, _, _>(#alias))
};
}
if optional {
quote_spanned! {
f.span()=>
match #access_expr {
Ok(#name) => { self.#name.initialize(#name); },
Err(_) => (),
};
}
} else {
quote_spanned! {
f.span()=>
let #name: #inner_type = #access_expr?;
self.#name.initialize(#name);
}
}
} else {
if let Some(identifier) = identifier {
let mut access_expr = quote_spanned! {
f.span() =>
instance.exports.get_with_generics::<#inner_type, _, _>(#identifier)
};
for alias in aliases {
access_expr = quote_spanned! {
f.span()=>
#access_expr .or_else(|_| instance.exports.get_with_generics::<#inner_type, _, _>(#alias))
};
}
let local_var =
Ident::new(&format!("field_{}", field_num), identifier.span());
quote_spanned! {f.span()=>
let #local_var: #inner_type = instance.exports.get_with_generics(#identifier)?;
if optional {
quote_spanned! {
f.span()=>
match #access_expr {
Ok(#local_var) => {
self.#field_num.initialize(#local_var);
},
Err(_) => (),
}
}
} else {
quote_spanned! {
f.span()=>
let #local_var: #inner_type = #access_expr?;
self.#field_num.initialize(#local_var);
}
}
} else {
abort!(
Expand Down
78 changes: 59 additions & 19 deletions lib/derive/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,97 @@ use proc_macro_error::abort;
use syn::{
parenthesized,
parse::{Parse, ParseStream},
token, Ident, LitStr, Token,
token, Ident, LitBool, LitStr, Token,
};

pub enum WasmerAttr {
Export {
/// The identifier is an override, otherwise we use the field name as the name
/// to lookup in `instance.exports`.
identifier: Option<LitStr>,
optional: bool,
aliases: Vec<LitStr>,
span: Span,
},
}

#[derive(Debug)]
struct ExportExpr {
name: Option<LitStr>,
optional: bool,
aliases: Vec<LitStr>,
}

#[derive(Debug)]
struct ExportOptions {
name: Option<LitStr>,
optional: bool,
aliases: Vec<LitStr>,
}
impl Parse for ExportOptions {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let ident = input.parse::<Ident>()?;
let _ = input.parse::<Token![=]>()?;
let ident_str = ident.to_string();
let name;
let mut name = None;
let mut optional: bool = false;
let mut aliases: Vec<LitStr> = vec![];
loop {
let ident = input.parse::<Ident>()?;
let _ = input.parse::<Token![=]>()?;
let ident_str = ident.to_string();

match ident_str.as_str() {
"name" => {
name = Some(input.parse::<LitStr>()?);
match ident_str.as_str() {
"name" => {
name = Some(input.parse::<LitStr>()?);
}
"optional" => {
optional = input.parse::<LitBool>()?.value;
}
"alias" => {
let alias = input.parse::<LitStr>()?;
aliases.push(alias);
}
otherwise => {
abort!(
ident,
"Unrecognized argument in export options: expected `name = \"string\"`, `optional = bool`, or `alias = \"string\"` found `{}`",
otherwise
);
}
}
otherwise => {
abort!(
ident,
"Unrecognized argument in export options: expected `name` found `{}`",
otherwise
);

match input.parse::<Token![,]>() {
Ok(_) => continue,
Err(_) => break,
}
}

Ok(ExportOptions { name })
Ok(ExportOptions {
name,
optional,
aliases,
})
}
}

impl Parse for ExportExpr {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let name;
let optional;
let aliases;
if input.peek(Ident) {
let options = input.parse::<ExportOptions>()?;
name = options.name;
optional = options.optional;
aliases = options.aliases;
} else {
name = None;
optional = false;
aliases = vec![];
}
Ok(Self { name })
Ok(Self {
name,
optional,
aliases,
})
}
}

Expand All @@ -70,17 +108,19 @@ impl Parse for WasmerAttrInner {
let out = match ident_str.as_str() {
"export" => {
let export_expr;
let name = if input.peek(token::Paren) {
let (name, optional, aliases) = if input.peek(token::Paren) {
let _: token::Paren = parenthesized!(export_expr in input);

let expr = export_expr.parse::<ExportExpr>()?;
expr.name
(expr.name, expr.optional, expr.aliases)
} else {
None
(None, false, vec![])
};

WasmerAttr::Export {
identifier: name,
optional,
aliases,
span,
}
}
Expand Down
Loading