wasmi
wasmi copied to clipboard
Ability to run WASM functions one instruction at a time
Long story short: It'd be really great if I could step through a WASM function's instructions one-by-one instead of having to execute the whole function start-to-finish. This doesn't seem to be currently possible if I'm understanding the documentation and source code right.
Possible use-cases:
- Erlang-style preemptive concurrency (executing a module with a specified number of "reductions", after which execution forcibly pauses to allow other functions to run)
- Debuggers (e.g. to step through execution op-by-op and validate execution state)
I can think of a couple ways off the top of my head I'd go about implementing this:
- Pass in an optional maximum number of instructions to be executed (i.e. into
Interpreter.run_interpreter_loopandInterpreter.do_run_function- and in turn into any functions calling it); ifSome(max), keep looping and decrementing untilmax == 0, then throw a resumable trap. - Define entirely new functions that implement stepping (and possibly reimplement the existing functions in e.g.
impl Interpreterto wrap these, if we want to avoid code duplication).
Would y'all be open to a PR implementing one or more of the above (or perhaps some entirely-different strategy)? I realize the first option is most likely going to be a breaking change (unless perhaps combined with the second option).
Yeah, that sounds useful. People are also interested in profiling support (#197), which IMO could be related here.
It seems that the easiest option to implement would be the first one. I think we can even get away without introducing a breaking change. However, I am really not keen on going down this path since at some point we will end up with a kitchen sink. Existence "resumable traps" kind of proves the point.
The second option sounds tempting. I had some ideas on extracting and traitification of run_* functions from Interpreter and reusing them for assembling custom steppers: it could be execute N-steps, a debugger, or we could reimplement resumable traps as a custom stepper. We could probably implement a profiling stepper (although I think it might be a better idea to just add hooks to the default stepper because of DRY).
I didn't have much time to think through this kind of design though and I am not sure if this is the way we would like to follow ultimately. If you still want to research this path, it would be welcome!
So I've started to go down that second path with a smattering of the first path (tracked in a stepper branch in my fork: https://github.com/YellowApple/wasmi/tree/stepper). So far I've implemented Interpreter::step_function() and a StepResult enum, pulling the code out of do_run_function() (and in turn rewriting do_run_function() as a wrapper around step_function() to keep things nice and DRY), and all tests are still passing. The difference between step_function() and do_run_function() is the addition of an additional u64 argument (reductions); if it's zero, then it'll loop infinitely like how wasmi currently behaves, but if it's greater than zero, then it'll loop until it reaches the reductionsnth iteration (at which point - if it hasn't returned or branched yet - it'll return a StepResult::Continue that'll eventually get passed up the chain.
Thoughts so far? I'm gonna keep venturing further up the call chain here and see if I can continue to make some good progress. Not to toot my own horn here, but considering this is the first time I've actually hacked on a (serious) Rust codebase, I'm a bit proud of the fact I've made any progress at all without completely breaking tests, let alone all tests continuing to pass :)
@YellowApple I am currently cleaning up the issues list of wasmi. Is this feature still relevant to you?
The problem is that wasmi is primarily used by Parity as an interpreter for Substrate smart contracts. Therefore if we ever plan on implementing this feature we must not compromise on the performance of it as an interpreter.
I think this is possible, thought, probably will require quite an amount of work in order to be well implemented.
I'd like to close this issue if this feature is no longer relevant to you. If you ever feel you have a need for this feature again feel free to reopen if we decide to close this issue. I will close this issue if I do not hear back from you within a week.
Yeah, if y'all want to close this for now, go for it. I can always reopen if/when I resume work on implementing this, but I ended up switching languages for the project I had in mind for this so this is no longer a priority for me.
Thanks for the quick info!
You'd probably need to reimplement this using the new wasmi engine though ...
Closed.