diff --git a/source/m3_env.c b/source/m3_env.c index f8c81ec..75fc86f 100644 --- a/source/m3_env.c +++ b/source/m3_env.c @@ -368,6 +368,30 @@ _ (ReadLEB_u32 (& functionIndex, & bytes, end)); _catch: return result; } +M3Result InitStartFunc (IM3Module io_module) +{ + M3Result result = c_m3Err_none; + + if (io_module->startFunction >= 0) { + if (io_module->startFunction >= io_module->numFunctions) { + return "start function index out of bounds"; + } + IM3Function function = &io_module->functions [io_module->startFunction]; + if (not function) { + return "start function not found"; + } + + if (not function->compiled) + { +_ (Compile_Function (function)); + if (result) + function = NULL; + } +_ (m3_Call(function)); + } + + _catch: return result; +} // TODO: deal with main + side-modules loading efforcement M3Result m3_LoadModule (IM3Runtime io_runtime, IM3Module io_module) @@ -390,6 +414,9 @@ _ (InitElements (io_module)); io_module->runtime = io_runtime; io_module->next = io_runtime->modules; io_runtime->modules = io_module; + + // Functions expect module to be linked to a runtime, so we call start here +_ (InitStartFunc (io_module)); } else _throw (c_m3Err_moduleAlreadyLinked); diff --git a/source/m3_env.h b/source/m3_env.h index f6256b5..4b9322e 100644 --- a/source/m3_env.h +++ b/source/m3_env.h @@ -145,6 +145,8 @@ typedef struct M3Module // TODO add env owner? also discriminate u32 numFunctions; M3Function * functions; + i32 startFunction; + u32 numDataSegments; M3DataSegment * dataSegments; diff --git a/source/m3_parse.c b/source/m3_parse.c index b8abbf9..e620cb9 100644 --- a/source/m3_parse.c +++ b/source/m3_parse.c @@ -232,6 +232,17 @@ _ (ReadLEB_u32 (& index, & i_bytes, i_end)); } +M3Result ParseSection_Start (IM3Module io_module, bytes_t i_bytes, cbytes_t i_end) +{ + M3Result result = c_m3Err_none; + + u32 startFunc; +_ (ReadLEB_u32 (& startFunc, & i_bytes, i_end)); m3log (parse, "** Start Function: %d", startFunc); + + io_module->startFunction = startFunc; + + _catch: return result; +} M3Result Parse_InitExpr (M3Module * io_module, bytes_t * io_bytes, cbytes_t i_end) { @@ -492,7 +503,7 @@ M3Result ParseModuleSection (M3Module * o_module, u8 i_sectionType, bytes_t i_ ParseSection_Memory, // 5 ParseSection_Global, // 6 ParseSection_Export, // 7 - NULL, // 8: start + ParseSection_Start, // 8 ParseSection_Element, // 9 ParseSection_Code, // 10 ParseSection_Data // 11 @@ -527,6 +538,7 @@ _ (m3Alloc (& module, M3Module, 1)); // Module_Init (module); module->name = ".unnamed"; m3log (parse, "load module: %d bytes", i_numBytes); + module->startFunction = -1; const u8 * pos = i_bytes; const u8 * end = pos + i_numBytes; diff --git a/test/run-spec-test.py b/test/run-spec-test.py index 76ee68f..01495d2 100755 --- a/test/run-spec-test.py +++ b/test/run-spec-test.py @@ -35,6 +35,7 @@ parser.add_argument("--all", action="store_true") parser.add_argument("--show-logs", action="store_true") parser.add_argument("--skip-crashes", action="store_true") parser.add_argument("--format", choices=["raw", "hex", "fp"], default="fp") +#parser.add_argument("--wasm-opt", metavar="") parser.add_argument("-v", "--verbose", action="store_true") parser.add_argument("-s", "--silent", action="store_true") parser.add_argument("file", nargs='*') @@ -87,7 +88,7 @@ def fatal(msg): sys.exit(1) def run(cmd): - return subprocess.check_output(cmd, shell=True) + return subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) def filename(p): _, fn = os.path.split(p) @@ -171,6 +172,17 @@ def specTestsPreprocess(): json_fn = os.path.join(coreDir, os.path.splitext(fn)[0]) + ".json" run(f"wast2json --debug-names -o {json_fn} {wast_fn}") + ''' + if args.wasm_opt: + wasmFiles = glob.glob(os.path.join(coreDir, "*.wasm")) + wasmFiles.sort() + for fn in wasmFiles: + try: + run(f"wasm-opt {args.wasm_opt} {fn} -o {fn}") + except Exception: + pass + ''' + # # Wasm3 REPL # @@ -206,13 +218,15 @@ class Wasm3(): self.t.daemon = True self.t.start() + output = self._read_until("wasm3> ", False) + def invoke(self, cmd): cmd = " ".join(map(str, cmd)) + "\n" self._flush_input() self._write(cmd) return self._read_until("\nwasm3> ") - def _read_until(self, token): + def _read_until(self, token, autorestart=True): buff = "" tout = time.time() + self.timeout error = None @@ -233,7 +247,8 @@ class Wasm3(): error = "Timeout" # Crash => restart - self.load(self.loaded) + if autorestart: + self.load(self.loaded) raise Exception(error) def _write(self, data): @@ -247,7 +262,7 @@ class Wasm3(): def _flush_input(self): while not self.q.empty(): - self.q.get_nowait() + self.q.get() def terminate(self): self.p.stdin.close() @@ -305,7 +320,7 @@ def runInvoke(test): test_id = f"{test.source} {test.wasm} {test.cmd[0]}({', '.join(test.cmd[1:])})" if test_id in blacklist: - warning(f"Skipping {test_id}") + warning(f"Skipping {test_id} (blacklisted)") stats.skipped += 1 return @@ -454,11 +469,11 @@ else: "memory_redundancy", "float_memory", "memory", "memory_trap", "memory_grow", - "switch", "if", - "nop" + "switch", "if", + "nop", + "start", #--- TODO --- - #"start", #"loop", "labels", "block", "br", "br_if", "br_table", "return", "unwind", #"float_exprs", #"unreachable", @@ -483,8 +498,14 @@ for fn in jsonFiles: if test.type == "module": wast_module = cmd["filename"] - fn = os.path.relpath(os.path.join(coreDir, wast_module), curDir) - wasm3.load(fn) + if args.verbose: + print(f"Loading {wast_module}") + + try: + fn = os.path.relpath(os.path.join(coreDir, wast_module), curDir) + wasm3.load(fn) + except Exception: + pass elif ( test.type == "action" or test.type == "assert_return" or @@ -510,7 +531,7 @@ for fn in jsonFiles: test.expected_trap = cmd["text"] else: stats.skipped += 1 - warning(f"Skipped {test.source} {test.type}") + warning(f"Skipped {test.source} ({test.type} not implemented)") continue test.action = dotdict(cmd["action"]) @@ -532,6 +553,7 @@ for fn in jsonFiles: test.type == "assert_unlinkable" or test.type == "assert_uninstantiable"): stats.skipped += 1 + #warning(f"Skipped {test.source} ({test.type} not implemented)") else: fatal(f"Unknown command '{test}'")