WordPress / wordpress-playground

Run WordPress in the browser via WebAssembly PHP
https://w.org/playground/
GNU General Public License v2.0
1.57k stars 221 forks source link

PHP WASM: Compile PHP to WASI #290

Open eliot-akira opened 1 year ago

eliot-akira commented 1 year ago

There was a pull request #113 that was exploring this direction, which was closed recently with a note to come back at a later time.

Let's look into collaborating with https://github.com/vmware-labs/webassembly-language-runtimes (see php-8.1.11) once WASI supports longjmp.

From what I understand, an advantage of compiling PHP to WASI is that it can be a standalone binary that runs without dependency on Node.js. I wanted to contribute a bit by gathering related links that I came across while studying about this topic.


In the WASI repo, there was an issue WebAssembly/WASI#490 asking about setjmp support. It was closed with the following note:

The current plan is to wait for the exception-handling proposal to be standardized and implemented in wasm engines, and then to implement setjmp and longjmp using that feature. Exception-handling is currently in phase 3.

So the feature will be implemented eventually. That implies that any workaround solution is temporary, to be replaced/removed in the future.


In the meantime, a WebAssembly / WASI port of Ruby was developed, which gets around the limitation by emulating setjmp and longjmp with Asyncify. I learned about it from these articles:

Then someone re-purposed that setjmp polyfill to integrate with PHP. Here's the as-yet-unmerged pull request:

In parallel, another person from VMware started on an ambitious effort in the PHP repo itself.


Hopefully this issue can serve as reference when there's progress in any of the above.

adamziel commented 1 year ago

What a great issue @eliot-akira, thank you so much for putting all this information together!

From what I understand, an advantage of compiling PHP to WASI is that it can be a standalone binary that runs without dependency on Node.js.

You're exactly right! I thought Asyncify was a JavaScript thing, but it seems like it's not. TIL! This certainly opens the door to supporting WASI. This would still be a challenge, though, unless we let Asyncify auto-wrap everything it wants to: https://github.com/WordPress/wordpress-playground/issues/251

adamziel commented 5 months ago

Related:

adamziel commented 5 months ago

The Python WASI demo shipped with container2wasm even handled os.fork():

code = '''
import os  
import time
pid = os.fork()   
if pid > 0:
    print("I am parent process:") 
    print("Process ID:", os.getpid()) 
    print("Child's process ID:", pid)
    time.sleep(3)
    print("Parent process is killed")
else:
    print("I am child process:") 
    print("Process ID:", os.getpid()) 
    print("Parent's process ID:", os.getppid()) 
    time.sleep(3)
    print("child process is killed")
'''

with open("process_test.py", "w") as file:
     file.write(code)

import process_test

Now, these demos ship an entire OS compiled to WASM and require more resources to run, but for something like a development environment that should be fine.

I wonder whether the WASI shim can handle forking a process. If so, perhaps we could ditch emscripten, migrate to WASI entirely, and get more features with less patches.

adamziel commented 5 months ago

Container2Wasm demos are impressive but also too slow for any real-world use:

browser_wasi_shim is promising and its filesystem implementation looks much cleaner than the Emscripten's one, but it has important limitations:

On the upside, there were some explorations to support the WebAssembly Component Model.

Either way, there's nothing actionable here today.

adamziel commented 2 months ago

It is possible that recent WASM runtimes support longjmp and exceptions which means we could potentially produce a standalone WASI now – this needs investigation:

https://github.com/emscripten-core/emscripten/issues/20484

I'm not sure what about async IO and fork