From d2d2ef924c66a3fc43817ab187268aba7fb0c5d6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Feb 2024 16:21:11 -0800 Subject: [PATCH 01/10] work --- scripts/fuzz_shell.js | 1 + src/tools/js-wrapper.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 08864dfc713..4b0f19bc4e4 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -167,6 +167,7 @@ var imports = { 'log-i64': logValue, 'log-f32': logValue, 'log-f64': logValue, + 'log-v128': logValue, }, 'env': { 'setTempRet0': function(x) { tempRet0 = x }, diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h index edee301ca86..7357c179653 100644 --- a/src/tools/js-wrapper.h +++ b/src/tools/js-wrapper.h @@ -80,6 +80,9 @@ inline std::string generateJSWrapper(Module& wasm) { " 'log-f64': function(x) { " "console.log('[LoggingExternalInterface logging ' + literal(x, 'f64') " "+ ']') },\n" + " 'log-v128': function(x) { " + "console.log('[LoggingExternalInterface logging ' + literal(x, 'v128')" + " + ']') },\n" " },\n" " 'env': {\n" " 'setTempRet0': function(x) { tempRet0 = x },\n" From b6ce11f8c2ea8118e61bfdc5b05a663198f670cf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Feb 2024 16:25:08 -0800 Subject: [PATCH 02/10] work --- src/tools/js-wrapper.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h index 7357c179653..5df0f4f6cb5 100644 --- a/src/tools/js-wrapper.h +++ b/src/tools/js-wrapper.h @@ -60,6 +60,10 @@ inline std::string generateJSWrapper(Module& wasm) { " ret += Number(x).toString();\n" " break;\n" " }\n" + " case 'v128': {\n" + " ret += '' + x;\n" + " break;\n" + " }\n" " // For anything else, just print the type.\n" " default: ret += type; break;\n" " }\n" From 77e2d1a303bb4fe23c91be9fa22d67591c415ccb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Feb 2024 17:00:38 -0800 Subject: [PATCH 03/10] ebttr --- src/tools/js-wrapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/js-wrapper.h b/src/tools/js-wrapper.h index 5df0f4f6cb5..975d2809334 100644 --- a/src/tools/js-wrapper.h +++ b/src/tools/js-wrapper.h @@ -107,7 +107,7 @@ inline std::string generateJSWrapper(Module& wasm) { } else { ret += " "; } - ret += std::string("instance.exports.") + exp->name.toString() + "("; + ret += std::string("instance.exports['") + exp->name.toString() + "']("; bool first = true; for (auto param : func->getParams()) { // zeros in arguments TODO more? From a7d2ee8426f7429e27b703b78a3a5f1a2fec4553 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 14 Feb 2024 12:30:45 -0800 Subject: [PATCH 04/10] work --- scripts/fuzz_opt.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index b514c5e7e7c..386acecd12a 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -750,10 +750,7 @@ def run(self, wasm, extra_d8_flags=[]): return run_vm([shared.V8, wasm + '.js'] + shared.V8_OPTS + extra_d8_flags + ['--', wasm]) def can_run(self, wasm): - # INITIAL_CONTENT is disallowed because some initial spec testcases - # have names that require mangling, see - # https://github.com/WebAssembly/binaryen/pull/3216 - return not INITIAL_CONTENTS + return True def can_compare_to_self(self): # With nans, VM differences can confuse us, so only very simple VMs @@ -924,6 +921,11 @@ def compare_before_and_after(self, before, after): compare(before[vm], after[vm], 'CompareVMs between before and after: ' + vm.name) def can_run_on_feature_opts(self, feature_opts): + # XXX for simd and multivalue to be allowed, for v8, we can add a pass + # that removes them from the ABI. Like legalize but it can be + # simpler: remove such exports and replace such imports, e.g. + # the fuzzer can do that maybe, but we do want such coverage sometimes... + # like LEGALIZE_JS... an option? return all_disallowed(['simd', 'multivalue', 'multimemory']) From b211b60043ea661750c03a35101dc078235ad981 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 21 Feb 2024 12:22:02 -0800 Subject: [PATCH 05/10] work --- scripts/fuzz_shell.js | 5 ++++- src/tools/fuzzing/fuzzing.cpp | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js index 73611075104..106c877aa0d 100644 --- a/scripts/fuzz_shell.js +++ b/scripts/fuzz_shell.js @@ -47,7 +47,10 @@ function printed(x, y) { // JS has just one null. Print that out rather than typeof null which is // 'object', below. return 'null'; - } else if (typeof x !== 'number' && typeof x !== 'string') { + } else if (typeof x === 'string') { + // Emit a string in the same format as the binaryen interpreter. + return 'string("' + x + '")'; + } else if (typeof x !== 'number') { // Something that is not a number or string, like a reference. We can't // print a reference because it could look different after opts - imagine // that a function gets renamed internally (that is, the problem is that diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 2b776144dc5..c1625d726a4 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -433,6 +433,15 @@ void TranslateToFuzzReader::setupGlobals() { } void TranslateToFuzzReader::setupTags() { + // As in modifyInitialFunctions(), we can't allow tag imports as it would trap + // when the fuzzing infrastructure doesn't know what to provide. + for (auto& tag : wasm.tags) { + if (tag->imported()) { + tag->module = tag->base = Name(); + } + } + + // Add some random tags. Index num = upTo(3); for (size_t i = 0; i < num; i++) { addTag(); From 5b8bdafc4e3fb7f1d7e9dcde8d21e177cd8b0bfe Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 21 Feb 2024 12:26:11 -0800 Subject: [PATCH 06/10] fix --- scripts/test/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 75dece375f4..15c837b1df7 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -260,6 +260,7 @@ def has_shell_timeout(): '--experimental-wasm-typed-funcref', '--experimental-wasm-memory64', '--experimental-wasm-extended-const', + '--experimental-wasm-stringref', '--wasm-final-types', ] From ce637b2f59b890dc400f74645d82aafe08d1a137 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 21 Feb 2024 12:33:37 -0800 Subject: [PATCH 07/10] fix --- src/tools/execution-results.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index add7cd3a5a3..afe3342eb43 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -115,7 +115,7 @@ 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(); + auto resultType = values->type; 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 From 48195746467fed4b2f9ecbd228ad0fcb8bcbf329 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 21 Feb 2024 12:33:51 -0800 Subject: [PATCH 08/10] fix --- src/tools/execution-results.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index afe3342eb43..ffcaa5997b0 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -115,7 +115,7 @@ 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 = values->type; + auto resultType = values->getType(); 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 From ca1164616d7d75a0c9a24372373df15b7299b9e9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 21 Feb 2024 12:40:14 -0800 Subject: [PATCH 09/10] work --- scripts/fuzz_opt.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/fuzz_opt.py b/scripts/fuzz_opt.py index 5ec2a9d8c87..5a339013d25 100755 --- a/scripts/fuzz_opt.py +++ b/scripts/fuzz_opt.py @@ -311,6 +311,8 @@ def is_git_repo(): 'exception-handling.wast', 'translate-eh-old-to-new.wast', 'rse-eh.wast', + # Non-UTF8 strings trap in V8 + 'string-lowering.wast', ] From c4e7c44bb1b7955f6bfce0efb7b87e6c10426e00 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 22 Feb 2024 10:19:31 -0800 Subject: [PATCH 10/10] fix --- src/tools/execution-results.h | 56 ++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index ffcaa5997b0..40d844f19d0 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 = values->getType(); - 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;