Host Function capability to call into Wasm Function
Motivation
Host code sometimes needs to call Wasm functions for runtime-related issues. For example in AssemblyScript the __new() function is exported to allow host code to allocate memory for an object which it can then write to. The most obvious example of this is for passing strings, where AssemblyScript expects points to objects inside Wasm memory & host code needs to use __new() to allocate a string object of the appropriate size in order to then copy bytes into the Wasm memory.
If you do this for input to the Wasm function it is quite achievable currently in WasmEdge: execute a call to __new() use the pointer to setup the string, pass the pointer as an integer parameter to the execute for the main function being called. However for Host Functions this approach does not seem to work: you are already in the context of a Wasm function, which then calls the Host Function ... if you then call into __new() via another execute call -> the __new() call works, but the system segfaults on return from the Host Function (i.e. attempting to return back to the calling Wasm Function).
Currently therefore with AssemblyScript string you can achieve:
- Pass string into Wasm function
- Return string from Wasm function
- Pass string into Host function call from Wasm
But not:
- Return string from Host function call (cannot allocate string to return)
Details
I am not a C++ programmer so I'm stumbling around in the dark a little. However it appears to me that what is happening is probably around the implementation of Executer::runFunction (which seems to be ultimately where you end up after calling the API WasmEdge_VMExecute method). Within the runFunction it explicitly has a step around 'Reset and push a dummy frame into Stack', before then calling enterFunction and execute. From within a Host Function context, this would have the effect of resetting the stack state used by the calling Wasm function & probably therefore explain the issue once the Host Function returns.
On the other hand, the implementation of runCallOp (inside Wasm execution) just calls enterFunction, and then lets execution proceed. It seems to me (simplistically) that a new method (something like callFunction), and corresponding API method, could allow the Host Function to call a function using the existing stack context on top of the existing frames .. so that unwinding of the frames was still possible. There are probably additional complexities that I am not aware of, but hopefully the principal is correct.
Source: WasmEdge/WasmEdge