Skip to content

Commit

Permalink
Try to use prepared calls for Event
Browse files Browse the repository at this point in the history
  • Loading branch information
fwsGonzo committed Jun 20, 2024
1 parent d60adf3 commit 821c5f6
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 33 deletions.
52 changes: 22 additions & 30 deletions engine/src/script/event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ enum EventUsagePattern : int {
template <typename F, EventUsagePattern Usage = PerThread>
struct Event
{
Event() = default;
Event(Script&, const std::string& func);
Event(Script&, Script::gaddr_t address);

Expand All @@ -24,32 +23,27 @@ struct Event
template <typename... Args>
auto call(Args&&... args);

bool is_callable() const noexcept
{
return m_script != nullptr && m_addr != 0x0;
}

auto& script() noexcept
{
assert(m_script != nullptr);
auto* script_ptr = m_pcall.machine().template get_userdata<Script>();
if constexpr (Usage == EventUsagePattern::PerThread)
return m_script->get_fork();
return script_ptr->get_fork();
else
return *m_script;
return *script_ptr;
}

const auto& script() const noexcept
{
assert(m_script != nullptr);
auto* script_ptr = m_pcall.machine().template get_userdata<Script>();
if constexpr (Usage == EventUsagePattern::PerThread)
return m_script->get_fork();
return script_ptr->get_fork();
else
return *m_script;
return *script_ptr;
}

auto address() const noexcept
{
return m_addr;
return m_pcall.address();
}

// Turn address into function name (as long as it's visible)
Expand All @@ -59,20 +53,21 @@ struct Event
}

private:
Script* m_script = nullptr;
Script::gaddr_t m_addr = 0;
riscv::PreparedCall<Script::MARCH, F> m_pcall;
};

template <typename F, EventUsagePattern Usage>
inline Event<F, Usage>::Event(Script& script, const std::string& func)
: m_script(&script), m_addr(script.address_of(func))
inline Event<F, Usage>::Event(Script& script, Script::gaddr_t address)
: m_pcall(script.machine(), address)
{
}

template <typename F, EventUsagePattern Usage>
inline Event<F, Usage>::Event(Script& script, Script::gaddr_t address)
: m_script(&script), m_addr(address)
inline Event<F, Usage>::Event(Script& script, const std::string& func)
: Event(script, script.address_of(func))
{
if (address() == 0x0)
throw std::runtime_error("Function not found: " + func);
}

template <typename F, EventUsagePattern Usage>
Expand All @@ -81,17 +76,14 @@ template <typename... Args> inline auto Event<F, Usage>::call(Args&&... args)
static_assert(std::is_invocable_v<F, Args...>);
using Ret = decltype((F*){}(args...));

if (is_callable())
{
auto& script = this->script();
if (auto res = script.call(address(), std::forward<Args>(args)...)) {
if constexpr (std::is_same_v<void, Ret>)
return true;
else if constexpr (std::is_same_v<Script::gaddr_t, Ret>)
return res;
else
return std::optional<Ret> (res.value());
}
auto& script = this->script();
if (auto res = script.template prepared_call<F, Args...>(m_pcall, std::forward<Args>(args)...)) {
if constexpr (std::is_same_v<void, Ret>)
return true;
else if constexpr (std::is_same_v<Script::gaddr_t, Ret>)
return res;
else
return std::optional<Ret> (res.value());
}
if constexpr (std::is_same_v<void, Ret>)
return false;
Expand Down
29 changes: 29 additions & 0 deletions engine/src/script/script.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <any>
#include <functional>
#include <libriscv/machine.hpp>
#include <libriscv/prepared_call.hpp>
#include <optional>
#include <unordered_set>
#include "script_depth.hpp"
Expand Down Expand Up @@ -259,6 +260,13 @@ struct Script
/// @return The script instance with the given name.
static Script& Find(const std::string& name);

/// @brief Make a prepared function call into the script
/// @param pcall The prepared call object.
/// @param args The arguments to pass to the function.
/// @return The optional integral return value.
template <typename F, typename... Args>
std::optional<Script::sgaddr_t> prepared_call(riscv::PreparedCall<MARCH, F>& pcall, Args&&... args);

// Create new Script instance from file
Script(
const std::string& name, const std::string& filename,
Expand Down Expand Up @@ -368,6 +376,27 @@ inline std::optional<Script::sgaddr_t> Script::call(const std::string& func, Arg
return {this->call(address, std::forward<Args>(args)...)};
}

template <typename F, typename... Args>
inline std::optional<Script::sgaddr_t> Script::prepared_call(riscv::PreparedCall<MARCH, F>& pcall, Args&&... args)
{
ScriptDepthMeter meter(this->m_call_depth);
try
{
if (LIKELY(meter.is_one()))
return {pcall.vmcall(std::forward<Args>(args)...)};
else if (LIKELY(meter.get() < MAX_CALL_DEPTH))
return {machine().preempt(MAX_CALL_INSTR, pcall.address(),
std::forward<Args>(args)...)};
else
this->max_depth_exceeded(pcall.address());
}
catch (const std::exception& e)
{
this->handle_exception(pcall.address());
}
return std::nullopt;
}

template <typename... Args>
inline std::optional<Script::sgaddr_t> Script::preempt(gaddr_t address, Args&&... args)
{
Expand Down
2 changes: 1 addition & 1 deletion ext/libriscv
6 changes: 4 additions & 2 deletions tests/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ TEST_CASE("Simple events", "[Events]")
REQUIRE(obj.at(0).arg2 == 123);

/* Function that doesn't exist */
Event<void()> ev6(script, "VoidlessFunc");
REQUIRE(!ev6.call());
REQUIRE_THROWS(
[&] {
Event<void()> ev(script, "VoidlessFunc");
}());

/* Function that returns void */
Event<void()> ev7(script, "VoidFunc");
Expand Down

0 comments on commit 821c5f6

Please sign in to comment.