Skip to content

Commit 7101a53

Browse files
committed
Put JS_FUNC in thread local storage
1 parent d5d6603 commit 7101a53

File tree

2 files changed

+45
-25
lines changed

2 files changed

+45
-25
lines changed

wasm/lib/src/convert.rs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::cell::RefCell;
2+
13
use js_sys::{Array, ArrayBuffer, Object, Promise, Reflect, SyntaxError, Uint8Array};
24
use wasm_bindgen::{closure::Closure, prelude::*, JsCast};
35

@@ -13,6 +15,9 @@ use rustpython_vm::{exceptions, py_serde};
1315
use crate::browser_module;
1416
use crate::vm_class::{stored_vm_from_wasm, WASMVirtualMachine};
1517

18+
// Currently WASM do not support multithreading. We should change this once it is enabled.
19+
thread_local!(static JS_FUNC: RefCell<Option<js_sys::Function>> = RefCell::new(None));
20+
1621
#[wasm_bindgen(inline_js = r"
1722
export class PyError extends Error {
1823
constructor(info) {
@@ -149,6 +154,25 @@ pub fn pyresult_to_jsresult(vm: &VirtualMachine, result: PyResult) -> Result<JsV
149154
.map_err(|err| py_err_to_js_err(vm, &err))
150155
}
151156

157+
fn js_func_to_py(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
158+
JS_FUNC.with(|func| {
159+
let this = Object::new();
160+
for (k, v) in args.kwargs {
161+
Reflect::set(&this, &k.into(), &py_to_js(vm, v)).expect("property to be settable");
162+
}
163+
let js_args = Array::new();
164+
for v in args.args {
165+
js_args.push(&py_to_js(vm, v));
166+
}
167+
func.borrow()
168+
.as_ref()
169+
.unwrap()
170+
.apply(&this, &js_args)
171+
.map(|val| js_to_py(vm, val))
172+
.map_err(|err| js_err_to_py_err(vm, &err))
173+
})
174+
}
175+
152176
pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef {
153177
if js_val.is_object() {
154178
if let Some(promise) = js_val.dyn_ref::<Promise>() {
@@ -191,22 +215,8 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef {
191215
}
192216
} else if js_val.is_function() {
193217
let func = js_sys::Function::from(js_val);
194-
vm.ctx
195-
.new_method(move |vm: &VirtualMachine, args: PyFuncArgs| -> PyResult {
196-
let func = func.clone();
197-
let this = Object::new();
198-
for (k, v) in args.kwargs {
199-
Reflect::set(&this, &k.into(), &py_to_js(vm, v))
200-
.expect("property to be settable");
201-
}
202-
let js_args = Array::new();
203-
for v in args.args {
204-
js_args.push(&py_to_js(vm, v));
205-
}
206-
func.apply(&this, &js_args)
207-
.map(|val| js_to_py(vm, val))
208-
.map_err(|err| js_err_to_py_err(vm, &err))
209-
})
218+
JS_FUNC.with(|thread_func| thread_func.replace(Some(func.clone())));
219+
vm.ctx.new_method(js_func_to_py)
210220
} else if let Some(err) = js_val.dyn_ref::<js_sys::Error>() {
211221
js_err_to_py_err(vm, err).into_object()
212222
} else if js_val.is_undefined() {

wasm/lib/src/vm_class.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ use crate::js_module;
1919
use crate::wasm_builtins;
2020
use rustpython_compiler::mode::Mode;
2121

22+
// Currently WASM do not support multithreading. We should change this once it is enabled.
23+
thread_local!(static JS_FUNC: RefCell<Option<js_sys::Function>> = RefCell::new(None));
24+
2225
pub(crate) struct StoredVirtualMachine {
2326
pub vm: VirtualMachine,
2427
pub scope: RefCell<Scope>,
@@ -151,6 +154,20 @@ pub struct WASMVirtualMachine {
151154
pub(crate) id: String,
152155
}
153156

157+
fn stdout_js_func(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
158+
JS_FUNC.with(|func| {
159+
func.borrow()
160+
.as_ref()
161+
.unwrap()
162+
.call1(
163+
&JsValue::UNDEFINED,
164+
&wasm_builtins::format_print_args(vm, args)?.into(),
165+
)
166+
.map_err(|err| convert::js_py_typeerror(vm, err))?;
167+
Ok(vm.get_none())
168+
})
169+
}
170+
154171
#[wasm_bindgen(js_class = VirtualMachine)]
155172
impl WASMVirtualMachine {
156173
pub(crate) fn with_unchecked<F, R>(&self, f: F) -> R
@@ -229,15 +246,8 @@ impl WASMVirtualMachine {
229246
}
230247
} else if stdout.is_function() {
231248
let func = js_sys::Function::from(stdout);
232-
vm.ctx
233-
.new_method(move |vm: &VirtualMachine, args: PyFuncArgs| -> PyResult {
234-
func.call1(
235-
&JsValue::UNDEFINED,
236-
&wasm_builtins::format_print_args(vm, args)?.into(),
237-
)
238-
.map_err(|err| convert::js_py_typeerror(vm, err))?;
239-
Ok(vm.get_none())
240-
})
249+
JS_FUNC.with(|thread_func| thread_func.replace(Some(func.clone())));
250+
vm.ctx.new_method(stdout_js_func)
241251
} else if stdout.is_null() {
242252
fn noop(vm: &VirtualMachine, _args: PyFuncArgs) -> PyResult {
243253
Ok(vm.get_none())

0 commit comments

Comments
 (0)