Skip to content

Commit 7a522e7

Browse files
committed
Update VM calls docs
1 parent e28dab7 commit 7a522e7

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

docs/emulator/vmcalls.md

+25-2
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,30 @@ The helper function `machine.instruction_limit_reached()` will tell you if the i
222222

223223
It is possible to interrupt a running machine to perform another task. This can be done using the `machine.preempt()` function. A machine can also interrupt itself without any issues. Preemption stores and restores all registers, making it slightly expensive, but guarantees the ability to preempt from any location.
224224

225-
High-quality scripting solutions will use pre-emption when re-entrancy is detected:
225+
### Alternative 1:
226+
227+
```cpp
228+
template <typename... Args>
229+
inline std::optional<int64_t> Script::call(gaddr_t address, Args&&... args)
230+
{
231+
try
232+
{
233+
return {machine().preempt(MAX_CALL_INSTR, address, std::forward<Args>(args)...)};
234+
}
235+
catch (const std::exception& e)
236+
{
237+
this->handle_exception(address);
238+
}
239+
return std::nullopt;
240+
}
241+
```
242+
This example uses optional to determine if a call failed. Otherwise, it returns an (optional) integer which is the return value from the called function. `MAX_CALL_INSTR` is the number of instruction to execute before it's considered a timeout. `address` is the address of the function we want to call, which you can get with `machine.address_of("my_function")`.
243+
244+
We make `handle_exception()` opaque so that it hides the implementation, and inside we re-throw the exception to handle it properly.
245+
246+
### Alternative 2:
247+
248+
High-quality scripting solutions will use pre-emption only when re-entrancy is detected:
226249
227250
```cpp
228251
template <typename... Args>
@@ -247,4 +270,4 @@ inline std::optional<Script::sgaddr_t> Script::call(gaddr_t address, Args&&... a
247270
return std::nullopt;
248271
}
249272
```
250-
From `script.call(...)` as implemented in the [gamedev example](https://github.com/libriscv/libriscv/blob/master/examples/gamedev/script.hpp). `ScriptDepthMeter` measures the current call depth in order to avoid recursive calls back into the script, while also using `preempt()` on the second call.
273+
From `script.call(...)` as implemented in the [gamedev example](https://github.com/libriscv/libriscv/blob/master/examples/gamedev/script.hpp). `ScriptDepthMeter` measures the current call depth in order to avoid too many recursive calls back into the script, while also using the faster `vmcall()` on the first call.

0 commit comments

Comments
 (0)