Skip to content

Commit 3730ca2

Browse files
authored
Merge pull request RustPython#551 from coolreader18/store-rcs-in-stored-vm
[WASM] Keep a PyObjectWeakRef to the PyObjectRef being moved to a closure
2 parents 9e827cf + f1b156d commit 3730ca2

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

wasm/lib/src/convert.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ pub fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue {
2222
let wasm_vm = WASMVirtualMachine {
2323
id: wasm_id.clone(),
2424
};
25-
let mut py_obj = Some(py_obj);
25+
let weak_py_obj = wasm_vm.push_held_rc(py_obj).unwrap();
26+
2627
let closure =
2728
move |args: Option<Array>, kwargs: Option<Object>| -> Result<JsValue, JsValue> {
2829
let py_obj = match wasm_vm.assert_valid() {
29-
Ok(_) => py_obj.clone().expect("py_obj to be valid if VM is valid"),
30+
Ok(_) => weak_py_obj
31+
.upgrade()
32+
.expect("weak_py_obj to be valid if VM is valid"),
3033
Err(err) => {
31-
py_obj = None;
3234
return Err(err);
3335
}
3436
};
@@ -57,7 +59,8 @@ pub fn py_to_js(vm: &mut VirtualMachine, py_obj: PyObjectRef) -> JsValue {
5759
as Box<dyn FnMut(Option<Array>, Option<Object>) -> Result<JsValue, JsValue>>);
5860
let func = closure.as_ref().clone();
5961

60-
// TODO: Come up with a way of managing closure handles
62+
// stores pretty much nothing, it's fine to leak this because if it gets dropped
63+
// the error message is worse
6164
closure.forget();
6265

6366
return func;

wasm/lib/src/vm_class.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,16 @@ use std::collections::HashMap;
1313
use std::rc::{Rc, Weak};
1414
use wasm_bindgen::prelude::*;
1515

16+
pub trait HeldRcInner {}
17+
18+
impl<T> HeldRcInner for T {}
19+
1620
pub(crate) struct StoredVirtualMachine {
1721
pub vm: VirtualMachine,
1822
pub scope: ScopeRef,
23+
/// you can put a Rc in here, keep it as a Weak, and it'll be held only for
24+
/// as long as the StoredVM is alive
25+
held_rcs: Vec<Rc<dyn HeldRcInner>>,
1926
}
2027

2128
impl StoredVirtualMachine {
@@ -27,7 +34,11 @@ impl StoredVirtualMachine {
2734
setup_browser_module(&mut vm);
2835
}
2936
vm.wasm_id = Some(id);
30-
StoredVirtualMachine { vm, scope }
37+
StoredVirtualMachine {
38+
vm,
39+
scope,
40+
held_rcs: vec![],
41+
}
3142
}
3243
}
3344

@@ -211,6 +222,17 @@ impl WASMVirtualMachine {
211222
STORED_VMS.with(|cell| cell.borrow().contains_key(&self.id))
212223
}
213224

225+
pub(crate) fn push_held_rc<T: HeldRcInner + 'static>(
226+
&self,
227+
rc: Rc<T>,
228+
) -> Result<Weak<T>, JsValue> {
229+
self.with(|stored_vm| {
230+
let weak = Rc::downgrade(&rc);
231+
stored_vm.held_rcs.push(rc);
232+
weak
233+
})
234+
}
235+
214236
pub fn assert_valid(&self) -> Result<(), JsValue> {
215237
if self.valid() {
216238
Ok(())
@@ -234,6 +256,7 @@ impl WASMVirtualMachine {
234256
move |StoredVirtualMachine {
235257
ref mut vm,
236258
ref mut scope,
259+
..
237260
}| {
238261
let value = convert::js_to_py(vm, value);
239262
scope.locals.set_item(&vm.ctx, &name, value);
@@ -247,6 +270,7 @@ impl WASMVirtualMachine {
247270
move |StoredVirtualMachine {
248271
ref mut vm,
249272
ref mut scope,
273+
..
250274
}| {
251275
let print_fn: Box<Fn(&mut VirtualMachine, PyFuncArgs) -> PyResult> =
252276
if let Some(selector) = stdout.as_string() {
@@ -315,6 +339,7 @@ impl WASMVirtualMachine {
315339
|StoredVirtualMachine {
316340
ref mut vm,
317341
ref mut scope,
342+
..
318343
}| {
319344
source.push('\n');
320345
let code =

0 commit comments

Comments
 (0)