asterius icon indicating copy to clipboard operation
asterius copied to clipboard

Use WASI to model the system interface

Open TerrorJack opened this issue 6 years ago • 5 comments

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 unblock QuickCheck)
  • They don't work well with node. To avoid conditional compilation in rts, we assume a "minimal environment" which mostly models the browser, so e.g. read cannot call real fs.readSync and 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.

TerrorJack avatar Dec 17 '19 15:12 TerrorJack

Major WASI reference list:

WASI Core API WASI Constants

TerrorJack avatar Dec 19 '19 15:12 TerrorJack

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.

TerrorJack avatar Dec 19 '19 16:12 TerrorJack

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.

TerrorJack avatar Dec 19 '19 17:12 TerrorJack

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 wasmer or wasmtime, i64 can appear in a wasi import type signature's parameter list. The engine handles that perfectly; although I don't understand why i64 isn't directly returned, but instead a pointer is often used to pass an i64 result
  • For web engines, wasmer-js implements a lower_i64_imports transformation on the binary module. Well, this may explain why i64 appears in parameters but not results at the ABI level....
  • binaryen also seems to implement the i64 lowering transformation. Haven't checked whether/how that's used by emscripten.

So. When writing our wasi capabilities, we need to:

  • Write a default version that matches the i64 ABI, assuming i64 parameters are passed as BigInt. This will work when the BigInt integration 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 i64 version. 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..

TerrorJack avatar Dec 21 '19 20:12 TerrorJack

Am I correct in assuming that there hasn't been any progress here since 2019?

theduke avatar Feb 08 '22 10:02 theduke