alexcrichton opened issue #7349:
Currently Cranelift is a required feature of the C API due to the C API's usage of
Func::new{,_unchecked}
which require Cranelift to emit some trampolines. This means that in general only Rust gets to benefit from Cranelift-less builds which is not ideal since other embeddings may wish to exclude Cranelift for security or binary size reasons as well. We should figure out how to implementFunc::new
without requiring cranelift.
alexcrichton added the wasmtime:c-api label to Issue #7349.
github-actions[bot] commented on issue #7349:
Subscribe to Label Action
cc @peterhuene
<details>
This issue or pull request has been labeled: "wasmtime:c-api"Thus the following users have been cc'd because of the following labels:
- peterhuene: wasmtime:c-api
To subscribe or unsubscribe from this label, edit the <code>.github/subscribe-to-label.json</code> configuration file.
Learn more.
</details>
Milek7 commented on issue #7349:
I have been thinking about this.
wasm->array trampolines could be stored in the compiled module. Currently there's an assumption that whenwasm_call
is null then the callee is always native. Some flag would need to be added to VMFuncRef to decide whether to pick wasm->native or wasm->array trampoline. Alternatively callee could stay as always native and instead native->array trampolines could be stored in the module, and then usingFunc::new
would chain wasm->native and native->array together.
Though neither approach would solveTypedFunc::call
calling intoFunc::new
when no appropriate trampolines are available in the loaded modules. I see only two possible solutions for that, both not particularly desirable: either monomorphizing array call inTypedFunc::call
for use when native callee is not available, or universal runtime native->array trampoline hand-written in assembly.Maybe this case could be just ignored, because
TypedFunc
is not accessible from C anyway. Another option would be not providingFunc::new
in the C API when building without JIT and instead provideFunc::wrap
counterpart, but this has its own problems (currentlywrap
machinery relies on monomorphized shims, so that would again require hand-written assembly)What's your opinion on this?
alexcrichton commented on issue #7349:
Thanks for helping to think about this, it's much appreciated!
Though neither approach would solve TypedFunc::call calling into Func::new when no appropriate trampolines are available in the loaded modules
I agree that this is the main tricky bit. We've tried pretty hard to avoid handwritten assembly (removing it later whenever we've added it at some point) so if possible I'd prefer to avoid that route. When I was last thinking about it I was concluding what you're thinking here too which is to add an array call path to
TypedFunc::call
for when the native trampoline is null.Maybe this case could be just ignored, because TypedFunc is not accessible from C anyway
While I think you might be right today this is also sort of tricky. Modules can reexport their imports so it's possible to get your hands on a function defined with
TypedFunc::wrap
, by, e.g. reexporting a WASI-defined import. It's still difficult to get toTypedFunc::call
in the C API but I think it might not be as far away as we might otherwise think. Additionally if even just for the Rust API I think it'd be good to handle this case too.instead provide Func::wrap counterpart
I'd agree this isn't feasible, I don't know how we'd actually do this in any way other than saying "these are the supported signatures" and you'd be out of luck if your signature wasn't there.
One thing I've wondered in the past as well is whether the dual of array/native calling conventions are actually buying us anything. While I don't think there's any doubt that an array calling convention is slower than native it might be the case that it's not slower enough to really make a difference. For example we could also solve some questions in this issue by posing the question: "what if we removed the native calling convention?". That would make most of these issues go away at the cost of performance at callsites. I'm not sure if the perf hit is really that noticeable, though, outside of microbenchmarks.
alexcrichton closed issue #7349:
Currently Cranelift is a required feature of the C API due to the C API's usage of
Func::new{,_unchecked}
which require Cranelift to emit some trampolines. This means that in general only Rust gets to benefit from Cranelift-less builds which is not ideal since other embeddings may wish to exclude Cranelift for security or binary size reasons as well. We should figure out how to implementFunc::new
without requiring cranelift.
Last updated: Dec 23 2024 at 12:05 UTC