Skip to content

Commit

Permalink
wasm2c: group imports for a given module into a struct type.
Browse files Browse the repository at this point in the history
Rather than given each import a magic name we can group imports into a
single struct and pass that struct into the init function.

This means that in the generated code all access to imported elements
now goes via the `g_imports` struct.  Note that this is not a pointer
but a copy of the passed in struct, to avoid adding any extra
indirection.

This can be considered one step towards module instancing.

It also avoids the need for name mangling since individual imports no
longer live in the global namespace.
  • Loading branch information
sbc100 committed Apr 29, 2022
1 parent d6dfa01 commit d8903a2
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 27 deletions.
64 changes: 55 additions & 9 deletions src/c-writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ class CWriter {
std::string DefineGlobalScopeName(const std::string&);
std::string DefineLocalScopeName(const std::string&);
std::string DefineStackVarName(Index, Type, std::string_view);
bool AlreadyImported(const std::string& name,
std::string_view module,
std::string_view mangled_field_name);

void Indent(int size = INDENT_SIZE);
void Dedent(int size = INDENT_SIZE);
Expand Down Expand Up @@ -467,10 +470,31 @@ std::string_view StripLeadingDollar(std::string_view name) {
return name;
}

bool CWriter::AlreadyImported(const std::string& name,
std::string_view module,
std::string_view mangled_field_name) {
std::string mangled = MangleName(module) + mangled_field_name;
if (global_syms_.count(mangled) != 0) {
global_sym_map_.insert(SymbolMap::value_type(name, mangled));
return true;
}
return false;
}

std::string CWriter::DefineImportName(const std::string& name,
std::string_view module,
std::string_view mangled_field_name) {
std::string mangled = MangleName(module) + mangled_field_name;
// Handle duplicate imports (i.e. the same thing being imported
// mulitple times).
if (global_syms_.count(mangled)) {
std::string mangled_base = mangled;
int counter = 1;
while (global_syms_.count(mangled)) {
mangled = mangled_base + "_" + std::to_string(counter);
counter++;
}
}
import_syms_.insert(name);
global_syms_.insert(mangled);
global_sym_map_.insert(SymbolMap::value_type(name, mangled));
Expand Down Expand Up @@ -578,7 +602,9 @@ void CWriter::Write(const GlobalName& name) {
void CWriter::Write(const ExternalPtr& name) {
bool is_import = import_syms_.count(name.name) != 0;
if (is_import) {
Write(GetGlobalName(name.name));
std::string full_name("g_imports.");
full_name += GetGlobalName(name.name);
Write(full_name);
} else {
Write(AddressOf(GetGlobalName(name.name)));
}
Expand All @@ -587,7 +613,9 @@ void CWriter::Write(const ExternalPtr& name) {
void CWriter::Write(const ExternalRef& name) {
bool is_import = import_syms_.count(name.name) != 0;
if (is_import) {
Write(Deref(GetGlobalName(name.name)));
std::string full_name("g_imports.");
full_name += GetGlobalName(name.name);
Write(Deref(full_name));
} else {
Write(GetGlobalName(name.name));
}
Expand Down Expand Up @@ -792,6 +820,9 @@ void CWriter::WriteSourceTop() {
Write(s_source_includes);
Write(Newline(), "#include \"", header_name_, "\"", Newline());
Write(s_source_declarations);
if (!module_->imports.empty()) {
Write("static ", module_prefix_, "_imports_t g_imports;", Newline(), Newline());
}
}

void CWriter::WriteMultivalueTypes() {
Expand Down Expand Up @@ -852,13 +883,16 @@ void CWriter::WriteImports() {
if (module_->imports.empty())
return;

Write(Newline());

Write("typedef struct ", module_prefix_, "_imports_t {", Newline());
// TODO(binji): Write imports ordered by type.
for (const Import* import : module_->imports) {
Write("/* import: '", import->module_name, "' '", import->field_name,
"' */", Newline());
Write("extern ");
/*
if (AlreadyImported(import->name, import->module_name, MangleName(import->field_name))) {
continue;
}
*/
Write(" /* import: '", import->module_name, "' '", import->field_name,
"' */", Newline(), " ");
switch (import->kind()) {
case ExternalKind::Func: {
const Func& func = cast<FuncImport>(import)->func;
Expand Down Expand Up @@ -897,6 +931,8 @@ void CWriter::WriteImports() {

Write(Newline());
}
Write("} ", module_prefix_, "_imports_t;", Newline());
Write(Newline());
}

void CWriter::WriteFuncDeclarations() {
Expand Down Expand Up @@ -1198,7 +1234,12 @@ void CWriter::WriteExports(WriteExportsKind kind) {
}

void CWriter::WriteInit() {
Write(Newline(), "void ", module_prefix_, "_init(void) ", OpenBrace());
if (module_->imports.empty()) {
Write(Newline(), "void ", module_prefix_, "_init(void) ", OpenBrace());
} else {
Write(Newline(), "void ", module_prefix_, "_init(", module_prefix_, "_imports_t* imports) ", OpenBrace());
Write("g_imports = *imports;", Newline());
}
Write("init_func_types();", Newline());
Write("init_globals();", Newline());
Write("init_memory();", Newline());
Expand Down Expand Up @@ -1449,6 +1490,7 @@ void CWriter::Write(const ExprList& exprs) {
Write(StackVar(num_params - 1, func.GetResultType(0)), " = ");
}


Write(GlobalVar(var), "(");
for (Index i = 0; i < num_params; ++i) {
if (i != 0) {
Expand Down Expand Up @@ -2379,7 +2421,11 @@ void CWriter::WriteCHeader() {
Write(s_header_top);
WriteMultivalueTypes();
WriteImports();
Write("void ", module_prefix_, "_init(void);", Newline());
if (module_->imports.empty()) {
Write("void ", module_prefix_, "_init();", Newline());
} else {
Write("void ", module_prefix_, "_init(", module_prefix_, "_imports_t* imports);", Newline());
}
Write("void ", module_prefix_, "_free(void);", Newline());
WriteExports(WriteExportsKind::Declarations);
Write(s_header_bottom);
Expand Down
2 changes: 1 addition & 1 deletion wasm2c/examples/fac/fac.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ typedef double f64;
extern "C" {
#endif

void Z_fac_init(void);
void Z_fac_init();
void Z_fac_free(void);

/* export: 'fac' */
Expand Down
37 changes: 20 additions & 17 deletions wasm2c/examples/rot13/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,38 @@

#include "rot13.h"

/* Define the imports as declared in rot13.h. */
wasm_rt_memory_t (*Z_hostZ_mem);
u32 (*Z_hostZ_fill_buf)(u32, u32);
void (*Z_hostZ_buf_done)(u32, u32);

/* Define the implementations of the imports. */
static wasm_rt_memory_t s_memory;
static u32 fill_buf(u32 ptr, u32 size);
static void buf_done(u32 ptr, u32 size);

/* The string that is currently being processed. This needs to be static
* because the buffer is filled in the callback. */
/*
* Provide the imports object expected by the module: "host.mem",
* "host.fill_buf" and "host.buf_done". Their mangled names are `Z_hostZ_mem`,
* `Z_hostZ_fill_buf` and `Z_hostZ_buf_done`.
*/
static Z_rot13_imports_t imports = {
.Z_hostZ_mem = &s_memory,
.Z_hostZ_fill_buf = &fill_buf,
.Z_hostZ_buf_done = &buf_done,
};

/*
* The string that is currently being processed. This needs to be static
* because the buffer is filled in the callback.
*/
static const char* s_input;

int main(int argc, char** argv) {
/* Initialize the Wasm runtime. */
wasm_rt_init();

/* Initialize the rot13 module. */
Z_rot13_init();
Z_rot13_init(&imports);

/* Allocate 1 page of wasm memory (64KiB). */
wasm_rt_allocate_memory(&s_memory, 1, 1);

/* Provide the imports expected by the module: "host.mem", "host.fill_buf"
* and "host.buf_done". Their mangled names are `Z_hostZ_mem`,
* `Z_hostZ_fill_buf` and `Z_hostZ_buf_done`. */
Z_hostZ_mem = &s_memory;
Z_hostZ_fill_buf = &fill_buf;
Z_hostZ_buf_done = &buf_done;

/* Call `rot13` on each argument, using the mangled name. */
while (argc > 1) {
/* Move to next arg. Do this first, so the program name is skipped. */
Expand All @@ -68,7 +69,8 @@ int main(int argc, char** argv) {
return 0;
}

/* Fill the wasm buffer with the input to be rot13'd.
/*
* Fill the wasm buffer with the input to be rot13'd.
*
* params:
* ptr: The wasm memory address of the buffer to fill data.
Expand All @@ -86,7 +88,8 @@ u32 fill_buf(u32 ptr, u32 size) {
return size;
}

/* Called when the wasm buffer has been rot13'd.
/*
* Called when the wasm buffer has been rot13'd.
*
* params:
* ptr: The wasm memory address of the buffer.
Expand Down

0 comments on commit d8903a2

Please sign in to comment.