Use WASI to model the system interface
In the current runtime, we already have various ad hoc simulations of system interfaces like read, write, etc. The problem of these ad hoc simulations is:
- An interface is implemented only when we discover it blocks some interesting examples we care about (e.g. the
clock_*APIs are implemented to unblockQuickCheck) - They don't work well with
node. To avoid conditional compilation inrts, we assume a "minimal environment" which mostly models the browser, so e.g.readcannot call realfs.readSyncand use real file descriptors. - They are hard-wired and can't be overloaded via our rts api. We may want to override the implementation of certain interfaces.
In the WebAssembly ecosystem, there's now WASI which has the hope of becoming the target-independent ABI standard. We should start using WASI to model our system interface, provide node/browser default WASI capabilities, and allow certain parts of those capabilities to be overridden.
Note that using WASI doesn't mean our code can be run on environments like wasmtime, since we still depend on JS in a lot of places, and that situation will remain for quite some while. But moving system interfaces to WASI should still be a good move towards that direction.
Since the WASI Core API depends on passing i64 across js/wasm boundary, this issue and #407 is blocked by #33. Better implement a uniform i64 FFI mechanism and clean up our ad-hoc type casts here and there.
The WASI API documentation doesn't seem to match the implementation. I eyeballed the wasm-objdump of a "typical" wasi binary from https://wapm.io/package/lucklove/tidb#explore, and the wasi_unstable import function signatures don't match the API documentation.
One example: __wasi_clock_time_get, according to the doc, the signature should be (i32, i64) -> i64, but the actual signature found in the binary is (i32, i64, i32) -> i32.
I also checked wasmer source code; from the implementation the semantics is (clock_id, precision, result_ptr) -> errno. Maybe the doc is still correct and it's a semi-automatic handling of i64 return value thing, I don't know.
See https://github.com/WebAssembly/WASI/issues/54 for upstream discussion of i64 FFI problem
The status quo seems to be:
- For non-web engines like
wasmerorwasmtime,i64can appear in awasiimport type signature's parameter list. The engine handles that perfectly; although I don't understand whyi64isn't directly returned, but instead a pointer is often used to pass ani64result - For web engines,
wasmer-jsimplements alower_i64_importstransformation on the binary module. Well, this may explain whyi64appears in parameters but not results at the ABI level.... binaryenalso seems to implement thei64lowering transformation. Haven't checked whether/how that's used byemscripten.
So. When writing our wasi capabilities, we need to:
- Write a default version that matches the
i64ABI, assumingi64parameters are passed asBigInt. This will work when theBigIntintegration feature flag is on (works in V8 but off by default) - For each wasi interface, we have a wrapper which matches the lowered ABI, and calls the
i64version. Or this can be derived from a value-level type signatures accompanying each of the interfaces we write.
What a wild west we're dealing here..
Am I correct in assuming that there hasn't been any progress here since 2019?