Skip to content

Commit

Permalink
Add distinction between initialization-only, client- and server-only …
Browse files Browse the repository at this point in the history
…dynamic calls

Also, make void vmcall returns into a simple boolean
  • Loading branch information
fwsGonzo committed May 15, 2024
1 parent 902f671 commit 6d2afa2
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 21 deletions.
6 changes: 4 additions & 2 deletions engine/src/script/event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,16 @@ template <typename... Args> inline auto Event<F, Usage>::call(Args&&... args)
{
auto& script = this->script();
if (auto res = script.call(address(), std::forward<Args>(args)...)) {
if constexpr (std::is_same_v<void, Ret> || std::is_same_v<Script::gaddr_t, Ret>)
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 std::optional<Script::sgaddr_t>{std::nullopt};
return false;
else
return std::optional<Ret>{std::nullopt};
}
55 changes: 44 additions & 11 deletions engine/src/script/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ void Script::machine_setup()
this->add_shared_memory();

// Figure out the local indices based on dynamic call table
this->resolve_dynamic_calls();
// We are pretending to be initializing the client-side
this->resolve_dynamic_calls(true, true, false);
}

void Script::could_not_find(std::string_view func)
Expand Down Expand Up @@ -405,7 +406,7 @@ void Script::dynamic_call_error(uint32_t idx, const std::exception& e)
throw;
}

void Script::resolve_dynamic_calls()
void Script::resolve_dynamic_calls(bool initialization, bool client_side, bool verbose)
{
this->m_g_dyncall_table = machine().address_of("dyncall_table");
if (m_g_dyncall_table == 0x0)
Expand All @@ -420,17 +421,44 @@ void Script::resolve_dynamic_calls()
// Reserve space for host-side dynamic call handlers
this->m_dyncall_array.reserve(entries);
this->m_dyncall_array.clear();
if constexpr (WARN_ON_UNIMPLEMENTED_DYNCALL) {
strf::to(stdout)(
"Resolving dynamic calls for '", name(), "' with ", entries, " entries\n");
}
unsigned unimplemented = 0;

// Copy whole table into vector
std::vector<DyncallDesc> table (entries);
machine().copy_from_guest(table.data(), g_table, entries * sizeof(DyncallDesc));

for (unsigned i = 0; i < entries; i++) {
auto& entry = table.at(i);
if (entry.initialization_only && !initialization) {
if (verbose) strf::to(stdout)(
"Skipping initialization-only dynamic call '",
this->machine().memory.memstring(entry.strname), "'\n");
this->m_dyncall_array.push_back(
[] (auto&) {
throw std::runtime_error("Initialization-only dynamic call triggered");
});
continue;
}
if (entry.client_side_only && !client_side) {
if (verbose) strf::to(stdout)(
"Skipping client-side-only dynamic call '",
machine().memory.memstring(entry.strname), "'\n");
this->m_dyncall_array.push_back(
[] (auto&) {
throw std::runtime_error("Clientside-only dynamic call triggered");
});
continue;
}
if (entry.server_side_only && client_side) {
if (verbose) strf::to(stdout)(
"Skipping server-side-only dynamic call '",
machine().memory.memstring(entry.strname), "'\n");
this->m_dyncall_array.push_back(
[] (auto&) {
throw std::runtime_error("Serverside-only dynamic call triggered");
});
continue;
}

auto it = m_dynamic_functions.find(entry.hash);
if (LIKELY(it != m_dynamic_functions.end()))
Expand All @@ -439,18 +467,23 @@ void Script::resolve_dynamic_calls()
} else {
this->m_dyncall_array.push_back(
[] (auto&) {
throw std::runtime_error("Unimplemented-trap");
throw std::runtime_error("Unimplemented dynamic call triggered");
});
if constexpr (WARN_ON_UNIMPLEMENTED_DYNCALL) {
if (verbose) {
const std::string name = machine().memory.memstring(entry.strname);
strf::to(stdout)(
"WARNING: Unimplemented dynamic function '", name, "' with hash ", strf::hex(entry.hash), " and program table index ",
m_dyncall_array.size(), "\n");
strf::to(stderr)(
"WARNING: Unimplemented dynamic function '", name, "' with hash ",
strf::hex(entry.hash), " and program table index ", i, " (total: ",
m_dyncall_array.size(), ")\n");
}
unimplemented++;
}
}
if (m_dyncall_array.size() != entries)
throw std::runtime_error("Mismatching number of dynamic call array entries");
strf::to(stdout)(
"* Resolved dynamic calls for '", name(), "' with ", entries, " entries, ",
unimplemented, " unimplemented\n");
}

void Script::set_global_setting(std::string_view setting, gaddr_t value)
Expand Down
5 changes: 4 additions & 1 deletion engine/src/script/script.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ struct Script
void max_depth_exceeded(gaddr_t);
void machine_setup();
void machine_remote_setup();
void resolve_dynamic_calls();
void resolve_dynamic_calls(bool initialization, bool client_side, bool verbose);
void dynamic_call_error(uint32_t idx, const std::exception& e);
static long finish_benchmark(std::vector<long>&);

Expand Down Expand Up @@ -311,6 +311,9 @@ struct Script
uint32_t hash;
uint32_t resv;
uint32_t strname;
bool initialization_only;
bool client_side_only;
bool server_side_only;
};
std::vector<ghandler_t> m_dyncall_array;
gaddr_t m_g_dyncall_table = 0x0;
Expand Down
13 changes: 13 additions & 0 deletions programs/dynamic_calls.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
"typedef void (*timer_callback) (int, void*)",
"typedef void (*gui_callback) (unsigned, void*)"
],
"initialization": [
],
"clientside": [
"GUI::find",
"GUI::window",
"GUI::widget",
"GUI::button",
"GUI::label",
"GUI::widget_set_pos",
"GUI::widget_callback"
],
"serverside": [
],
"Timer::stop": "void sys_timer_stop (int)",
"Timer::periodic": "int sys_timer_periodic (float, float, timer_callback, void*, size_t)",
"Debug::breakpoint": "void sys_breakpoint (uint16_t, const char*)",
Expand Down
32 changes: 31 additions & 1 deletion programs/dyncalls/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ def emit_inline_assembly(header, asmdef, index, fargs):
with open(args.jsonfile) as f:
j = json.load(f)

# List of client-side only dyncalls
client_side = []
if "clientside" in j:
for key in j["clientside"]:
client_side.append(key)

# List of server-side only dyncalls
server_side = []
if "serverside" in j:
for key in j["serverside"]:
server_side.append(key)

# List of initialization-only dyncalls
initialization = []
if "initialization" in j:
for key in j["initialization"]:
initialization.append(key)

header = """
#pragma once
#include <stddef.h>
Expand All @@ -161,7 +179,9 @@ def emit_inline_assembly(header, asmdef, index, fargs):

# create dyncall prototypes and assembly
for key in j:
if key != "typedef":
if key == "typedef" or key == "clientside" or key == "serverside" or key == "initialization":
continue
else:
asmdef = j[key]
asmname = asmdef.split(' ')[1]

Expand All @@ -182,10 +202,20 @@ def emit_inline_assembly(header, asmdef, index, fargs):
if args.verbose:
print("Dynamic call: " + key + ", hash 0x" + crc + (" (inlined)" if inlined else ""))

# Each dynamic call has a table index where the name and hash is stored
dyncall += ' .long 0x' + crc + '\\n\\\n'
dyncall += ' .long ' + str(0) + '\\n\\\n'
dyncall += ' .long ' + asmname + '_str\\n\\\n'

# Flags (one byte each for client-side, server-side, initialization, and padding)
is_client_side = key in client_side
is_server_side = key in server_side
is_initialization = key in initialization
dyncall += ' .byte ' + str(int(is_initialization)) + '\\n\\\n'
dyncall += ' .byte ' + str(int(is_client_side)) + '\\n\\\n'
dyncall += ' .byte ' + str(int(is_server_side)) + '\\n\\\n'
dyncall += ' .byte 0\\n\\\n'

# These dynamic calls use the table indexed variant
# Each dynamic call has a table index where the name and hash is stored
# and at run-time this value is lazily resolved
Expand Down
11 changes: 5 additions & 6 deletions tests/events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ TEST_CASE("Simple events", "[Events]")
extern "C" void VoidFunc() {
}
extern "C" int FailingFunc() {
assert(0);
asm volatile("unimp");
__builtin_unreachable();
}
)M");
Expand Down Expand Up @@ -89,15 +90,13 @@ TEST_CASE("Simple events", "[Events]")

/* Function that doesn't exist */
Event<void()> ev6(script, "VoidlessFunc");
auto res6 = ev6.call();
REQUIRE(!res6.has_value());
REQUIRE(!ev6.call());

/* Function that returns void */
Event<void()> ev7(script, "VoidFunc");
REQUIRE(ev7.call().has_value());
REQUIRE(ev7.call());

/* Function that fails */
Event<void()> ev8(script, "FailingFunc");
auto res8 = ev8.call();
REQUIRE(!res8.has_value());
REQUIRE(!ev8.call());
}

0 comments on commit 6d2afa2

Please sign in to comment.