summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-02-22 10:18:48 -0800
committerGitHub <noreply@github.com>2024-02-22 10:18:48 -0800
commit4969f936bd44943b08525aff3db709dfc24ab1d6 (patch)
tree4fdc4d46b88b36fe6e05a22a56efad2fabfce5f4 /src/tools
parentf6bb943490dc87b16481bfc1604a796edf2acea8 (diff)
downloadbinaryen-4969f936bd44943b08525aff3db709dfc24ab1d6.tar.gz
binaryen-4969f936bd44943b08525aff3db709dfc24ab1d6.tar.bz2
binaryen-4969f936bd44943b08525aff3db709dfc24ab1d6.zip
Fuzzer: Match the logging of i31ref between JS and C++ (#6335)
JS engines print i31ref as just a number, so we need a small regex to standardize the representation (similar to what we do for funcrefs on the code above). On the C++ side, make it actually print the i31ref rather than treat it like a generic reference (for whom we only print "object"). To do that we must unwrap an externalized i31 as necessary, and add a case for i31 in the printing logic. Also move that printing logic to its own function, as it was starting to get quite long.
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/execution-results.h56
1 files changed, 35 insertions, 21 deletions
diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h
index add7cd3a5..40d844f19 100644
--- a/src/tools/execution-results.h
+++ b/src/tools/execution-results.h
@@ -115,27 +115,8 @@ struct ExecutionResults {
// ignore the result if we hit an unreachable and returned no value
if (values->size() > 0) {
std::cout << "[fuzz-exec] note result: " << exp->name << " => ";
- auto resultType = func->getResults();
- if (resultType.isRef() && !resultType.isString()) {
- // Don't print reference values, as funcref(N) contains an index
- // for example, which is not guaranteed to remain identical after
- // optimizations. Do not print the type in detail (as even that
- // may change due to closed-world optimizations); just print a
- // simple type like JS does, 'object' or 'function', but also
- // print null for a null (so a null function does not get
- // printed as object, as in JS we have typeof null == 'object').
- if (values->size() == 1 && (*values)[0].isNull()) {
- std::cout << "null\n";
- } else if (resultType.isFunction()) {
- std::cout << "function\n";
- } else {
- std::cout << "object\n";
- }
- } else {
- // Non-references can be printed in full. So can strings, since we
- // always know how to print them and there is just one string
- // type.
- std::cout << *values << '\n';
+ for (auto value : *values) {
+ printValue(value);
}
}
}
@@ -150,6 +131,39 @@ struct ExecutionResults {
}
}
+ void printValue(Literal value) {
+ // Unwrap an externalized value to get the actual value.
+ if (Type::isSubType(value.type, Type(HeapType::ext, Nullable))) {
+ value = value.internalize();
+ }
+
+ // Don't print most reference values, as e.g. funcref(N) contains an index,
+ // which is not guaranteed to remain identical after optimizations. Do not
+ // print the type in detail (as even that may change due to closed-world
+ // optimizations); just print a simple type like JS does, 'object' or
+ // 'function', but also print null for a null (so a null function does not
+ // get printed as object, as in JS we have typeof null == 'object').
+ //
+ // The only references we print in full are strings and i31s, which have
+ // simple and stable internal structures that optimizations will not alter.
+ auto type = value.type;
+ if (type.isRef()) {
+ if (type.isString() || type.getHeapType() == HeapType::i31) {
+ std::cout << value << '\n';
+ } else if (value.isNull()) {
+ std::cout << "null\n";
+ } else if (type.isFunction()) {
+ std::cout << "function\n";
+ } else {
+ std::cout << "object\n";
+ }
+ return;
+ }
+
+ // Non-references can be printed in full.
+ std::cout << value << '\n';
+ }
+
// get current results and check them against previous ones
void check(Module& wasm) {
ExecutionResults optimizedResults;