Skip to content

[WASM] How would a VirtualMachine class work for binding to JS? #262

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
coolreader18 opened this issue Jan 28, 2019 · 6 comments · Fixed by #267
Closed

[WASM] How would a VirtualMachine class work for binding to JS? #262

coolreader18 opened this issue Jan 28, 2019 · 6 comments · Fixed by #267

Comments

@coolreader18
Copy link
Member

Given that a VirtualMachine could potentially take up a lot of memory, what would be the smartest way to make a JS class to manage it? The pyEval function is sufficient for simple things, but it might be desirable to persist the context over, e.g. for a REPL.

I see two or three ways to do this:

  • Hold created VirtualMachines in a global HashMap by randomly generated IDs, and have a .destroy() method on the JS class that has to be called or risk a memory leak.
  • Only allow one VirtualMachine per JS context, held in a global variable, initialized at load.
  • Implement a way for the entire Python context to be serialized (probably not feasible at the moment, nor necessarily worth the time).

I considered some stuff with maybe JS WeakSets or WeakMaps (that take an object as a key but don't prevent it or its value from being garbage-collected), but I don't think that would be able to do anything.

@coolreader18
Copy link
Member Author

coolreader18 commented Jan 28, 2019

Another option would be to have a global variable of type HashMap<String, VirtualMachine> where the keys are IDs that are managed from JS:

// initialize vm
const vm = rp.vms.init("main"); // basically just { id: "main" }
// do stuff with the vm
vm.addVariable("something");
vm.compileAndRun("print('thing')");
// destroy the vm, not necessary if it should be
// kept for the lifetime of the program like for a repl
vm.destroy();
// or also:
rp.vms.destroy("main");

// this guarantees that the vms can always be accessed, and can be cleared individually
const vmIds = rp.vms.ids() // ["main", "other_id"]
const otherVm = rp.vms.get("other_id")
if (vmIds.contains("main")) {
  /* finish up work w/ main */
  rp.vms.destroy("main");
}

// or clear them all at once
rp.vms.clear()

// if you use it after it's been destroyed, it throws an error
otherVm.destroy();
try {
  otherVm.doThing();
} catch (e) {
  e // Error: Invalid VM ID, it was freed while this reference was still held
}

otherVm.valid() // boolean

rp.vms.get("nonexistent"); // undefined

I'm just sketching things out here, but I think this could work pretty well.

@coolreader18
Copy link
Member Author

Related to #209

@windelbouwman
Copy link
Contributor

In CPython there exists some global variables which contain state information about the python instance. In rustpython we capture this information in the VirtualMachine struct. It would be good to store this struct in a variable in a way as you suggested. It should be possible to create two fully independent virtual machines in the same process. This is the idea! Your example looks good to me!

@coolreader18
Copy link
Member Author

Alright, I think I'll start working on this then.

@coolreader18
Copy link
Member Author

Okay, apparently this isn't doable because a VirtualMachine isn't Send, so it can't be stored in a static variable. I'm looking into stuff like Box::leak to see if it's possible in some other way.

@coolreader18
Copy link
Member Author

Ah, never mind, I can use a thread local variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants