Skip to content

Commit

Permalink
wasm2c: support for module instancing (#1814)
Browse files Browse the repository at this point in the history
Co-authored-by: Angela Montemayor <amontema@cs.stanford.edu>
  • Loading branch information
yhdengh and angelamontemayor authored Sep 16, 2022
1 parent 31604f8 commit dd44ca9
Show file tree
Hide file tree
Showing 12 changed files with 949 additions and 268 deletions.
688 changes: 539 additions & 149 deletions src/c-writer.cc

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/template/wasm2c.declarations.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,5 @@ static float wasm_sqrtf(float x) {
}
return sqrtf(x);
}

static bool s_module_initialized = false;
1 change: 1 addition & 0 deletions src/template/wasm2c.includes.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <assert.h>
#include <math.h>
#include <string.h>
#if defined(_MSC_VER)
Expand Down
59 changes: 47 additions & 12 deletions test/run-spec-wasm2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ def __init__(self, spec_json, prefix, out_file, out_dir):
self.module_name_to_idx = {}
self.module_prefix_map = {}
self.unmangled_names = {}

def Write(self):
self._MaybeWriteDummyModule()
self._CacheModulePrefixes()

def Write(self):
self._WriteIncludes()
self.out_file.write(self.prefix)
self.out_file.write("\nvoid run_spec_tests(void) {\n\n")
Expand All @@ -145,6 +145,9 @@ def GetModulePrefix(self, idx_or_name=None):
def GetModulePrefixUnmangled(self, idx):
return self.unmangled_names[idx]

def GetModuleInstanceName(self, idx_or_name=None):
return self.GetModulePrefix() + '_instance'

def _CacheModulePrefixes(self):
idx = 0
for command in self.commands:
Expand Down Expand Up @@ -173,6 +176,29 @@ def _CacheModulePrefixes(self):
self.module_prefix_map[name_idx] = name
self.unmangled_names[name_idx] = command['as']

def _WriteModuleInitCall(self, command, uninstantiable):
header_filename = utils.ChangeExt(command['filename'], '.h')
with open(os.path.join(self.out_dir, header_filename), encoding='utf-8') as f:
imported_modules = set()
for line in f:
if 'import: ' in line:
line_split = line.split()
import_module_name = MangleName(line_split[2][1:-1])
imported_modules.add(import_module_name)

if uninstantiable:
self.out_file.write('ASSERT_TRAP(')

self.out_file.write('%s_instantiate(&%s_instance' % (self.GetModulePrefix(), self.GetModulePrefix()))
for imported_module in sorted(imported_modules):
self.out_file.write(', &%s_instance' % imported_module)
self.out_file.write(')')

if uninstantiable:
self.out_file.write(')')

self.out_file.write(';\n')

def _MaybeWriteDummyModule(self):
if len(self.GetModuleFilenames()) == 0:
# This test doesn't have any valid modules, so just use a dummy instead.
Expand Down Expand Up @@ -212,15 +238,19 @@ def _WriteCommand(self, command):

def _WriteModuleCommand(self, command):
self.module_idx += 1
self.out_file.write('%s_init();\n' % self.GetModulePrefix())
self.out_file.write('%s_init_module();\n' % self.GetModulePrefix())
self.out_file.write('%s_instance_t %s;\n' % (self.GetModulePrefix(), self.GetModuleInstanceName()))
self._WriteModuleInitCall(command, False)

def _WriteModuleCleanUps(self):
for idx in range(self.module_idx):
self.out_file.write("%s_free();\n" % self.GetModulePrefix(idx))
self.out_file.write("%s_free(&%s_instance);\n" % (self.GetModulePrefix(idx), self.GetModulePrefix(idx)))

def _WriteAssertUninstantiableCommand(self, command):
self.module_idx += 1
self.out_file.write('ASSERT_TRAP(%s_init());\n' % self.GetModulePrefix())
self.out_file.write('%s_init_module();\n' % self.GetModulePrefix())
self.out_file.write('%s_instance_t %s;\n' % (self.GetModulePrefix(), self.GetModuleInstanceName()))
self._WriteModuleInitCall(command, True)

def _WriteActionCommand(self, command):
self.out_file.write('%s;\n' % self._Action(command))
Expand Down Expand Up @@ -326,9 +356,14 @@ def _Action(self, command):
mangled_module_name = self.GetModulePrefix(action.get('module'))
field = mangled_module_name + MangleName(action['field'])
if type_ == 'invoke':
return '%s(%s)' % (field, self._ConstantList(action.get('args', [])))
args = self._ConstantList(action.get('args', []))
if len(args) == 0:
args = f'&{mangled_module_name}_instance'
else:
args = f'&{mangled_module_name}_instance, {args}'
return '%s(%s)' % (field, args)
elif type_ == 'get':
return '*%s' % field
return '*%s(%s)' % (field, '&' + mangled_module_name + '_instance')
else:
raise Error('Unexpected action type: %s' % type_)

Expand Down Expand Up @@ -460,11 +495,6 @@ def main(args):

output = io.StringIO()
cwriter = CWriter(spec_json, prefix, output, out_dir)
cwriter.Write()

main_filename = utils.ChangeExt(json_file_path, '-main.c')
with open(main_filename, 'w') as out_main_file:
out_main_file.write(output.getvalue())

o_filenames = []
includes = '-I%s' % options.wasmrt_dir
Expand All @@ -477,6 +507,11 @@ def main(args):
if options.compile:
o_filenames.append(Compile(cc, c_filename, out_dir, includes))

cwriter.Write()
main_filename = utils.ChangeExt(json_file_path, '-main.c')
with open(main_filename, 'w') as out_main_file:
out_main_file.write(output.getvalue())

if options.compile:
# Compile wasm-rt-impl.
wasm_rt_impl_c = os.path.join(options.wasmrt_dir, 'wasm-rt-impl.c')
Expand Down
75 changes: 49 additions & 26 deletions test/spec-wasm2c-prefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,59 +213,82 @@ static bool is_arithmetic_nan_f64(u64 x) {
return (x & 0x7ff8000000000000) == 0x7ff8000000000000;
}

typedef struct Z_spectest_instance_t {
wasm_rt_table_t spectest_table;
wasm_rt_memory_t spectest_memory;
uint32_t spectest_global_i32;
uint64_t spectest_global_i64;
float spectest_global_f32;
double spectest_global_f64;
} Z_spectest_instance_t;

static Z_spectest_instance_t Z_spectest_instance;

/*
* spectest implementations
*/
static void spectest_print(void) {
void Z_spectestZ_print(Z_spectest_instance_t* instance) {
printf("spectest.print()\n");
}

static void spectest_print_i32(uint32_t i) {
void Z_spectestZ_print_i32(Z_spectest_instance_t* instance, uint32_t i) {
printf("spectest.print_i32(%d)\n", i);
}

static void spectest_print_f32(float f) {
void Z_spectestZ_print_f32(Z_spectest_instance_t* instance, float f) {
printf("spectest.print_f32(%g)\n", f);
}

static void spectest_print_i32_f32(uint32_t i, float f) {
void Z_spectestZ_print_i32_f32(Z_spectest_instance_t* instance,
uint32_t i,
float f) {
printf("spectest.print_i32_f32(%d %g)\n", i, f);
}

static void spectest_print_f64(double d) {
void Z_spectestZ_print_f64(Z_spectest_instance_t* instance, double d) {
printf("spectest.print_f64(%g)\n", d);
}

static void spectest_print_f64_f64(double d1, double d2) {
void Z_spectestZ_print_f64_f64(Z_spectest_instance_t* instance,
double d1,
double d2) {
printf("spectest.print_f64_f64(%g %g)\n", d1, d2);
}

static wasm_rt_table_t spectest_table;
static wasm_rt_memory_t spectest_memory;
static uint32_t spectest_global_i32 = 666;
static uint64_t spectest_global_i64 = 666l;

void (*Z_spectestZ_print)(void) = &spectest_print;
void (*Z_spectestZ_print_i32)(uint32_t) = &spectest_print_i32;
void (*Z_spectestZ_print_f32)(float) = &spectest_print_f32;
void (*Z_spectestZ_print_i32_f32)(uint32_t, float) = &spectest_print_i32_f32;
void (*Z_spectestZ_print_f64)(double) = &spectest_print_f64;
void (*Z_spectestZ_print_f64_f64)(double, double) = &spectest_print_f64_f64;
wasm_rt_table_t* Z_spectestZ_table = &spectest_table;
wasm_rt_memory_t* Z_spectestZ_memory = &spectest_memory;
uint32_t* Z_spectestZ_global_i32 = &spectest_global_i32;
uint64_t* Z_spectestZ_global_i64 = &spectest_global_i64;

static void init_spectest_module(void) {
wasm_rt_allocate_memory(&spectest_memory, 1, 2);
wasm_rt_allocate_table(&spectest_table, 10, 20);
wasm_rt_table_t* Z_spectestZ_table(Z_spectest_instance_t* instance) {
return &instance->spectest_table;
}

wasm_rt_memory_t* Z_spectestZ_memory(Z_spectest_instance_t* instance) {
return &instance->spectest_memory;
}

uint32_t* Z_spectestZ_global_i32(Z_spectest_instance_t* instance) {
return &instance->spectest_global_i32;
}

uint64_t* Z_spectestZ_global_i64(Z_spectest_instance_t* instance) {
return &instance->spectest_global_i64;
}

float* Z_spectestZ_global_f32(Z_spectest_instance_t* instance) {
return &instance->spectest_global_f32;
}

double* Z_spectestZ_global_f64(Z_spectest_instance_t* instance) {
return &instance->spectest_global_f64;
}

static void init_spectest_module(Z_spectest_instance_t* instance) {
instance->spectest_global_i32 = 666;
instance->spectest_global_i64 = 666l;
wasm_rt_allocate_memory(&instance->spectest_memory, 1, 2);
wasm_rt_allocate_table(&instance->spectest_table, 10, 20);
}

int main(int argc, char** argv) {
wasm_rt_init();
init_spectest_module();
init_spectest_module(&Z_spectest_instance);
run_spec_tests();
printf("%u/%u tests passed.\n", g_tests_passed, g_tests_run);
wasm_rt_free();
Expand Down
Loading

0 comments on commit dd44ca9

Please sign in to comment.