Skip to content

Make rustpython-vm compatible with non-js wasm32-unknown & add tests #4211

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Make rustpython-vm compatible with non-js wasm32-unknown & add tests
  • Loading branch information
coolreader18 authored and youknowone committed Aug 8, 2024
commit 85030e368a37abfd14da707e6360eb6fc48f512c
8 changes: 8 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,14 @@ jobs:
env:
NODE_OPTIONS: "--openssl-legacy-provider"
working-directory: ./wasm/demo
- uses: mwilliamson/setup-wabt-action@v1
with: { wabt-version: "1.0.30" }
- name: check wasm32-unknown without js
run: |
cargo build --release -p wasm-unknown-test --target wasm32-unknown-unknown --verbose
if wasm-objdump -xj Import target/wasm32-unknown-unknown/release/wasm_unknown_test.wasm; then
echo "ERROR: wasm32-unknown module expects imports from the host environment" >2
fi
- name: build notebook demo
if: github.ref == 'refs/heads/release'
run: |
Expand Down
8 changes: 8 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ x86_64-pc-windows-msvc = { triplet = "x64-windows-static-md", dev-dependencies =
resolver = "2"
members = [
"compiler", "compiler/core", "compiler/codegen",
".", "common", "derive", "jit", "vm", "vm/sre_engine", "pylib", "stdlib", "wasm/lib", "derive-impl",
".", "common", "derive", "jit", "vm", "vm/sre_engine", "pylib", "stdlib", "derive-impl",
"wasm/lib", "wasm/wasm-unknown-test",
]

[workspace.package]
Expand Down
2 changes: 1 addition & 1 deletion stdlib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ssl-vendor = ["ssl", "openssl/vendored", "openssl-probe"]
[dependencies]
# rustpython crates
rustpython-derive = { workspace = true }
rustpython-vm = { workspace = true }
rustpython-vm = { workspace = true, default-features = false }
rustpython-common = { workspace = true }

ahash = { workspace = true }
Expand Down
10 changes: 6 additions & 4 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repository.workspace = true
license.workspace = true

[features]
default = ["compiler"]
default = ["compiler", "js"]
importlib = []
encodings = ["importlib"]
vm-tracing-logging = []
Expand All @@ -24,6 +24,8 @@ codegen = ["rustpython-codegen", "ast"]
parser = ["rustpython-parser", "ast"]
serde = ["dep:serde"]

js = ["getrandom/js", "chrono/wasmbind", "wasm-bindgen"]

[dependencies]
rustpython-compiler = { workspace = true, optional = true }
rustpython-codegen = { workspace = true, optional = true }
Expand Down Expand Up @@ -71,7 +73,7 @@ thread_local = { workspace = true }
memchr = { workspace = true }

caseless = "0.2.1"
getrandom = { version = "0.2.12", features = ["js"] }
getrandom = { version = "0.2.12" }
flamer = { version = "0.4", optional = true }
half = "1.8.2"
memoffset = "0.9.1"
Expand Down Expand Up @@ -140,8 +142,8 @@ features = [
"Win32_UI_WindowsAndMessaging",
]

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.92"
[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dependencies]
wasm-bindgen = { version = "0.2.92", optional = true }

[build-dependencies]
glob = { workspace = true }
Expand Down
7 changes: 6 additions & 1 deletion vm/src/stdlib/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ mod decl {
Ok(duration_since_system_now(vm)?.as_secs_f64())
}

#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
#[cfg(all(target_arch = "wasm32", feature = "js", not(target_os = "wasi")))]
fn _time(_vm: &VirtualMachine) -> PyResult<f64> {
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
Expand All @@ -115,6 +115,11 @@ mod decl {
Ok(Date::now() / 1000.0)
}

#[cfg(all(target_arch = "wasm32", not(feature = "js"), not(target_os = "wasi")))]
fn _time(vm: &VirtualMachine) -> PyResult<f64> {
Err(vm.new_not_implemented_error("time.time".to_owned()))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will need a way to implement time, I have the APIs in my environment, but I will need a way to override this

}

#[pyfunction]
fn monotonic(vm: &VirtualMachine) -> PyResult<f64> {
Ok(get_monotonic_time(vm)?.as_secs_f64())
Expand Down
7 changes: 6 additions & 1 deletion vm/src/vm/vm_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl VirtualMachine {
self.flush_std();
panic!("{msg}")
}
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
#[cfg(all(target_arch = "wasm32", feature = "js", not(target_os = "wasi")))]
{
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
Expand All @@ -32,6 +32,11 @@ impl VirtualMachine {
error(&s);
panic!("{}; exception backtrace above", msg)
}
#[cfg(all(target_arch = "wasm32", not(feature = "js"), not(target_os = "wasi")))]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be useful to still see information from the exception? Can't you do something like:

let err_string: String = exc.to_pyobject(vm).repr(vm).unwrap().to_string();

Or does the msg have everything we need?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be useful

{
let _ = exc;
panic!("{}; python exception not available", msg)
}
}

pub(crate) fn flush_std(&self) {
Expand Down
2 changes: 1 addition & 1 deletion wasm/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ rustpython-common = { workspace = true }
rustpython-pylib = { workspace = true, optional = true }
rustpython-stdlib = { workspace = true, default-features = false, optional = true }
# make sure no threading! otherwise wasm build will fail
rustpython-vm = { workspace = true, features = ["compiler", "encodings", "serde"] }
rustpython-vm = { workspace = true, features = ["compiler", "encodings", "serde", "js"] }

rustpython-parser = { workspace = true }

Expand Down
11 changes: 11 additions & 0 deletions wasm/wasm-unknown-test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "wasm-unknown-test"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
getrandom = { version = "0.2.7", features = ["custom"] }
rustpython-vm = { path = "../../vm", default-features = false, features = ["compiler"] }
1 change: 1 addition & 0 deletions wasm/wasm-unknown-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A test crate to ensure that `rustpython-vm` compiles on `wasm32-unknown-unknown` without a JS host.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

16 changes: 16 additions & 0 deletions wasm/wasm-unknown-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use rustpython_vm::{eval, Interpreter};

pub unsafe extern "C" fn eval(s: *const u8, l: usize) -> u32 {
let src = std::slice::from_raw_parts(s, l);
let src = std::str::from_utf8(src).unwrap();
Interpreter::without_stdlib(Default::default()).enter(|vm| {
let res = eval::eval(vm, src, vm.new_scope_with_builtins(), "<string>").unwrap();
res.try_into_value(vm).unwrap()
})
}

fn getrandom_always_fail(_buf: &mut [u8]) -> Result<(), getrandom::Error> {
Err(getrandom::Error::UNSUPPORTED)
}

getrandom::register_custom_getrandom!(getrandom_always_fail);