// 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 #include #include 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* 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 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 v) { return(v * 3); }); core_invoke_function(fn, 14); delete fn; core_counter++; }