Skip to content

Commit cded1ac

Browse files
bors[bot]Mark McCaskey
and
Mark McCaskey
authored
Merge #2005
2005: Improve WasmerEnv, fix emscripten imports r=MarkMcCaskey a=MarkMcCaskey This PR adds two new features to `WasmerEnv`: - `alias = "alias_name"` for specifying additional names to try to find the export by - `optional = true` for specifying that failure to find this export is okay In addition, it fixes some breakages on emscripten introduced by migrating emscripten to `WasmerEnv` naively. I've tested this in `examples/nginx` on the `0.x` branch and Wasmer is able to run nginx again, so this resolves #1997 # Review - [x] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Mark McCaskey <mark@wasmer.io>
2 parents 7a3d482 + 3654cb1 commit cded1ac

File tree

15 files changed

+262
-108
lines changed

15 files changed

+262
-108
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
## **[Unreleased]**
99

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

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

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

1719
## 1.0.0 - 2021-01-05
1820

Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ test-packages:
234234
cargo test -p wasmer-cli --release
235235
cargo test -p wasmer-cache --release
236236
cargo test -p wasmer-engine --release
237+
cargo test -p wasmer-derive --release
237238

238239

239240
# The test-capi rules depend on the build-capi rules to build the .a files to

lib/api/src/env.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ impl From<ExportError> for HostEnvInitError {
4242
/// memory: LazyInit<Memory>,
4343
/// #[wasmer(export(name = "real_name"))]
4444
/// func: LazyInit<NativeFunc<(i32, i32), i32>>,
45+
/// #[wasmer(export(optional = true, alias = "memory2", alias = "_memory2"))]
46+
/// optional_memory: LazyInit<Memory>,
4547
/// }
4648
///
4749
/// ```
@@ -51,7 +53,16 @@ impl From<ExportError> for HostEnvInitError {
5153
/// `<field_name>_ref` and `<field_name>_ref_unchecked` for easy access to the
5254
/// data.
5355
///
54-
/// This trait can also be implemented manually:
56+
/// The valid arguments to `export` are:
57+
/// - `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.
58+
/// - `optional = true`: specify whether this export is optional. Defaults to
59+
/// `false`. Being optional means that if the export can't be found, the
60+
/// [`LazyInit`] will be left uninitialized.
61+
/// - `alias = "string"`: specify additional names to look for in the Wasm module.
62+
/// `alias` may be specified multiple times to search for multiple aliases.
63+
/// -------
64+
///
65+
/// This trait may also be implemented manually:
5566
/// ```
5667
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
5768
/// #[derive(Clone)]

lib/cli/src/commands/compile.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ impl Compile {
4141
pub(crate) fn get_recommend_extension(
4242
engine_type: &EngineType,
4343
target_triple: &Triple,
44-
) -> &'static str {
45-
match engine_type {
44+
) -> Result<&'static str> {
45+
Ok(match engine_type {
4646
#[cfg(feature = "native")]
4747
EngineType::Native => {
4848
wasmer_engine_native::NativeArtifact::get_default_extension(target_triple)
@@ -55,7 +55,7 @@ impl Compile {
5555
}
5656
#[cfg(not(all(feature = "native", feature = "jit", feature = "object-file")))]
5757
_ => bail!("selected engine type is not compiled in"),
58-
}
58+
})
5959
}
6060

6161
fn inner_execute(&self) -> Result<()> {
@@ -81,7 +81,7 @@ impl Compile {
8181
.file_stem()
8282
.map(|osstr| osstr.to_string_lossy().to_string())
8383
.unwrap_or_default();
84-
let recommended_extension = Self::get_recommend_extension(&engine_type, target.triple());
84+
let recommended_extension = Self::get_recommend_extension(&engine_type, target.triple())?;
8585
match self.output.extension() {
8686
Some(ext) => {
8787
if ext != recommended_extension {

lib/cli/src/commands/run.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,19 @@ impl Run {
119119
let mut em_env = EmEnv::new(&emscripten_globals.data, Default::default());
120120
let import_object =
121121
generate_emscripten_env(module.store(), &mut emscripten_globals, &mut em_env);
122-
let mut instance = Instance::new(&module, &import_object)
123-
.with_context(|| "Can't instantiate emscripten module")?;
122+
let mut instance = match Instance::new(&module, &import_object) {
123+
Ok(instance) => instance,
124+
Err(e) => {
125+
let err: Result<(), _> = Err(e);
126+
#[cfg(feature = "wasi")]
127+
{
128+
if Wasi::has_wasi_imports(&module) {
129+
return err.with_context(|| "This module has both Emscripten and WASI imports. Wasmer does not currently support Emscripten modules using WASI imports.");
130+
}
131+
}
132+
return err.with_context(|| "Can't instantiate emscripten module");
133+
}
134+
};
124135

125136
run_emscripten_instance(
126137
&mut instance,

lib/cli/src/commands/run/wasi.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,22 @@ pub struct Wasi {
2727
enable_experimental_io_devices: bool,
2828
}
2929

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

39+
/// Checks if a given module has any WASI imports at all.
40+
pub fn has_wasi_imports(module: &Module) -> bool {
41+
// Get the wasi version in non-strict mode, so no other imports
42+
// are allowed
43+
get_wasi_version(&module, false).is_some()
44+
}
45+
3846
/// Helper function for executing Wasi from the `Run` command.
3947
pub fn execute(&self, module: Module, program_name: String, args: Vec<String>) -> Result<()> {
4048
let args = args.iter().cloned().map(|arg| arg.into_bytes());

lib/compiler-cranelift/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ rayon = "1.5"
2323
serde = { version = "1.0", features = ["derive"] }
2424
more-asserts = "0.2"
2525
gimli = { version = "0.22", optional = true }
26-
smallvec = "1.5"
26+
smallvec = "1.6"
2727

2828
[dev-dependencies]
2929
target-lexicon = { version = "0.11", default-features = false }

lib/compiler-llvm/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ wasmer-compiler = { path = "../compiler", version = "1.0.0", features = ["transl
1616
wasmer-vm = { path = "../vm", version = "1.0.0" }
1717
wasmer-types = { path = "../wasmer-types", version = "1.0.0" }
1818
target-lexicon = { version = "0.11", default-features = false }
19-
smallvec = "1.5"
19+
smallvec = "1.6"
2020
goblin = "0.2"
2121
libc = { version = "^0.2", default-features = false }
2222
byteorder = "1"

lib/compiler-singlepass/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ dynasm = "1.0"
2323
dynasmrt = "1.0"
2424
lazy_static = "1.4"
2525
byteorder = "1.3"
26-
smallvec = "1.5"
26+
smallvec = "1.6"
2727

2828
[dev-dependencies]
2929
target-lexicon = { version = "0.11", default-features = false }

lib/compiler/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ hashbrown = { version = "0.9", optional = true }
2020
serde = { version = "1.0", features = ["derive"], optional = true }
2121
thiserror = "1.0"
2222
serde_bytes = { version = "0.11", optional = true }
23-
smallvec = "1.5"
23+
smallvec = "1.6"
2424

2525
[target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies]
2626
raw-cpuid = "7.0"

lib/derive/src/lib.rs

+55-6
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,71 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) {
123123
helpers.push(helper_tokens);
124124
}
125125
match wasmer_attr {
126-
WasmerAttr::Export { identifier, span } => {
126+
WasmerAttr::Export {
127+
identifier,
128+
optional,
129+
aliases,
130+
span,
131+
} => {
127132
let finish_tokens = if let Some(name) = name {
128133
let name_str = name.to_string();
129134
let item_name =
130135
identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span()));
131-
quote_spanned! {f.span()=>
132-
let #name: #inner_type = instance.exports.get_with_generics(#item_name)?;
133-
self.#name.initialize(#name);
136+
let mut access_expr = quote_spanned! {
137+
f.span() =>
138+
instance.exports.get_with_generics::<#inner_type, _, _>(#item_name)
139+
};
140+
for alias in aliases {
141+
access_expr = quote_spanned! {
142+
f.span()=>
143+
#access_expr .or_else(|_| instance.exports.get_with_generics::<#inner_type, _, _>(#alias))
144+
};
145+
}
146+
if optional {
147+
quote_spanned! {
148+
f.span()=>
149+
match #access_expr {
150+
Ok(#name) => { self.#name.initialize(#name); },
151+
Err(_) => (),
152+
};
153+
}
154+
} else {
155+
quote_spanned! {
156+
f.span()=>
157+
let #name: #inner_type = #access_expr?;
158+
self.#name.initialize(#name);
159+
}
134160
}
135161
} else {
136162
if let Some(identifier) = identifier {
163+
let mut access_expr = quote_spanned! {
164+
f.span() =>
165+
instance.exports.get_with_generics::<#inner_type, _, _>(#identifier)
166+
};
167+
for alias in aliases {
168+
access_expr = quote_spanned! {
169+
f.span()=>
170+
#access_expr .or_else(|_| instance.exports.get_with_generics::<#inner_type, _, _>(#alias))
171+
};
172+
}
137173
let local_var =
138174
Ident::new(&format!("field_{}", field_num), identifier.span());
139-
quote_spanned! {f.span()=>
140-
let #local_var: #inner_type = instance.exports.get_with_generics(#identifier)?;
175+
if optional {
176+
quote_spanned! {
177+
f.span()=>
178+
match #access_expr {
179+
Ok(#local_var) => {
180+
self.#field_num.initialize(#local_var);
181+
},
182+
Err(_) => (),
183+
}
184+
}
185+
} else {
186+
quote_spanned! {
187+
f.span()=>
188+
let #local_var: #inner_type = #access_expr?;
141189
self.#field_num.initialize(#local_var);
190+
}
142191
}
143192
} else {
144193
abort!(

lib/derive/src/parse.rs

+59-19
Original file line numberDiff line numberDiff line change
@@ -3,59 +3,97 @@ use proc_macro_error::abort;
33
use syn::{
44
parenthesized,
55
parse::{Parse, ParseStream},
6-
token, Ident, LitStr, Token,
6+
token, Ident, LitBool, LitStr, Token,
77
};
88

99
pub enum WasmerAttr {
1010
Export {
1111
/// The identifier is an override, otherwise we use the field name as the name
1212
/// to lookup in `instance.exports`.
1313
identifier: Option<LitStr>,
14+
optional: bool,
15+
aliases: Vec<LitStr>,
1416
span: Span,
1517
},
1618
}
1719

20+
#[derive(Debug)]
1821
struct ExportExpr {
1922
name: Option<LitStr>,
23+
optional: bool,
24+
aliases: Vec<LitStr>,
2025
}
2126

27+
#[derive(Debug)]
2228
struct ExportOptions {
2329
name: Option<LitStr>,
30+
optional: bool,
31+
aliases: Vec<LitStr>,
2432
}
2533
impl Parse for ExportOptions {
2634
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
27-
let ident = input.parse::<Ident>()?;
28-
let _ = input.parse::<Token![=]>()?;
29-
let ident_str = ident.to_string();
30-
let name;
35+
let mut name = None;
36+
let mut optional: bool = false;
37+
let mut aliases: Vec<LitStr> = vec![];
38+
loop {
39+
let ident = input.parse::<Ident>()?;
40+
let _ = input.parse::<Token![=]>()?;
41+
let ident_str = ident.to_string();
3142

32-
match ident_str.as_str() {
33-
"name" => {
34-
name = Some(input.parse::<LitStr>()?);
43+
match ident_str.as_str() {
44+
"name" => {
45+
name = Some(input.parse::<LitStr>()?);
46+
}
47+
"optional" => {
48+
optional = input.parse::<LitBool>()?.value;
49+
}
50+
"alias" => {
51+
let alias = input.parse::<LitStr>()?;
52+
aliases.push(alias);
53+
}
54+
otherwise => {
55+
abort!(
56+
ident,
57+
"Unrecognized argument in export options: expected `name = \"string\"`, `optional = bool`, or `alias = \"string\"` found `{}`",
58+
otherwise
59+
);
60+
}
3561
}
36-
otherwise => {
37-
abort!(
38-
ident,
39-
"Unrecognized argument in export options: expected `name` found `{}`",
40-
otherwise
41-
);
62+
63+
match input.parse::<Token![,]>() {
64+
Ok(_) => continue,
65+
Err(_) => break,
4266
}
4367
}
4468

45-
Ok(ExportOptions { name })
69+
Ok(ExportOptions {
70+
name,
71+
optional,
72+
aliases,
73+
})
4674
}
4775
}
4876

4977
impl Parse for ExportExpr {
5078
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
5179
let name;
80+
let optional;
81+
let aliases;
5282
if input.peek(Ident) {
5383
let options = input.parse::<ExportOptions>()?;
5484
name = options.name;
85+
optional = options.optional;
86+
aliases = options.aliases;
5587
} else {
5688
name = None;
89+
optional = false;
90+
aliases = vec![];
5791
}
58-
Ok(Self { name })
92+
Ok(Self {
93+
name,
94+
optional,
95+
aliases,
96+
})
5997
}
6098
}
6199

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

76114
let expr = export_expr.parse::<ExportExpr>()?;
77-
expr.name
115+
(expr.name, expr.optional, expr.aliases)
78116
} else {
79-
None
117+
(None, false, vec![])
80118
};
81119

82120
WasmerAttr::Export {
83121
identifier: name,
122+
optional,
123+
aliases,
84124
span,
85125
}
86126
}

0 commit comments

Comments
 (0)