2026-06-12 11:40:26 +00:00

74 lines
2.4 KiB
C++

// WASM-PROPOSAL Phase 0 — unit module stub.
//
// Stands in for a generated UCE unit: compiled with -fPIC and linked with
// wasm-ld -shared into a PIC module carrying a dylink.0 section. Defines no
// allocator and links no libc — operator new/delete, memcpy, and the core
// API all arrive as imports resolved by the loader against the core module
// (§5.4 unit module contract).
//
// Exercises, in one render call:
// - unit-local data segment with relocation (__memory_base placement)
// - GOT.mem read+write of a core-defined global (core_counter)
// - C++ containers (std::string/std::map) on the core's heap
// - heap object created in core, mutated and read from the unit
// - function pointer from unit through core and back (shared table)
// - std::function/lambda handed across the module boundary
#include <string>
#include <functional>
#include <map>
extern "C" {
void uce_print(const char* s, size_t len);
extern int core_counter;
std::string* core_make_string(const char* s);
void core_append_string(std::string* str, const char* s);
void core_invoke_callback(void (*cb)(int), int arg);
void core_invoke_function(std::function<int(int)>* f, int arg);
}
static const char* unit_static_message = "unit-data-segment-ok";
static int unit_state = 41;
static void my_callback(int x)
{
std::string s = "[cb:" + std::to_string(x + unit_state) + "]";
uce_print(s.data(), s.size());
}
extern "C" void uce_unit_render()
{
std::string out = "hello from unit; ";
out += unit_static_message;
out += "; counter=" + std::to_string(core_counter);
uce_print(out.data(), out.size());
std::map<std::string, int> m;
m["a"] = 1;
m["b"] = 2;
int sum = 0;
for(auto& kv : m)
sum += kv.second;
std::string s2 = "; mapsum=" + std::to_string(sum);
uce_print(s2.data(), s2.size());
std::string* cs = core_make_string("; core-string");
core_append_string(cs, "+unit");
uce_print(cs->data(), cs->size());
delete cs;
core_invoke_callback(my_callback, 1);
// address of a core-defined function taken in the unit → GOT.func import;
// the loader must ensure the core function has a funcref table entry.
// volatile so the optimizer cannot fold it back into a direct call.
void (*volatile print_ptr)(const char*, size_t) = uce_print;
print_ptr("[got-func-ok]", 13);
auto* fn = new std::function<int(int)>([](int v) { return(v * 3); });
core_invoke_function(fn, 14);
delete fn;
core_counter++;
}