pypyjs / pypyjs

PyPy compiled to JavaScript
MIT License
1.86k stars 154 forks source link

support for suspending / resuming VM #76

Open perkinslr opened 9 years ago

perkinslr commented 9 years ago

So I've got the twisted reactor running, which lets me incrementally execute some things, by scheduling periodic execution of reactor.iterate. Combined with select, this works okay for sockets, but not so well for os.pipe(), which multiprocessing uses. Ideally, a call to time.sleep should pause calculations for the VM and let other javascript stuff run. I can see 4 possible ways to implement it.

I know JS doesn't have first-class continuations, so it won't be as simple as (call/cc ), but it does support continuation passing, which could work for something like this. Probably would be rather difficult to do, since you'd have to preserve the existing stack.

PyPy itself has a weak form of continuation, in the _continuation module, which is not included in pypyjs currently. If this were available I think it would be fairly simple to implement suspend/resume using these single-use continuations. Basically you create a new continulet, which saves the current f_back, then abort out of the current calculation. Later, to resume, you set the saved continulet's f_back as the curren't frame's f_back, and it should pick up where it left off. I don't know how difficult it would be to get _continuation to compile and work for pypyjs, but it is probably the simplest solution.

The third method would be to modify pypy's main vm loop to support stopping and resuming. While it would be relatively simple, it would probably require multiple changes in pypy's core, which should be avoided if possible, since it wouldn't likely be accepted upstream.

Last would be to possibly use the empterpreter option, which is being considered for other reasons too. If it is likely that we'll see a build with empterpreter soon, it probably makes sense to see if that does what we need, especially since it could handle blocking operations better than a sleep loop does. If there are difficulties in making it work, or it isn't likely to be available soon, then I'll see about trying to compile _continuation.

rfk commented 9 years ago

I don't know how difficult it would be to get _continuation to compile and work for pypyjs, but it is probably the simplest solution.

I suspect this will be very difficult to get working. IIUC the current implementation uses platform-specific assember to copy the C stack, which is just not possible when targetting javascript.

Last would be to possibly use the empterpreter option, which is being considered for other reasons too.

I think this is the most likely path forward, although I'm not thrilled about the potential performance impact. It may even be possible to implement a _continuation module backend on top of the stack-managment provided by the emterpreter.

perkinslr commented 9 years ago

I believe that is correct, the wiki page for it points at .h files anyway, and it only supports x86/x86_64 at the moment. It is similar to the implementation of call/cc for CPython (from 1998, which eventually became stackless). I take it then that pypyjs piggybacks off of JS's stack? At which point we're back at the JS doesn't support continuations, and you'd have to implement your own stack to get around that.

emterpreter supports skipping some functions; the only function which really needs the suspend/resume functionality is time.sleep. Anything else that needs it can always just call time.sleep(0). Probably will need to compile with emterpreter to see what the actual performance impact is and go from there.