summaryrefslogtreecommitdiff
path: root/src/tools/execution-results.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/execution-results.h')
-rw-r--r--src/tools/execution-results.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h
new file mode 100644
index 000000000..163e70abb
--- /dev/null
+++ b/src/tools/execution-results.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Shared execution result checking code
+//
+
+#include "wasm.h"
+#include "shell-interface.h"
+
+namespace wasm {
+
+static bool areBitwiseEqual(Literal a, Literal b) {
+ if (a == b) return true;
+ // accept equal nans if equal in all bits
+ if (a.type != b.type) return false;
+ if (a.type == f32) {
+ return a.reinterpreti32() == b.reinterpreti32();
+ } else if (a.type == f64) {
+ return a.reinterpreti64() == b.reinterpreti64();
+ }
+ return false;
+}
+
+// gets execution results from a wasm module. this is useful for fuzzing
+//
+// we can only get results when there are no imports. we then call each method
+// that has a result, with some values
+struct ExecutionResults {
+ std::map<Name, Literal> results;
+
+ // get results of execution
+ void get(Module& wasm) {
+ if (wasm.imports.size() > 0) {
+ std::cout << "[fuzz-exec] imports, so quitting\n";
+ return;
+ }
+ for (auto& func : wasm.functions) {
+ if (func->result != none) {
+ // this has a result
+ results[func->name] = run(func.get(), wasm);
+ std::cout << "[fuzz-exec] note result: " << func->name.str << " => " << results[func->name] << '\n';
+ } else {
+ // no result, run it anyhow (it might modify memory etc.)
+ run(func.get(), wasm);
+ std::cout << "[fuzz-exec] no result for void func: " << func->name.str << '\n';
+ }
+ }
+ std::cout << "[fuzz-exec] " << results.size() << " results noted\n";
+ }
+
+ // get current results and check them against previous ones
+ void check(Module& wasm) {
+ ExecutionResults optimizedResults;
+ optimizedResults.get(wasm);
+ if (optimizedResults != *this) {
+ std::cout << "[fuzz-exec] optimization passes changed execution results";
+ abort();
+ }
+ std::cout << "[fuzz-exec] " << results.size() << " results match\n";
+ }
+
+ bool operator==(ExecutionResults& other) {
+ for (auto& iter : results) {
+ auto name = iter.first;
+ if (other.results.find(name) != other.results.end()) {
+ std::cout << "[fuzz-exec] comparing " << name << '\n';
+ if (!areBitwiseEqual(results[name], other.results[name])) {
+ std::cout << "not identical!\n";
+ abort();
+ }
+ }
+ }
+ return true;
+ }
+
+ bool operator!=(ExecutionResults& other) {
+ return !((*this) == other);
+ }
+
+ Literal run(Function* func, Module& wasm) {
+ ShellExternalInterface interface;
+ try {
+ ModuleInstance instance(wasm, &interface);
+ LiteralList arguments;
+ // init hang support, if present
+ if (wasm.getFunctionOrNull("hangLimitInitializer")) {
+ instance.callFunction("hangLimitInitializer", arguments);
+ }
+ // call the method
+ for (WasmType param : func->params) {
+ // zeros in arguments TODO: more?
+ arguments.push_back(Literal(param));
+ }
+ return instance.callFunction(func->name, arguments);
+ } catch (const TrapException&) {
+ // may throw in instance creation (init of offsets) or call itself
+ return Literal();
+ }
+ }
+};
+
+} // namespace wasm
+