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

Allow using WASI APIs in the Python extension #533

Merged
merged 4 commits into from
Nov 11, 2019
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
1 change: 1 addition & 0 deletions crates/interface-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ wasmparser = { version = "0.39.2", default-features = false }
wasm-webidl-bindings = "0.6"
wasmtime-jit = { path = '../jit', default-features = false }
wasmtime-runtime = { path = '../runtime', default-features = false }
wasmtime-wasi = { path = '../wasi' }

[badges]
maintenance = { status = "actively-developed" }
44 changes: 29 additions & 15 deletions crates/interface-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use value::Value;
/// appropriate for bound functions.
pub struct ModuleData {
inner: Option<Inner>,
wasi_module_name: Option<String>,
}

struct Inner {
Expand Down Expand Up @@ -65,17 +66,38 @@ impl ModuleData {
// find the right section.
let mut reader = wasmparser::ModuleReader::new(wasm)?;
let mut found = false;
let mut wasi_module_name = None;
while !reader.eof() {
let section = reader.read()?;
if let wasmparser::SectionCode::Custom { name, .. } = section.code {
if name == "webidl-bindings" {
found = true;
break;

match section.code {
wasmparser::SectionCode::Custom { name, .. } => {
if name == "webidl-bindings" {
found = true;
break;
}
}

// If we see the import section then see if we can find a wasi
// module import which we can later use to register the wasi
// implementation automatically.
wasmparser::SectionCode::Import => {
let section = section.get_import_section_reader()?;
for import in section {
let import = import?;
if wasmtime_wasi::is_wasi_module(import.module) {
wasi_module_name = Some(import.module.to_string());
}
}
}
_ => {}
}
}
if !found {
return Ok(ModuleData { inner: None });
return Ok(ModuleData {
inner: None,
wasi_module_name,
});
}

// Ok, perform the more expensive parsing. WebAssembly interface types
Expand All @@ -96,21 +118,13 @@ impl ModuleData {

Ok(ModuleData {
inner: Some(Inner { module }),
wasi_module_name,
})
}

/// Detects if WASI support is needed: returns module name that is requested.
pub fn find_wasi_module_name(&self) -> Option<String> {
self.inner.as_ref().and_then(|Inner { module }| {
module
.imports
.iter()
.find(|walrus::Import { module, .. }| match module.as_str() {
"wasi" | "wasi_unstable" => true,
_ => false,
})
.map(|walrus::Import { module, .. }| module.clone())
})
self.wasi_module_name.clone()
}

/// Same as `Context::invoke` except that this works with a `&[Value]` list
Expand Down
1 change: 1 addition & 0 deletions crates/misc/py/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ wasmtime-environ = { path = "../../environ" }
wasmtime-interface-types = { path = "../../interface-types" }
wasmtime-jit = { path = "../../jit" }
wasmtime-runtime = { path = "../../runtime" }
wasmtime-wasi = { path = "../../wasi" }
target-lexicon = { version = "0.9.0", default-features = false }
anyhow = "1.0.19"
region = "2.0.0"
Expand Down
14 changes: 14 additions & 0 deletions crates/misc/py/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ pub fn instantiate(
}

let data = Rc::new(ModuleData::new(wasm_data).map_err(err2py)?);

// If this module expects to be able to use wasi then go ahead and hook
// that up into the imported crates.
if let Some(module_name) = data.find_wasi_module_name() {
let wasi_handle =
wasmtime_wasi::instantiate_wasi("", context.get_global_exports(), &[], &[], &[])
.map_err(|e| err2py(e.into()))?;
context.name_instance(module_name, wasi_handle);
}
let instance = context
.instantiate_module(None, wasm_data)
.map_err(|e| err2py(e.into()))?;
Expand Down Expand Up @@ -111,6 +120,11 @@ pub fn imported_modules<'p>(py: Python<'p>, buffer_source: &PyBytes) -> PyResult
let reader = section.get_import_section_reader().unwrap();
for import in reader {
let import = import.unwrap();
// Skip over wasi-looking imports since those aren't imported from
// Python but rather they're implemented natively.
if wasmtime_wasi::is_wasi_module(import.module) {
continue;
}
let set = match dict.get_item(import.module) {
Some(set) => set.downcast_ref::<PySet>().unwrap(),
None => {
Expand Down
3 changes: 2 additions & 1 deletion crates/wasi-common/winx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ features = [
"errhandlingapi",
"handleapi",
"processthreadsapi",
"profileapi",
"securitybaseapi",
"winbase",
"winerror",
"ws2def",
"fileapi",
"aclapi"
"aclapi",
]

[badges]
Expand Down
7 changes: 7 additions & 0 deletions crates/wasi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ mod instantiate;
mod syscalls;

pub use instantiate::{instantiate_wasi, instantiate_wasi_with_context};

pub fn is_wasi_module(name: &str) -> bool {
// FIXME: this should be more conservative, but while WASI is in flux and
// we're figuring out how to support multiple revisions, this should do the
// trick.
name.starts_with("wasi")
}