summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-12-09 14:46:24 -0800
committerGitHub <noreply@github.com>2024-12-09 14:46:24 -0800
commit7f62a423ee4bd908f485d01945b71786176b926a (patch)
treeaae42c49412b0153c34ef5a26fea888bb404bdd7
parent729ea41d145d369b203dca6f70b251ea365cb3d0 (diff)
downloadbinaryen-7f62a423ee4bd908f485d01945b71786176b926a.tar.gz
binaryen-7f62a423ee4bd908f485d01945b71786176b926a.tar.bz2
binaryen-7f62a423ee4bd908f485d01945b71786176b926a.zip
Fuzzer: Add call-ref, call-ref-catch imports (#7137)
Similar to call-export*, these imports call a wasm function from outside the module. The difference is that we send a function reference for them to call (rather than an export index). This gives more coverage, first by sending a ref from wasm to JS, and also since we will now try to call anything that is sent. Exports, in comparison, are filtered by the fuzzer to things that JS can handle, so this may lead to more traps, but maybe also some new situations. This also leads to adding more logic to execution-results.h to model JS trapping properly. fuzz_shell.js is refactored to allow sharing code between call-export* and call-ref*.
-rw-r--r--scripts/fuzz_shell.js89
-rw-r--r--src/tools/execution-results.h55
-rw-r--r--src/tools/fuzzing.h6
-rw-r--r--src/tools/fuzzing/fuzzing.cpp122
-rw-r--r--test/lit/exec/fuzzing-api.wast199
-rw-r--r--test/lit/passes/gufa-closed-open.wast6
-rw-r--r--test/passes/fuzz_metrics_noprint.bin.txt52
-rw-r--r--test/passes/fuzz_metrics_passes_noprint.bin.txt53
-rw-r--r--test/passes/translate-to-fuzz_all-features_metrics_noprint.txt87
9 files changed, 493 insertions, 176 deletions
diff --git a/scripts/fuzz_shell.js b/scripts/fuzz_shell.js
index 782040dac..95176bbe6 100644
--- a/scripts/fuzz_shell.js
+++ b/scripts/fuzz_shell.js
@@ -160,6 +160,49 @@ function callFunc(func) {
return func.apply(null, args);
}
+// Calls a given function in a try-catch, swallowing JS exceptions, and return 1
+// if we did in fact swallow an exception. Wasm traps are not swallowed (see
+// details below).
+function tryCall(func) {
+ try {
+ func();
+ return 0;
+ } catch (e) {
+ // We only want to catch exceptions, not wasm traps: traps should still
+ // halt execution. Handling this requires different code in wasm2js, so
+ // check for that first (wasm2js does not define RuntimeError, so use
+ // that for the check - when wasm2js is run, we override the entire
+ // WebAssembly object with a polyfill, so we know exactly what it
+ // contains).
+ var wasm2js = !WebAssembly.RuntimeError;
+ if (!wasm2js) {
+ // When running native wasm, we can detect wasm traps.
+ if (e instanceof WebAssembly.RuntimeError) {
+ throw e;
+ }
+ }
+ var text = e + '';
+ // We must not swallow host limitations here: a host limitation is a
+ // problem that means we must not compare the outcome here to any other
+ // VM.
+ var hostIssues = ['requested new array is too large',
+ 'out of memory',
+ 'Maximum call stack size exceeded'];
+ if (wasm2js) {
+ // When wasm2js does trap, it just throws an "abort" error.
+ hostIssues.push('abort');
+ }
+ for (var hostIssue of hostIssues) {
+ if (text.includes(hostIssue)) {
+ throw e;
+ }
+ }
+ // Otherwise, this is a normal exception we want to catch (a wasm
+ // exception, or a conversion error on the wasm/JS boundary, etc.).
+ return 1;
+ }
+}
+
// Table get/set operations need a BigInt if the table has 64-bit indexes. This
// adds a proper cast as needed.
function toAddressType(table, index) {
@@ -204,43 +247,15 @@ var imports = {
callFunc(exportList[index].value);
},
'call-export-catch': (index) => {
- try {
- callFunc(exportList[index].value);
- return 0;
- } catch (e) {
- // We only want to catch exceptions, not wasm traps: traps should still
- // halt execution. Handling this requires different code in wasm2js, so
- // check for that first (wasm2js does not define RuntimeError, so use
- // that for the check - when wasm2js is run, we override the entire
- // WebAssembly object with a polyfill, so we know exactly what it
- // contains).
- var wasm2js = !WebAssembly.RuntimeError;
- if (!wasm2js) {
- // When running native wasm, we can detect wasm traps.
- if (e instanceof WebAssembly.RuntimeError) {
- throw e;
- }
- }
- var text = e + '';
- // We must not swallow host limitations here: a host limitation is a
- // problem that means we must not compare the outcome here to any other
- // VM.
- var hostIssues = ['requested new array is too large',
- 'out of memory',
- 'Maximum call stack size exceeded'];
- if (wasm2js) {
- // When wasm2js does trap, it just throws an "abort" error.
- hostIssues.push('abort');
- }
- for (var hostIssue of hostIssues) {
- if (text.includes(hostIssue)) {
- throw e;
- }
- }
- // Otherwise, this is a normal exception we want to catch (a wasm
- // exception, or a conversion error on the wasm/JS boundary, etc.).
- return 1;
- }
+ return tryCall(() => callFunc(exportList[index].value));
+ },
+
+ // Funcref operations.
+ 'call-ref': (ref) => {
+ callFunc(ref);
+ },
+ 'call-ref-catch': (ref) => {
+ return tryCall(() => callFunc(ref));
},
},
// Emscripten support.
diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h
index 25d0c0772..bffc4e8f2 100644
--- a/src/tools/execution-results.h
+++ b/src/tools/execution-results.h
@@ -105,13 +105,25 @@ public:
tableStore(exportedTable, index, arguments[1]);
return {};
} else if (import->base == "call-export") {
- callExport(arguments[0].geti32());
+ callExportAsJS(arguments[0].geti32());
// Return nothing. If we wanted to return a value we'd need to have
// multiple such functions, one for each signature.
return {};
} else if (import->base == "call-export-catch") {
try {
- callExport(arguments[0].geti32());
+ callExportAsJS(arguments[0].geti32());
+ return {Literal(int32_t(0))};
+ } catch (const WasmException& e) {
+ return {Literal(int32_t(1))};
+ }
+ } else if (import->base == "call-ref") {
+ callRefAsJS(arguments[0]);
+ // Return nothing. If we wanted to return a value we'd need to have
+ // multiple such functions, one for each signature.
+ return {};
+ } else if (import->base == "call-ref-catch") {
+ try {
+ callRefAsJS(arguments[0]);
return {Literal(int32_t(0))};
} catch (const WasmException& e) {
return {Literal(int32_t(1))};
@@ -145,7 +157,7 @@ public:
throwException(WasmException{Literal(payload)});
}
- Literals callExport(Index index) {
+ Literals callExportAsJS(Index index) {
if (index >= wasm.exports.size()) {
// No export.
throwEmptyException();
@@ -155,20 +167,47 @@ public:
// No callable export.
throwEmptyException();
}
- auto* func = wasm.getFunction(exp->value);
+ return callFunctionAsJS(exp->value);
+ }
+
+ Literals callRefAsJS(Literal ref) {
+ if (!ref.isFunction()) {
+ // Not a callable ref.
+ throwEmptyException();
+ }
+ return callFunctionAsJS(ref.getFunc());
+ }
- // TODO JS traps on some types on the boundary, which we should behave the
- // same on. For now, this is not needed because the fuzzer will prune all
- // non-JS-compatible exports anyhow.
+ // Call a function in a "JS-ey" manner, adding arguments as needed, and
+ // throwing if necessary, the same way JS does.
+ Literals callFunctionAsJS(Name name) {
+ auto* func = wasm.getFunction(name);
- // Send default values as arguments, or trap if we need anything else.
+ // Send default values as arguments, or error if we need anything else.
Literals arguments;
for (const auto& param : func->getParams()) {
+ // An i64 param can work from JS, but fuzz_shell provides 0, which errors
+ // on attempts to convert it to BigInt. v128 cannot work at all.
+ if (param == Type::i64 || param == Type::v128) {
+ throwEmptyException();
+ }
if (!param.isDefaultable()) {
throwEmptyException();
}
arguments.push_back(Literal::makeZero(param));
}
+
+ // Error on illegal results. Note that this happens, as per JS semantics,
+ // *before* the call.
+ for (const auto& result : func->getResults()) {
+ // An i64 result is fine: a BigInt will be provided. But v128 still
+ // errors.
+ if (result == Type::v128) {
+ throwEmptyException();
+ }
+ }
+
+ // Call the function.
return instance->callFunction(func->name, arguments);
}
diff --git a/src/tools/fuzzing.h b/src/tools/fuzzing.h
index a3261ccbe..78219045c 100644
--- a/src/tools/fuzzing.h
+++ b/src/tools/fuzzing.h
@@ -115,6 +115,8 @@ private:
Name tableSetImportName;
Name callExportImportName;
Name callExportCatchImportName;
+ Name callRefImportName;
+ Name callRefCatchImportName;
std::unordered_map<Type, std::vector<Name>> globalsByType;
std::unordered_map<Type, std::vector<Name>> mutableGlobalsByType;
@@ -244,7 +246,9 @@ private:
Expression* makeImportThrowing(Type type);
Expression* makeImportTableGet();
Expression* makeImportTableSet(Type type);
- Expression* makeImportCallExport(Type type);
+ // Call either an export or a ref. We do this from a single function to better
+ // control the frequency of each.
+ Expression* makeImportCallCode(Type type);
Expression* makeMemoryHashLogging();
// Function creation
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index ab200a126..a7f5e0d01 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -771,22 +771,33 @@ void TranslateToFuzzReader::addImportLoggingSupport() {
}
void TranslateToFuzzReader::addImportCallingSupport() {
+ if (wasm.features.hasReferenceTypes() && closedWorld) {
+ // In closed world mode we must *remove* the call-ref* imports, if they
+ // exist in the initial content. These are not valid to call in closed-world
+ // mode as they call function references. (Another solution here would be to
+ // make closed-world issue validation errors on these imports, but that
+ // would require changes to the general-purpose validator.)
+ for (auto& func : wasm.functions) {
+ if (func->imported() && func->module == "fuzzing-support" &&
+ func->base.startsWith("call-ref")) {
+ // Make it non-imported, and with a simple body.
+ func->module = func->base = Name();
+ auto results = func->getResults();
+ func->body =
+ results.isConcrete() ? makeConst(results) : makeNop(Type::none);
+ }
+ }
+ }
+
// Only add these some of the time, as they inhibit some fuzzing (things like
// wasm-ctor-eval and wasm-merge are sensitive to the wasm being able to call
- // its own exports, and to care about the indexes of the exports):
- //
- // 0 - none
- // 1 - call-export
- // 2 - call-export-catch
- // 3 - call-export & call-export-catch
- // 4 - none
- // 5 - none
- //
- auto choice = upTo(6);
- if (choice >= 4) {
+ // its own exports, and to care about the indexes of the exports).
+ if (oneIn(2)) {
return;
}
+ auto choice = upTo(16);
+
if (choice & 1) {
// Given an export index, call it from JS.
callExportImportName = Names::getValidFunctionName(wasm, "call-export");
@@ -811,6 +822,34 @@ void TranslateToFuzzReader::addImportCallingSupport() {
func->type = Signature(Type::i32, Type::i32);
wasm.addFunction(std::move(func));
}
+
+ // If the wasm will be used for closed-world testing, we cannot use the
+ // call-ref variants, as mentioned before.
+ if (wasm.features.hasReferenceTypes() && !closedWorld) {
+ if (choice & 4) {
+ // Given an funcref, call it from JS.
+ callRefImportName = Names::getValidFunctionName(wasm, "call-ref");
+ auto func = std::make_unique<Function>();
+ func->name = callRefImportName;
+ func->module = "fuzzing-support";
+ func->base = "call-ref";
+ func->type = Signature({Type(HeapType::func, Nullable)}, Type::none);
+ wasm.addFunction(std::move(func));
+ }
+
+ if (choice & 8) {
+ // Given an funcref, call it from JS and catch all exceptions (similar
+ // to callExportCatch), return 1 if we caught).
+ callRefCatchImportName =
+ Names::getValidFunctionName(wasm, "call-ref-catch");
+ auto func = std::make_unique<Function>();
+ func->name = callRefCatchImportName;
+ func->module = "fuzzing-support";
+ func->base = "call-ref-catch";
+ func->type = Signature(Type(HeapType::func, Nullable), Type::i32);
+ wasm.addFunction(std::move(func));
+ }
+ }
}
void TranslateToFuzzReader::addImportThrowingSupport() {
@@ -998,27 +1037,48 @@ Expression* TranslateToFuzzReader::makeImportTableSet(Type type) {
Type::none);
}
-Expression* TranslateToFuzzReader::makeImportCallExport(Type type) {
- // The none-returning variant just does the call. The i32-returning one
- // catches any errors and returns 1 when it saw an error. Based on the
- // variant, pick which to call, and the maximum index to call.
- Name target;
+Expression* TranslateToFuzzReader::makeImportCallCode(Type type) {
+ // Call code: either an export or a ref. Each has a catching and non-catching
+ // variant. The catching variants return i32, the others none.
+ assert(type == Type::none || type == Type::i32);
+ auto catching = type == Type::i32;
+ auto exportTarget =
+ catching ? callExportCatchImportName : callExportImportName;
+ auto refTarget = catching ? callRefCatchImportName : callRefImportName;
+
+ // We want to call a ref less often, as refs are more likely to error (a
+ // function reference can have arbitrary params and results, including things
+ // that error on the JS boundary; an export is already filtered for such
+ // things in some cases - when we legalize the boundary - and even if not, we
+ // emit lots of void(void) functions - all the invoke_foo functions - that are
+ // safe to call).
+ if (refTarget) {
+ // This matters a lot more in the variants that do *not* catch (in the
+ // catching ones, we just get a result of 1, but when not caught it halts
+ // execution).
+ if ((catching && (!exportTarget || oneIn(2))) || (!catching && oneIn(4))) {
+ // Most of the time make a non-nullable funcref, to avoid errors.
+ auto refType = Type(HeapType::func, oneIn(10) ? Nullable : NonNullable);
+ return builder.makeCall(refTarget, {make(refType)}, type);
+ }
+ }
+
+ if (!exportTarget) {
+ // We decided not to emit a call-ref here, due to fear of erroring, and
+ // there is no call-export, so just emit something trivial.
+ return makeTrivial(type);
+ }
+
+ // Pick the maximum export index to call.
Index maxIndex = wasm.exports.size();
- if (type == Type::none) {
- target = callExportImportName;
- } else if (type == Type::i32) {
- target = callExportCatchImportName;
- // This never traps, so we can be less careful, but we do still want to
- // avoid trapping a lot as executing code is more interesting. (Note that
+ if (type == Type::i32) {
+ // This swallows errors, so we can be less careful, but we do still want to
+ // avoid swallowing a lot as executing code is more interesting. (Note that
// even though we double here, the risk is not that great: we are still
// adding functions as we go, so the first half of functions/exports can
// double here and still end up in bounds by the time we've added them all.)
maxIndex = (maxIndex + 1) * 2;
- } else {
- WASM_UNREACHABLE("bad import.call");
}
- // We must have set up the target function.
- assert(target);
// Most of the time, call a valid export index in the range we picked, but
// sometimes allow anything at all.
@@ -1027,7 +1087,7 @@ Expression* TranslateToFuzzReader::makeImportCallExport(Type type) {
index = builder.makeBinary(
RemUInt32, index, builder.makeConst(int32_t(maxIndex)));
}
- return builder.makeCall(target, {index}, type);
+ return builder.makeCall(exportTarget, {index}, type);
}
Expression* TranslateToFuzzReader::makeMemoryHashLogging() {
@@ -1705,8 +1765,8 @@ Expression* TranslateToFuzzReader::_makeConcrete(Type type) {
options.add(FeatureSet::Atomics, &Self::makeAtomic);
}
if (type == Type::i32) {
- if (callExportCatchImportName) {
- options.add(FeatureSet::MVP, &Self::makeImportCallExport);
+ if (callExportCatchImportName || callRefCatchImportName) {
+ options.add(FeatureSet::MVP, &Self::makeImportCallCode);
}
options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull);
options.add(FeatureSet::ReferenceTypes | FeatureSet::GC,
@@ -1787,8 +1847,8 @@ Expression* TranslateToFuzzReader::_makenone() {
if (tableSetImportName) {
options.add(FeatureSet::ReferenceTypes, &Self::makeImportTableSet);
}
- if (callExportImportName) {
- options.add(FeatureSet::MVP, &Self::makeImportCallExport);
+ if (callExportImportName || callRefImportName) {
+ options.add(FeatureSet::MVP, &Self::makeImportCallCode);
}
return (this->*pick(options))(Type::none);
}
diff --git a/test/lit/exec/fuzzing-api.wast b/test/lit/exec/fuzzing-api.wast
index 38a8ce41b..eae95fc0a 100644
--- a/test/lit/exec/fuzzing-api.wast
+++ b/test/lit/exec/fuzzing-api.wast
@@ -16,6 +16,9 @@
(import "fuzzing-support" "call-export" (func $call.export (param i32)))
(import "fuzzing-support" "call-export-catch" (func $call.export.catch (param i32) (result i32)))
+ (import "fuzzing-support" "call-ref" (func $call.ref (param funcref)))
+ (import "fuzzing-support" "call-ref-catch" (func $call.ref.catch (param funcref) (result i32)))
+
(table $table 10 20 funcref)
;; Note that the exported table appears first here, but in the binary and in
@@ -102,7 +105,6 @@
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
;; CHECK-NEXT: [LoggingExternalInterface logging 0]
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
- ;; CHECK-NEXT: warning: no passes specified, not doing any work
(func $export.calling.catching (export "export.calling.catching")
;; At index 0 in the exports we have $logging, so we will do those loggings,
;; then log a 0 as no exception happens.
@@ -118,6 +120,162 @@
)
)
)
+
+ ;; CHECK: [fuzz-exec] calling ref.calling
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
+ ;; CHECK-NEXT: [exception thrown: __private ()]
+ (func $ref.calling (export "ref.calling")
+ ;; This will emit some logging.
+ (call $call.ref
+ (ref.func $logging)
+ )
+ ;; This will throw.
+ (call $call.ref
+ (ref.null func)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.catching
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 42]
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+ (func $ref.calling.catching (export "ref.calling.catching")
+ ;; This will emit some logging, then log 0 as we do not error.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.func $logging)
+ )
+ )
+ ;; The exception here is caught, and we'll log 1.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.null func)
+ )
+ )
+ )
+
+ (func $legal (param $x i32) (result i32)
+ ;; Helper for the function below. All types here are legal for JS.
+ (call $log-i32
+ (i32.const 12)
+ )
+ ;; Also log the param to show it is 0, which is what $call.ref does for all
+ ;; params.
+ (call $log-i32
+ (local.get $x)
+ )
+ (i32.const 34)
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.legal
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 12]
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
+ (func $ref.calling.legal (export "ref.calling.legal")
+ ;; It is fine to call-ref a function with params and results. The params get
+ ;; default values, and the results are ignored. All we will see here is the
+ ;; logging from the function, "12".
+ (call $call.ref
+ (ref.func $legal)
+ )
+ )
+
+ (func $illegal (param $x i64)
+ ;; Helper for the function below. The param, an i64, causes a problem: when we
+ ;; call from JS we provide 0, but 0 throws when it tries to convert to BigInt.
+ (call $log-i32
+ (i32.const 56)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.illegal
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+ (func $ref.calling.illegal (export "ref.calling.illegal")
+ ;; The i64 param causes an error here, so we will only log 1 because we catch an exception.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.func $illegal)
+ )
+ )
+ )
+
+ (func $illegal-v128 (param $x v128)
+ ;; Helper for the function below.
+ (call $log-i32
+ (i32.const 56)
+ )
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+ (func $ref.calling.illegal-v128 (export "ref.calling.illegal-v128")
+ ;; As above, we throw on the v128 param, and log 1.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.func $illegal-v128)
+ )
+ )
+ )
+
+ (func $illegal-result (result v128)
+ ;; Helper for the function below. The result is illegal for JS.
+ (call $log-i32
+ (i32.const 910)
+ )
+ (v128.const i32x4 1 2 3 4)
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.illegal-result
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+ (func $ref.calling.illegal-result (export "ref.calling.illegal-result")
+ ;; The v128 result causes an error here, so we will log 1 as an exception. The JS
+ ;; semantics determine that we do that check *before* the call, so the logging
+ ;; of 910 does not go through.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.func $illegal-result)
+ )
+ )
+ )
+
+ (func $legal-result (result i64)
+ ;; Helper for the function below.
+ (call $log-i32
+ (i32.const 910)
+ )
+ (i64.const 90)
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.legal-result
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 910]
+ ;; CHECK-NEXT: [LoggingExternalInterface logging 0]
+ (func $ref.calling.legal-result (export "ref.calling.legal-result")
+ ;; Unlike v128, i64 is legal in a result. The JS VM just returns a BigInt.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.func $legal-result)
+ )
+ )
+ )
+
+ (func $trap
+ ;; Helper for the function below.
+ (unreachable)
+ )
+
+ ;; CHECK: [fuzz-exec] calling ref.calling.trap
+ ;; CHECK-NEXT: [trap unreachable]
+ ;; CHECK-NEXT: warning: no passes specified, not doing any work
+ (func $ref.calling.trap (export "ref.calling.trap")
+ ;; We try to catch an exception here, but the target function traps, which is
+ ;; not something we can catch. We will trap here, and not log at all.
+ (call $log-i32
+ (call $call.ref.catch
+ (ref.func $trap)
+ )
+ )
+ )
)
;; CHECK: [fuzz-exec] calling logging
;; CHECK-NEXT: [LoggingExternalInterface logging 42]
@@ -144,9 +302,48 @@
;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
;; CHECK-NEXT: [LoggingExternalInterface logging 0]
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+
+;; CHECK: [fuzz-exec] calling ref.calling
+;; CHECK-NEXT: [LoggingExternalInterface logging 42]
+;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
+;; CHECK-NEXT: [exception thrown: __private ()]
+
+;; CHECK: [fuzz-exec] calling ref.calling.catching
+;; CHECK-NEXT: [LoggingExternalInterface logging 42]
+;; CHECK-NEXT: [LoggingExternalInterface logging 3.14159]
+;; CHECK-NEXT: [LoggingExternalInterface logging 0]
+;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+
+;; CHECK: [fuzz-exec] calling ref.calling.legal
+;; CHECK-NEXT: [LoggingExternalInterface logging 12]
+;; CHECK-NEXT: [LoggingExternalInterface logging 0]
+
+;; CHECK: [fuzz-exec] calling ref.calling.illegal
+;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+
+;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128
+;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+
+;; CHECK: [fuzz-exec] calling ref.calling.illegal-result
+;; CHECK-NEXT: [LoggingExternalInterface logging 1]
+
+;; CHECK: [fuzz-exec] calling ref.calling.legal-result
+;; CHECK-NEXT: [LoggingExternalInterface logging 910]
+;; CHECK-NEXT: [LoggingExternalInterface logging 0]
+
+;; CHECK: [fuzz-exec] calling ref.calling.trap
+;; CHECK-NEXT: [trap unreachable]
;; CHECK-NEXT: [fuzz-exec] comparing export.calling
;; CHECK-NEXT: [fuzz-exec] comparing export.calling.catching
;; CHECK-NEXT: [fuzz-exec] comparing logging
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-result
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-v128
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal-result
+;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.trap
;; CHECK-NEXT: [fuzz-exec] comparing table.getting
;; CHECK-NEXT: [fuzz-exec] comparing table.setting
;; CHECK-NEXT: [fuzz-exec] comparing throwing
diff --git a/test/lit/passes/gufa-closed-open.wast b/test/lit/passes/gufa-closed-open.wast
index 47add9df5..689ee194f 100644
--- a/test/lit/passes/gufa-closed-open.wast
+++ b/test/lit/passes/gufa-closed-open.wast
@@ -12,15 +12,15 @@
;; OPEND: (type $2 (func (param i32)))
- ;; OPEND: (import "fuzzing-support" "call-ref-catch" (func $external-caller (type $0) (param funcref)))
+ ;; OPEND: (import "outside" "call-ref-catch" (func $external-caller (type $0) (param funcref)))
;; CLOSE: (type $0 (func (param funcref)))
;; CLOSE: (type $1 (func))
;; CLOSE: (type $2 (func (param i32)))
- ;; CLOSE: (import "fuzzing-support" "call-ref-catch" (func $external-caller (type $0) (param funcref)))
- (import "fuzzing-support" "call-ref-catch" (func $external-caller (param funcref)))
+ ;; CLOSE: (import "outside" "call-ref-catch" (func $external-caller (type $0) (param funcref)))
+ (import "outside" "call-ref-catch" (func $external-caller (param funcref)))
;; OPEND: (elem declare func $func)
diff --git a/test/passes/fuzz_metrics_noprint.bin.txt b/test/passes/fuzz_metrics_noprint.bin.txt
index 0fa206e0a..a2f996bcb 100644
--- a/test/passes/fuzz_metrics_noprint.bin.txt
+++ b/test/passes/fuzz_metrics_noprint.bin.txt
@@ -1,35 +1,35 @@
Metrics
total
- [exports] : 45
- [funcs] : 60
+ [exports] : 49
+ [funcs] : 74
[globals] : 18
- [imports] : 5
+ [imports] : 4
[memories] : 1
[memory-data] : 24
- [table-data] : 15
+ [table-data] : 19
[tables] : 1
[tags] : 0
- [total] : 5475
- [vars] : 222
- Binary : 410
- Block : 870
- Break : 148
- Call : 271
- CallIndirect : 30
- Const : 915
- Drop : 51
- GlobalGet : 458
- GlobalSet : 323
- If : 293
- Load : 96
- LocalGet : 442
- LocalSet : 284
- Loop : 99
- Nop : 76
- RefFunc : 15
- Return : 78
- Select : 47
- Store : 44
+ [total] : 5695
+ [vars] : 227
+ Binary : 430
+ Block : 976
+ Break : 188
+ Call : 272
+ CallIndirect : 20
+ Const : 876
+ Drop : 99
+ GlobalGet : 504
+ GlobalSet : 373
+ If : 299
+ Load : 111
+ LocalGet : 365
+ LocalSet : 299
+ Loop : 108
+ Nop : 58
+ RefFunc : 19
+ Return : 74
+ Select : 40
+ Store : 34
Switch : 2
Unary : 365
- Unreachable : 158
+ Unreachable : 183
diff --git a/test/passes/fuzz_metrics_passes_noprint.bin.txt b/test/passes/fuzz_metrics_passes_noprint.bin.txt
index 9c8c25c12..c3881104d 100644
--- a/test/passes/fuzz_metrics_passes_noprint.bin.txt
+++ b/test/passes/fuzz_metrics_passes_noprint.bin.txt
@@ -1,35 +1,34 @@
Metrics
total
- [exports] : 54
- [funcs] : 84
+ [exports] : 30
+ [funcs] : 47
[globals] : 17
[imports] : 4
[memories] : 1
[memory-data] : 11
- [table-data] : 22
+ [table-data] : 18
[tables] : 1
[tags] : 0
- [total] : 8343
- [vars] : 264
- Binary : 597
- Block : 1335
- Break : 226
- Call : 346
- CallIndirect : 65
- Const : 1375
- Drop : 107
- GlobalGet : 719
- GlobalSet : 522
- If : 458
- Load : 139
- LocalGet : 650
- LocalSet : 441
- Loop : 165
- Nop : 97
- RefFunc : 22
- Return : 120
- Select : 71
- Store : 56
- Switch : 2
- Unary : 574
- Unreachable : 256
+ [total] : 4738
+ [vars] : 133
+ Binary : 338
+ Block : 781
+ Break : 122
+ Call : 249
+ CallIndirect : 27
+ Const : 780
+ Drop : 105
+ GlobalGet : 378
+ GlobalSet : 288
+ If : 216
+ Load : 79
+ LocalGet : 396
+ LocalSet : 252
+ Loop : 89
+ Nop : 43
+ RefFunc : 18
+ Return : 70
+ Select : 37
+ Store : 36
+ Unary : 294
+ Unreachable : 140
diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
index 8df9d033c..e2e9b8053 100644
--- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
+++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
@@ -1,54 +1,57 @@
Metrics
total
- [exports] : 9
- [funcs] : 10
+ [exports] : 6
+ [funcs] : 6
[globals] : 4
[imports] : 8
[memories] : 1
[memory-data] : 112
- [table-data] : 2
+ [table-data] : 1
[tables] : 1
[tags] : 1
- [total] : 682
- [vars] : 37
- ArrayLen : 1
- ArrayNew : 7
- ArrayNewFixed : 5
+ [total] : 592
+ [vars] : 38
+ ArrayGet : 2
+ ArrayLen : 2
+ ArrayNew : 6
+ ArrayNewFixed : 4
ArraySet : 1
- AtomicNotify : 1
- Binary : 79
- Block : 72
- BrOn : 4
- Break : 7
- Call : 19
- Const : 149
- Drop : 15
- GlobalGet : 35
- GlobalSet : 32
- If : 20
- Load : 20
- LocalGet : 55
- LocalSet : 26
- Loop : 7
- MemoryFill : 1
- Nop : 9
- Pop : 1
+ AtomicCmpxchg : 1
+ AtomicFence : 1
+ AtomicRMW : 2
+ Binary : 81
+ Block : 62
+ BrOn : 1
+ Break : 11
+ Call : 13
+ CallIndirect : 2
+ Const : 123
+ Drop : 2
+ GlobalGet : 22
+ GlobalSet : 22
+ If : 17
+ Load : 25
+ LocalGet : 63
+ LocalSet : 35
+ Loop : 6
+ Nop : 8
+ Pop : 3
RefAs : 1
- RefCast : 1
RefEq : 1
- RefFunc : 17
- RefI31 : 2
- RefIsNull : 2
- RefNull : 8
- Return : 5
- SIMDExtract : 3
- Store : 1
- StringConst : 3
+ RefFunc : 6
+ RefNull : 3
+ Return : 4
+ SIMDExtract : 2
+ Select : 2
+ StringConst : 5
+ StringEncode : 1
+ StringEq : 2
StringMeasure : 1
- StringWTF16Get : 1
- StructNew : 23
- Try : 1
- TupleExtract : 3
- TupleMake : 4
- Unary : 23
- Unreachable : 16
+ StringWTF16Get : 2
+ StructNew : 9
+ Try : 3
+ TryTable : 3
+ TupleExtract : 1
+ TupleMake : 2
+ Unary : 18
+ Unreachable : 11