Implement start function. Fix #10

extensions
Volodymyr Shymanskyy 5 years ago
parent c03e75afb0
commit bc25ef6d16

@ -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);

@ -145,6 +145,8 @@ typedef struct M3Module // TODO add env owner? also discriminate
u32 numFunctions;
M3Function * functions;
i32 startFunction;
u32 numDataSegments;
M3DataSegment * dataSegments;

@ -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;

@ -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="<opt flags>")
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}'")

Loading…
Cancel
Save