summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/fuzz_opt.py38
-rw-r--r--src/tools/wasm2c-wrapper.h45
2 files changed, 67 insertions, 16 deletions
diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py
index 16a09eeb6..bc3b9fd5d 100755
--- a/scripts/fuzz_opt.py
+++ b/scripts/fuzz_opt.py
@@ -329,6 +329,9 @@ class CompareVMs(TestCaseHandler):
wabt_bin = shared.which('wasm2c')
wabt_root = os.path.dirname(os.path.dirname(wabt_bin))
self.wasm2c_dir = os.path.join(wabt_root, 'wasm2c')
+ if not os.path.isdir(self.wasm2c_dir):
+ print('wabt found, but not wasm2c support dir')
+ self.wasm2c_dir = None
except Exception as e:
print('warning: no wabt found:', e)
self.wasm2c_dir = None
@@ -358,12 +361,45 @@ class CompareVMs(TestCaseHandler):
# C won't trap on OOB, and NaNs can differ from wasm VMs
return not OOB and not NANS
+ class Wasm2C2Wasm(Wasm2C):
+ name = 'wasm2c2wasm'
+
+ def __init__(self):
+ super(Wasm2C2Wasm, self).__init__()
+
+ self.has_emcc = shared.which('emcc') is not None
+
+ def run(self, wasm):
+ run([in_bin('wasm-opt'), wasm, '--emit-wasm2c-wrapper=main.c'] + FEATURE_OPTS)
+ run(['wasm2c', wasm, '-o', 'wasm.c'])
+ compile_cmd = ['emcc', 'main.c', 'wasm.c', os.path.join(self.wasm2c_dir, 'wasm-rt-impl.c'), '-I' + self.wasm2c_dir, '-lm']
+ if random.random() < 0.5:
+ compile_cmd += ['-O' + str(random.randint(1, 3))]
+ elif random.random() < 0.5:
+ if random.random() < 0.5:
+ compile_cmd += ['-Os']
+ else:
+ compile_cmd += ['-Oz']
+ run(compile_cmd)
+ return run_vm(['d8', 'a.out.js'])
+
+ def can_run(self):
+ return super(Wasm2C2Wasm, self).can_run() and self.has_emcc
+
+ def can_compare_to_self(self):
+ return True
+
+ def can_compare_to_others(self):
+ # NaNs can differ from wasm VMs
+ return not NANS
+
self.vms = [
VM('binaryen interpreter', byn_run, can_run=yes, can_compare_to_self=yes, can_compare_to_others=yes),
# with nans, VM differences can confuse us, so only very simple VMs can compare to themselves after opts in that case.
# if not legalized, the JS will fail immediately, so no point to compare to others
VM('d8', v8_run, can_run=yes, can_compare_to_self=if_no_nans, can_compare_to_others=if_legal_and_no_nans),
- Wasm2C()
+ Wasm2C(),
+ Wasm2C2Wasm(),
]
def handle_pair(self, input, before_wasm, after_wasm, opts):
diff --git a/src/tools/wasm2c-wrapper.h b/src/tools/wasm2c-wrapper.h
index 684bd52f7..aa36dd782 100644
--- a/src/tools/wasm2c-wrapper.h
+++ b/src/tools/wasm2c-wrapper.h
@@ -29,6 +29,7 @@ static std::string generateWasm2CWrapper(Module& wasm) {
// First, emit implementations of the wasm's imports so that the wasm2c code
// can call them. The names use wasm2c's name mangling.
std::string ret = R"(
+#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
@@ -41,7 +42,7 @@ void _Z_fuzzingZ2DsupportZ_logZ2Di32Z_vi(u32 x) {
void (*Z_fuzzingZ2DsupportZ_logZ2Di32Z_vi)(u32) = _Z_fuzzingZ2DsupportZ_logZ2Di32Z_vi;
void _Z_fuzzingZ2DsupportZ_logZ2Di64Z_vj(u64 x) {
- printf("[LoggingExternalInterface logging %ld]\n", (long)x);
+ printf("[LoggingExternalInterface logging %" PRId64 "]\n", (int64_t)x);
}
void (*Z_fuzzingZ2DsupportZ_logZ2Di64Z_vj)(u64) = _Z_fuzzingZ2DsupportZ_logZ2Di64Z_vj;
@@ -79,28 +80,41 @@ u32 (*Z_envZ_getTempRet0Z_iv)(void) = _Z_envZ_getTempRet0Z_iv;
int main(int argc, char** argv) {
init();
+ // We go through each export and call it, in turn. Note that we use a loop
+ // so we can do all this with a single setjmp. A setjmp is needed to handle
+ // wasm traps, and emitting a single one helps compilation speed into wasm as
+ // compile times are O(size * num_setjmps).
+ for (size_t curr = 0;; curr++) {
+ // Always call the hang limit initializer before each export.
+ (*Z_hangLimitInitializerZ_vv)();
+
+ // Prepare to call the export, so we can catch traps.
+ if (setjmp(g_jmp_buf) != 0) {
+ puts("exception!");
+ } else {
+ // Call the proper export.
+ switch(curr) {
)";
// For each export in the wasm, emit code to call it and log its result,
// similar to the other wrappers.
+ size_t exportIndex = 0;
+
for (auto& exp : wasm.exports) {
if (exp->kind != ExternalKind::Function) {
continue;
}
- // Always call the hang limit initializer before each export.
- ret += " (*Z_hangLimitInitializerZ_vv)();\n";
+ ret += " case " + std::to_string(exportIndex++) + ":\n";
auto* func = wasm.getFunction(exp->value);
- // Emit a setjmp so that we can handle traps from the compiled wasm.
- ret +=
- std::string(" puts(\"[fuzz-exec] calling ") + exp->name.str + "\");\n";
- ret += " if (setjmp(g_jmp_buf) == 0) {\n";
+ ret += std::string(" puts(\"[fuzz-exec] calling ") +
+ exp->name.str + "\");\n";
auto result = func->sig.results;
// Emit the call itself.
- ret += " ";
+ ret += " ";
if (result != Type::none) {
ret += std::string("printf(\"[fuzz-exec] note result: ") + exp->name.str +
" => ";
@@ -109,7 +123,7 @@ int main(int argc, char** argv) {
ret += "%d\\n\", ";
break;
case Type::i64:
- ret += "%ld\\n\", (long)";
+ ret += "%\" PRId64 \"\\n\", (int64_t)";
break;
case Type::f32:
ret += "%.17e\\n\", ";
@@ -168,14 +182,15 @@ int main(int argc, char** argv) {
}
ret += ");\n";
- // Handle a longjmp which indicates a trap happened.
- ret += " } else {\n";
- ret += " puts(\"exception!\");\n";
- ret += " }\n";
+ // Break from the big switch.
+ ret += " break;\n";
}
- ret += R"(
-
+ ret += R"( default:
+ return 0; // All done.
+ }
+ }
+ }
return 0;
}
)";